| Bsoft 1.9 Bernard's software package

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
img_afm.cpp
Go to the documentation of this file.
1
9 #include "img_afm.h"
10 #include "timer.h"
11 #include "utilities.h"
12
13 // Declaration of global variables
14 extern int verbose; // Level of output to the screen
15
40 int img_to_surface(Bimage* p, Bimage* psd, int nz, double density, double resolution)
41 {
42 // Density within the surface
43 if ( density < 1e-10 ) density = 1;
44 Vector3<double> sampling(p->sampling());
45 double voxel_density = density*sampling.volume();
46 int local_psd(0);
47 unsigned long i, j, x, y, z, slice_size = p->sizeX()*p->sizeY();
48 double factor = GOLDEN;
49 double min, max, zdis, scale;
50
51 if ( psd == NULL ) {
52 local_psd = 1;
53 psd = p->copy_header();
54 slice_size = psd->sizeX()*psd->sizeY();
55 min = max = resolution*0.5;
56 psd->show_minimum(resolution*0.5);
57 psd->show_maximum(resolution*0.5);
58 scale = 1;
59 psd->data_alloc();
60 for ( i=0; i<slice_size; i++ )
61 psd->set(i, psd->show_minimum());
62 } else {
63 min = psd->minimum();
64 max = psd->maximum();
65 scale = (psd->show_maximum() - psd->show_minimum())/(max - min);
66 slice_size = psd->sizeX()*psd->sizeY();
67 for ( i=0; i<slice_size; i++ )
68 psd->set(i, scale*(*psd)[i] + psd->show_minimum());
69 }
70
71 p->sizeZ(nz);
72 if ( p->show_minimum() == 0 && p->show_maximum() == 0 ) {
73 p->show_minimum(resolution);
74 p->show_maximum((p->sizeZ() - 1)*p->sampling().z() - resolution);
75 }
76 double loz = p->show_minimum()/p->sampling().z();
77 scale = (p->show_maximum()-p->show_minimum())/(p->sampling().z()*(p->maximum()-p->minimum()));
78 if ( p->show_minimum() > p->show_maximum() ) factor *= -1;
79 float* dens = new float[p->sizeX()*p->sizeY()*p->sizeZ()];
80
81 if ( verbose & VERB_PROCESS ) {
82 cout << "Converting a 2D image into a 3D surface density" << endl;
83 cout << "New z dimension: " << p->sizeZ() << endl;
84 cout << "Dimension scale: " << sampling << " A/pixel" << endl;
85 cout << "Density scale: " << scale << " A/(unit density)" << endl;
86 cout << "Z min & max: " << p->show_minimum() << " A " << p->show_maximum() << " A" << endl;
87 cout << "Z thickness: " << p->show_maximum() - p->show_minimum() << " A" << endl;
88 cout << "Resolution: " << resolution << " A" << endl;
89 if ( psd )
90 cout << "Sigma min & max: " << psd->show_minimum() << " " << psd->show_maximum() << " A" << endl;
91 cout << "Density within surface: " << density << " Da/A3" << endl << endl;
92 } else if ( verbose & VERB_LABEL )
93 cout << "Converting a 2D image into a 3D surface density" << endl << endl;
94
95 for ( i=y=0; y<p->sizeY(); y++ ) {
96 for ( x=0; x<p->sizeX(); x++, i++ ) {
97 zdis = loz + scale*((*p)[i]-p->minimum());
98 for ( j=i, z=0; z<p->sizeZ(); z++, j+=slice_size )
99 dens[j] = voxel_density/(1+exp(factor*(z-zdis)/(*psd)[i]));
100 }
101 }
102
103 p->data_assign((unsigned char *) dens);
104
105 if ( local_psd ) delete psd;
106
107 p->statistics();
108
109 return 0;
110 }
111
123 Bimage* img_3D_to_height(Bimage* p, double threshold)
124 {
125 p->change_type(Float);
126
127 unsigned long i, j, x, y, z, n;
128
129 Bimage* ph = new Bimage(Float, p->compound_type(), p->sizeX(), p->sizeY(), 1, p->images());
130
131 if ( verbose & VERB_PROCESS ) {
132 cout << "Converting a 3D image into a 2D height image" << endl;
133 cout << "Threshold: " << threshold << endl << endl;
134 }
135
136 for ( i=n=0; n<p->images(); n++ ) {
137 for ( z=0; z<p->sizeZ(); z++ ) {
138 for ( y=0; y<p->sizeY(); y++ ) {
139 for ( x=0; x<p->sizeX(); x++, i++ ) {
140 j = (n*p->sizeY()+y)*p->sizeX()+x;
141 if ( !(*ph)[j] && (*p)[i] >= threshold ) ph->set(j, z);
142 }
143 }
144 }
145 }
146
147 return ph;
148 }
149
165 Bimage* afm_generate_tip(Vector3<int> size, Vector3<float> sampling, double radius,
166 double resolution)
167 {
168 unsigned long i, x, y;
169 double dx, dy, dis, dis2;
170
171 if ( size.x() < 4*radius/sampling.x() ) size[0] = (int) (4*radius/sampling.x());
172 if ( size.y() < 4*radius/sampling.y() ) size[1] = (int) (4*radius/sampling.y());
173 if ( size.z() < 4*radius/sampling.z() ) size[2] = (int) (4*radius/sampling.z());
174
175 if ( verbose & VERB_PROCESS ) {
176 cout << "Generating a 2D tip image" << endl;
177 cout << "Tip dimensions: " << size << endl;
178 cout << "Tip radius: " << radius << " A" << endl << endl;
179 } else if ( verbose & VERB_LABEL )
180 cout << "Generating a 2D tip image" << endl;
181
182 // Generate a 2D tip height image to be converted to 3D later
183 Bimage* p = new Bimage(Float, TSimple, size[0], size[1], 1, 1);
184 p->sampling(sampling);
185 p->image->origin(p->sizeX()/2, p->sizeY()/2, 0);
186
187 radius /= sampling.x(); // Convert the radius to pixel units
188 double radcut = radius/sqrt(2.0); // Edge between sphere and cone
189 double rad2 = radius*radius;
190 double max = sqrt(1.0*p->sizeX()*p->sizeX() + p->sizeY()*p->sizeY())/2;
191
192 // Generate 45 degree cone with spherical tip with input radius
193 for ( i=y=0; y<p->sizeY(); y++ ) {
194 dy = y - p->image->origin().y();
195 for ( x=0; x<p->sizeX(); x++, i++ ) {
196 dx = x - p->image->origin().x();
197 dis2 = dx*dx + dy*dy;
198 dis = sqrt(dis2);
199 if ( dis < radcut )
200 p->set(i, max - (2*radcut - sqrt(rad2 - dis2)));
201 else
202 p->set(i, max - dis);
203 }
204 }
205
206 p->statistics();
207
208 p->show_maximum((sqrt(2.0) - 1)*radius*p->sampling().z());
209 p->show_minimum(p->maximum()*p->sampling().z());
210
211 img_to_surface(p, NULL, size[2], 1.925, resolution);
212
213 p->image->origin(p->size()/2);
214
215 return p;
216 }
217
218 int afm_simulate_at_xy(Bimage* ptip, Bimage* p, long ii,
219 float* force, double spring, double modulus, double thick)
220 {
221 unsigned long i, ti, di, x, y, z, tx, ty, tz, hiz;
222 long dx, dy, dz, zshift;
223 unsigned long ss = p->sizeX()*p->sizeY(), tss = ptip->sizeX()*ptip->sizeY();
224 double fraction, overlap_volume(1);
225 double scale = p->sampling().volume()/(p->maximum()*ptip->maximum()); // Adjustment for correct units
226
227 // Tip displacement = proportion * volume overlap
228 double proportion = modulus/(spring*thick);
229
230 float* shift = new float[p->sizeZ()];
231
232 y = ii/p->sizeX();
233 x = ii - y*p->sizeX();
234 for ( z=0; z<p->sizeZ(); z++ ) {
235 shift[z] = 0;
236 if ( overlap_volume > 1e-30 ) {
237 overlap_volume = 0;
238 i = z*ss + ii;
239 hiz = ptip->sizeZ();
240 if ( hiz > p->sizeZ() - z ) hiz = p->sizeZ() - z;
241 for ( ti=ty=0; ty<ptip->sizeY(); ty++ ) { // Calculate overlap volume
242 dy = y + ty - (long)ptip->image->origin().y();
243 while ( dy < 0 ) dy += p->sizeY(); // Wrap y
244 while ( dy >= p->sizeY() ) dy -= p->sizeY();
245 for ( tx=0; tx<ptip->sizeX(); tx++, ti++ ) {
246 dx = x + tx - (long)ptip->image->origin().x();
247 while ( dx < 0 ) dx += p->sizeX(); // Wrap x
248 while ( dx >= p->sizeX() ) dx -= p->sizeX();
249 di = dy*p->sizeX()+dx;
250 for ( tz=0; tz<hiz; tz++ ) {
251 dz = z + tz;
252 overlap_volume += (*p)[dz*ss+di]*(*ptip)[tz*tss+ti];
253 }
254 }
255 }
256 }
257 shift[z] = overlap_volume*scale*proportion;
258 // cout << "%ld\t%g\n", z, shift[z]);
259 }
260
261 for ( z=0; z<p->sizeZ(); z++ ) { // Calculate zshift where the forces are equal
262 zshift = 0;
263 while ( zshift*p->sampling().z() < shift[z+zshift] &&
264 zshift+z < p->sizeZ() ) zshift++;
265 if ( zshift > 0 ) zshift--;
266 fraction = (zshift*p->sampling().z() - shift[z+zshift])/
267 (zshift*p->sampling().z() - shift[z+zshift] -
268 (zshift+1)*p->sampling().z() + shift[z+zshift+1]);
269 if ( !isfinite(fraction) )
270 cout << "Problem:\t" << x << tab << y << tab << z << tab <<
271 fraction << tab << zshift*p->sampling().z() << tab <<
272 shift[z+zshift] << tab << shift[z+zshift+1] << endl;
273 i = z*ss + ii;
274 force[i] = spring*(zshift + fraction)*p->sampling().z();
275 }
276 // cout << "%ld\t%ld\t%ld\n", x, y, zshift);
277
278 delete[] shift;
279
280 return 0;
281 }
282
311 Bplot* afm_simulate(Bimage* ptip, Bimage* p, double spring, double modulus, double thick)
312 {
313 unsigned long i, ii, z;
314 unsigned long ss = p->sizeX()*p->sizeY();
315 double avg_force;
316
317 if ( verbose & VERB_PROCESS ) {
318 cout << "Simulating an AFM experiment" << endl;
319 cout << "Spring constant: " << spring << " N/m" << endl;
320 cout << "Bulk modulus: " << modulus << " N/m2" << endl;
321 cout << "Specimen thickness: " << thick << " A" << endl << endl;
322 } else if ( verbose & VERB_LABEL )
323 cout << "Simulating an AFM experiment" << endl << endl;
324
325 // Conversions to Angstrom and pN
326 spring *= 100; // 100 pN/A = N/m
327 modulus *= 1e-8; // 0.01 aN/A2 = N/m2
328
329 float* force = new float[p->sizeX()*p->sizeY()*p->sizeZ()];
330
331 #ifdef HAVE_GCD
332 dispatch_apply(ss, dispatch_get_global_queue(0, 0), ^(size_t i){
333 afm_simulate_at_xy(ptip, p, i, force, spring, modulus, thick);
334 });
335 #else
336 #pragma omp parallel for
337 for ( long i=0; i<ss; i++ )
338 afm_simulate_at_xy(ptip, p, i, force, spring, modulus, thick);
339 #endif
340
341 p->maximum(0);
342 for ( i=0; i<ss*p->sizeZ(); i++ )
343 if ( p->maximum() < force[i] ) p->maximum(force[i]);
344
345 Bstring title("AFM simulation");
346 int ncol(3), nv(p->sizeZ());
347 Bplot* plot = new Bplot(1, nv, ncol);
348 plot->title(title);
349 plot->page(0).title(title);
350 plot->page(0).columns(ncol);
351 for ( i=0; i<ncol; i++ ) plot->page(0).column(i).number(i);
352 plot->page(0).column(0).label("Distance");
353 plot->page(0).column(0).axis(1);
354 plot->page(0).column(1).type(2);
355 plot->page(0).column(1).label("Deflection");
356 plot->page(0).column(1).axis(4);
357 plot->page(0).column(2).type(2);
358 plot->page(0).column(2).label("Force");
359 plot->page(0).column(2).axis(3);
360 // plot->page(0).axis(1).min(0);
361 // plot->page(0).axis(1).max(360);
362 // plot->page(0).axis(1).inc(30);
363
364 for ( z=0; z<nv; z++ ) {
365 for ( i=0, ii=z*ss, avg_force=0; i<ss; i++, ii++ )
366 avg_force += force[ii];
367 avg_force /= ss;
368 (*plot)[z] = z*p->sampling().z();
369 (*plot)[z+nv] = avg_force/spring;
370 (*plot)[z+2*nv] = avg_force;
371 }
372
373 Bstring txt;
374 txt = "Cantilever spring constant: " + Bstring(spring/100, "%lg N/m");
375 plot->page(0).add_text(txt);
376 txt = "Bulk modulus: " + Bstring(modulus*1e8, "%lg N/m2");
377 plot->page(0).add_text(txt);
378 txt = "Sample thickness: " + Bstring(thick, "%lg A");
379 plot->page(0).add_text(txt);
380
381 if ( verbose & VERB_PROCESS ) {
382 cout << "Distance(A)\tDeflection(A)\tForce(pN)" << endl;
383 for ( z=0; z<nv; z++ )
384 cout << setw(12) << (*plot)[z] << tab << setw(12)
385 << (*plot)[z+nv] << tab << (*plot)[z+2*nv] << endl;
386 cout << endl;
387 }
388
389 p->data_assign((unsigned char *) force);
390
391 return plot;
392 }
393
400 Bimage* afm_force_to_height(Bimage* pf, double force_step)
401 {
402 unsigned long i, j, x, y, z, n;
403 unsigned long ss = pf->sizeX()*pf->sizeY();
404 double denom, scale, min, max;
405
406 n = (unsigned long) (pf->maximum()/force_step); // A height image every 10 pN
407 Bimage* ph = pf->copy_header(n);
408 ph->sizeZ(1);
409 ph->data_type(Float);
410 ph->data_alloc();
411
412 if ( verbose & VERB_PROCESS ) {
413 cout << "Converting an AFM force map into " << ph->images() << " height images" << endl;
414 cout << "Force(pN)\tHeight_min(A)\tHeight_range(A)" << endl;
415 } else if ( verbose & VERB_LABEL )
416 cout << "Converting an AFM force map into " << ph->images() << " height images" << endl << endl;
417
418 for ( n=0; n<ph->images(); n++ ) {
419 min = 1e30;
420 max = -1e30;
421 for ( y=0; y<ph->sizeY(); y++ ) {
422 for ( x=0; x<ph->sizeX(); x++ ) {
423 z = 1;
424 while ( z < pf->sizeZ() && (*pf)[(z*pf->sizeY() + y)*pf->sizeX() + x] > force_step*(n+1) )
425 z++;
426 denom = (*pf)[((z-1)*pf->sizeY() + y)*pf->sizeX() + x] -
427 (*pf)[(z*pf->sizeY() + y)*pf->sizeX() + x];
428 i = (n*ph->sizeY() + y)*ph->sizeX() + x;
429 ph->set(i, ph->sampling().z()*z);
430 if ( denom != 0 )
431 ph->set(i, (*ph)[i] - ph->sampling().z()*
432 (force_step*(n+1) - (*pf)[(z*pf->sizeY() + y)*pf->sizeX() + x])/denom);
433 if ( min > (*ph)[i] ) min = (*ph)[i];
434 if ( max < (*ph)[i] ) max = (*ph)[i];
435 }
436 }
437 scale = max - min;
438 if ( verbose & VERB_PROCESS )
439 cout << setw(12) << force_step*(n+1) << tab << setw(12) << min << tab << scale << endl;
440 for ( i=0, j=n*ss; i<ss; i++, j++ )
441 ph->set(j, (*ph)[j] - min);
442 }
443 cout << endl;
444
445 ph->statistics();
446
447 if ( verbose & VERB_DEBUG )
448 cout << "DEBUG afm_force_to_height: Done!" << endl << endl;
449
450 return ph;
451 }
452
453
Bimage::change_type
void change_type(char letter)
Get the data type indicated by a single letter code.
Definition: Bimage.cpp:1544
Vector3::z
Type z()
Definition: Vector3.h:139
Bimage::sizeZ
void sizeZ(size_t nz)
Definition: Bimage.h:332
Bimage::copy_header
Bimage * copy_header()
Definition: Bimage.h:537
afm_simulate
Bplot * afm_simulate(Bimage *ptip, Bimage *p, double spring, double modulus, double thick)
Simulates and AFM experiment.
Definition: img_afm.cpp:311
utilities.h
Header file for general utilities.
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:106
Bimage::compound_type
CompoundType compound_type()
Definition: Bimage.h:307
GOLDEN
#define GOLDEN
Definition: utilities.h:75
Vector3< double >
VERB_PROCESS
#define VERB_PROCESS
Definition: utilities.h:101
Bimage::size
Vector3< size_t > size() const
Definition: Bimage.h:327
Bimage::statistics
size_t statistics()
Calculates the statistics for an image.
Definition: Bimage_stats.cpp:22
TSimple
Definition: Bimage.h:51
timer.h
Utilities for timing functions.
Float
Definition: utilities.h:151
Bimage
General image parameter class.
Definition: Bimage.h:152
Bimage::data_alloc
unsigned char * data_alloc()
Definition: Bimage.h:226
Bimage::maximum
double maximum()
Definition: Bimage.h:463
Bimage::sampling
void sampling(double s)
Definition: Bimage.h:440
Bimage::data_assign
unsigned char * data_assign(unsigned char *nudata)
Assign image data.
Definition: Bimage.cpp:623
afm_generate_tip
Bimage * afm_generate_tip(Vector3< int > size, Vector3< float > sampling, double radius, double resolution)
Generates a rounded conical AFM tip.
Definition: img_afm.cpp:165
Bimage::show_maximum
double show_maximum()
Definition: Bimage.h:479
Vector3::x
Type x()
Definition: Vector3.h:137
Bsub_image::origin
void origin(double x, double y, double z)
Definition: Bimage.h:132
Bimage::set
void set(size_t j, double v)
Sets a single value at the given index.
Definition: Bimage.cpp:977
verbose
int verbose
Bimage::images
size_t images()
Definition: Bimage.h:438
Bstring
Definition: Bstring.h:28
Bimage::sizeX
void sizeX(size_t nx)
Definition: Bimage.h:330
afm_force_to_height
Bimage * afm_force_to_height(Bimage *pf, double force_step)
Converts an AFM force map into a set of 2D height images at different constant force values...
Definition: img_afm.cpp:400
Bimage::sizeY
void sizeY(size_t ny)
Definition: Bimage.h:331
img_3D_to_height
Bimage * img_3D_to_height(Bimage *p, double threshold)
Converts a 3D image to a 2D height image.
Definition: img_afm.cpp:123
img_to_surface
int img_to_surface(Bimage *p, Bimage *psd, int nz, double density, double resolution)
Converts a 2D AFM image to a 3D density map.
Definition: img_afm.cpp:40
afm_simulate_at_xy
int afm_simulate_at_xy(Bimage *ptip, Bimage *p, long ii, float *force, double spring, double modulus, double thick)
Definition: img_afm.cpp:218
Bimage::show_minimum
double show_minimum()
Definition: Bimage.h:478
img_afm.h
Header file for AFM functions.
VERB_LABEL
#define VERB_LABEL
Definition: utilities.h:100
Bimage::data_type
DataType data_type()
Definition: Bimage.h:305
Vector3::volume
double volume()
Definition: Vector3.h:205
Vector3::y
Type y()
Definition: Vector3.h:138
Bimage::minimum
double minimum()
Definition: Bimage.h:462
tab
ostream & tab(ostream &out)
Definition: utilities.cpp:21
Bimage::image
Bsub_image * image
Definition: Bimage.h:183
Bplot
Definition: Bplot.h:146