pyMFD package#
Subpackages#
pyMFD.FV module#
- class pyMFD.FV.FV(fv_filename, fv_params_func=<function get_params>, fv_data_func=<function get_fv_data>, sc_params_filename=None, sc_params_func=<function get_scan_params>, fv_params_kwargs={}, fv_data_kwargs={}, sc_params_kwargs={})#
Bases:
object
This class represents a single force-volume scan. It contains the relevant scan parameters and force-volume data.
- Attributes
- fv_filenamestr
String pointing to the force-volume scan file.
- sc_params_filenamestr
String pointing to the force-volume scan parameters file.
- fv_paramsdict
Parameters extracted from the force-volume scan file header.
- sc_paramsdict
Scan parameters extracted from scan parameters JSON file.
- z_piezondarray
Displacement of AFM piezo. Has size ramp_len (from parameters samples_per_ramp).
- tm_deflndarray
Tapping mode deflection. Has shape (ramp_len, 2, num_curves). The 2 comes from having both an extension and retraction and num_curves is the number of force-ramps in a scan, e.g. 4096.
- pixel_sizefloat
Size of single pixel in force-volume map, in meters.
- _fv_params_funcfunction
Function that returns the fv_params dictionary.
- _fv_data_funcfunction
Function that returns the force-volume data.
- _sc_params_funcfunction
Function that returns the sv_params dictionary.
Methods
get_extend():
Get extenstion ramp data
get_retract():
Get retraction ramp data
get_pixel_size([scan_size, scan_points]):
Get pixel size
summarize([which_dir, summary_func]):
Summarize the ramp data (i.e. extract compliance)
- get_extend()#
Return the force-volume data recorded during the extension of the AFM cantilever.
- Returns
- ndarray
The extension curves of the tapping mode deflection data. Shape is (ramp_length, 1, num_curves), e.g. (1024, 1, 4096)
- get_pixel_size(scan_size=None, scan_points=None)#
Calculate the size of a single pixel in the force-volume data. Should be in units of meters.
- Parameters
- scan_sizefloat, optional
The total size of the force-volume scan (in meters).
- scan_pointsint, optional
The number of force-deflection ramps in each line of the scan.
- Returns
- float
Size of pixel (in meters).
- get_retract()#
Return the force-volume data recorded during the retraction of the AFM cantilever.
- Returns
- ndarray
The retraction curves of the tapping mode deflection data. Shape is (ramp_length, 1, num_curves), e.g. (1024, 1, 4096)
- summarize(which_dir='retrace', summary_func=<function get_comp_mat>, **kwargs)#
Create a 2D representation of the force-volume data.
- Parameters
- which_dirstr {‘trace’, ‘extend’, ‘retrace’, ‘retract’}, int {0 for trace, 1 for retrace}
Select whether the trace/extension curves or the retrace/retraction curves should be summarized.
- summary_funcfunction
Function that will perform the summary. By default, this is a function that takes z_piezo, tm_defl, and sc_params and returns the compliance matrix and R^2 matrix (how well each curve was summarized).
- **kwargsdict
Arguments that are passed to summary_func.
- Returns
- Default return values if summary_func`=`get_comp_mat.
- ndarray
Compliance matrix. Shape should be square, with the size of the sides being the square root of the number of force ramps. E.g. shape is (64, 64).
- ndarray
R^2 matrix. See comp for shape.
See also
pyMFD.cantilever module#
- pyMFD.cantilever.calc_modulus(fv, cant_num, rows_to_avg=1)#
Calculate the modulus from cantilever compliance using both the cubic model and linear model.
- Parameters
- fvFV
Object of class FV, which represents a single force-volume scan.
- cant_numint
Scans can contain more than one cantilever. This is an index (starting at 0) to select which cantilever to use.
- rows_to_avgint, optional
Total number of rows to average. Will always be symmetric, rounded up. Passing in 2 or 3 is equivalent.
- Returns
- E, offsetfloat
Modulus and offset from the cubic method
- E_lin, offset_linfloat
Modulus and offset using the linear method
- pyMFD.cantilever.calc_modulus_offset(slope, intercept, width, thickness)#
Calculate the modulus and fixed end offset.
- Parameters
- slopefloat
Slope returned from fit_compliance_linear()
- interceptfloat
Intercept returned from fit_compliance_linear()
- widthfloat
Width of cantilever
- thickfloat
Thickness of cantilever
- Returns
- E, cfloat
Young’s modulus and position offset (c).
- pyMFD.cantilever.fit_compliance(positions, compliances, width, thickness, func=<function fit_fun>)#
Standardized and then fit the non-linearized (i.e. original) compliance data.
- Parameters
- positionndarray
Vector of positions (in meters).
- compliancendarray
Vector of linearized compliance.
- widthfloat
Width of cantilever
- thickfloat
Thickness of cantilever
- funcfunction
- Returns
- Efloat
Young’s modulus
- pos_offfloat
Offset in initial guess of fixed end
- afloat
This is the a parameter in fit_fun().
- pyMFD.cantilever.fit_compliance_linear(position, compliance)#
Fit the linearized position vs compliance graph.
1/k = (4/(E*w*t^3))*(L-c)^3 1/k^(1/3) = (4/(E*w*t^3))^(1/3)*(L-c) 1/k^(1/3) = a*(L-c) 1/k^(1/3) = a*L-a*c y = m*x+b
The slope is proportional to E. To get the fixed end offset, divide the intercept by the slope (and take negative).
- Parameters
- positionndarray
Vector of positions (in meters).
- compliancendarray
Vector of linearized compliance.
- Returns
- res.slopefloat
Slope of the compliance data.
- res.interceptfloat
Y-intercept of the compliance data.
- pyMFD.cantilever.fit_fun(L, a, c)#
Function to fit with scipy.optimize.curve_fit.
compliance = 1/k = 1/a*(L - c)**3
- Parameters
- Lfloat
Position along cantilever
- afloat
Combination of width, thickness, and modulus.
- cfloat
Offset from L.
- Returns
- float
Compliance (inverse of stiffness)
- pyMFD.cantilever.get_cantilever_params(params, cant_num)#
Get the important parameters from the parameter dictionary (loaded from JSON) for a specific cantilever.
- Parameters
- paramsdict
Dictionary of parameters. Load from JSON using get_scan_params(). Pass in only parameter for single sample.
- cant_numint
Cantilever number for which to get params.
- Returns
- thick, widthfloat
Thickness and width of the cantilever.
- ignoint
Number of pixels to ignore from fixed end.
- fixedint
Pixel number of fixed end.
- start, endint
Start and end coordinates describing cantilever.
- col_s, col_eint
Column start and column end (i.e. the x-coordinate).
- pyMFD.cantilever.get_cantilever_pos(pixel_size, size)#
Returns the pixel locations in meters across a row.
- Parameters
- pixel_sizefloat
Size of pixel in meters.
- sizeint
Size of scan (number of pixels in scan).
- Returns
- ndarray
List of cantilever positions (in meters).
- pyMFD.cantilever.get_compliance_row(comp_mat, row, rows_to_avg=1)#
Return a full row of the compliance map. If rows_to_avg is greater than 1, then rows above and below row will be averaged.
- Parameters
- comp_matndarray
Compliance matrix
- rowint
Row of scan to extract
- rows_to_avgint, optional
Total number of rows to average. Will always be symmetric, rounded up. Passing in 2 or 3 is equivalent.
- Returns
- comp_rowndarray
Returns the compliance data (possibly averaged).
- pyMFD.cantilever.offset_to_col_coord(offset, col_s, pixel_size)#
TODO: Think of a better name for this function. TODO: Remove if unused
Takes the offset calculated from fitting the the compliance row and return where that offset is in compliance map space.
- Parameters
- offsetfloat
Offset calculated by fitting. This is how far the estimated fixed end is from the origin selected for position array.
- col_sint
Column (from compliance map). This is the fixed end location.
- pixel_sizefloat
Size of single pixel in meters.
- Returns
- int
Offset location in column coordinates.
pyMFD.nanoscope module#
- pyMFD.nanoscope.convert_fv_data(data: numpy.ndarray, params: dict) tuple #
Convert from ADC counts to volts. Returns the piezo ramp deflection z_piezo and the force-volume TM deflection data in volts in a tuple: (z_piezo, tm_defl).
- Parameters
- datandarray
Raw data from force-volume file (from read_fv_data()).
- paramsdict
Parameters dictionary. From get_params().
- Returns
- z_piezondarray
Displacement of AFM piezo. Has size ramp_len (from parameters samples_per_ramp).
- tm_deflndarray
Tapping mode deflection. Has shape (ramp_len, 2, num_curves). The 2 comes from having both an extension and retraction.
- pyMFD.nanoscope.convert_params(old_params, custom_to_extract=[])#
Convert the parameters from the NanoScope name to a new (universal) name. If this code is adapted to new file formats, a new convert_params function should return these same new parameters.
These are the parameters we need:
CFIL
Data offset
Data length
Bytes/pixel
Samps/line
@4:Ramp size
CSL
Samps/line
@2:TMDeflectionLimit
SL
@Sens. Zsens
- Parameters
- old_paramsdict
Original parameter dictionary loaded with read_fv_header()
- custom_to_extractarray of tuples, optional
This function will also convert any additional parameters provided here. Follow tuple format in function: (Section, Parameter Name, New parameter name, Function to convert from bytestring to desired type)
- Returns
- paramsdict
Params dictionary with new parameter names.
- pyMFD.nanoscope.get_fv_data(filename: str, params: dict) tuple #
Get z_piezo and tm_defl. params should be the converted, generalized parameter dictionary.
- Parameters
- filenamestr
Path to NanoScope scan file.
- paramsdict
Parameters dictionary. From get_params().
- Returns
- z_piezondarray
Displacement of AFM piezo. Has size ramp_len (from parameters samples_per_ramp).
- tm_deflndarray
Tapping mode deflection. Has shape (ramp_len, 2, num_curves). The 2 comes from having both an extension and retraction.
- pyMFD.nanoscope.get_params(filename: str) dict #
Get the parameters from the NanoScope file header.
- Parameters
- filenamestr
Path to NanoScope scan file.
- Returns
- paramsdict
Params dictionary with new parameter names.
- pyMFD.nanoscope.read_fv_data(filename: str, params: dict) numpy.ndarray #
Read the force-volume or force-ramp data from a Nanoscope file. The data is converted from binary representation to a float64 representation of the the SPM data in ADC counts. Convert to volts using convert_fv_data.
A force-volume scan contains three dimensions of data. For every point in a 2D array, two force-ramps are recorded (one for extension towards the sample and one for retraction – also called trace and retrace).
The raw data should have a size equal to the number of points in the 2D array times the number of samples in the force-ramp all times two (for extend and retract).
For example, a 64x64 with 1024 samples per force-ramp will have a data length of:
64^2 * 1024 * 2 = 8388608
This length should be recorded in the header as *Ciao force image listData length (keeping in mind the bytes/pixel).
- Parameters
- filenamestr
Path to NanoScope scan file.
- paramsdict
Parameters dictionary. From get_params().
- Returns
- ndarray
NanoScope scan data, unpacked from raw bytes.
- pyMFD.nanoscope.read_fv_header(filename: str) dict #
Read the header information from a Bruker/Veeco Nanoscope v7.2 file. Returns a dictionary containing all of the lines from the header organized under the sections:
FFL = b’*Force file list’
CFIL = b’*Ciao force image list’
CIL = b’*Ciao image list’
SL = b’*Scanner list’
CSL = b’*Ciao scan list’
Nanoscope header files are a mess. There will be different sections depending on the type of data in the file. For more information see Nanoscope User Guide and this informative forum post:
[Nanoscope 7.3](https://physics-astronomy-manuals.wwu.edu/Nanosocpe%207.3%20User%20Guide.pdf) (broken link as of 2/23/2022)
[Nanoscope 8.10](http://nanoqam.ca/wiki/lib/exe/fetch.php?media=nanoscope_software_8.10_user_guide-d_004-1025-000_.pdf)
[Forum post](http://nanoscaleworld.bruker-axs.com/nanoscaleworld/forums/p/538/1065.aspx)
In the file header some parameters start with ‘@’ instead of simply ‘'. This is an indication to the software that the data that follows is intended for a CIAO parameter object. After the ‘@’, you might see a number followed by a colon before the label. This number is what is called a “group number” and can generally be ignored.
Further, after the label and its colon, you will see a single definition character of ‘V’, ‘C’, or ‘S’.
V means _Value_ – a parameter that contains a double and a unit of measure, and some scaling definitions.
C means _Scale_ – a parameter that is simply a scaled version of another.
S means _Select_ – a parameter that describes some selection that has been made
- Parameters
- filenamestr
Filename of the NanoScope file.
- Returns
- paramsdict
Raw paramaters dictionary. Convert with convert_params()
- pyMFD.nanoscope.save_txt_data(data, filename)#
Save the converted data to an ASCII file using the same format as exports from Nanoscope Analysis 2.0.
- Parameters
- datandarray
Converted data to be saved in ASCII format.
- filenamestr
Filename to which the ASIC data should be saved.
pyMFD.scan_params module#
- pyMFD.scan_params.get_scan_params(sp_filename: str) dict #
Loads the scan parameters from a JSON file.
The following is an example scan parameter file, with annotation. JSON does not support comments, so anything after (and including) ‘#’ should be removed:
{ "name": "02041411.001", # Required "growth": "Polished12072018", "sample": "D1", "afm_spring_constant": 39, # Required [N/m] "afm_tip": "tip19", "thickness": 160E-9, # Required [m] "ignored": false, "cantilevers": [ # Required (at least one cantilever definition) { "name": "D1a2", # Required "width": 2.7E-6, # Required [m] "lin_ignore": 0, "fixed_edge": 24, # Required (guess in pixels at fixed end location relative to left side of scan) "start": [26, 13], # Required (top left corner [x, y] in pixels of cantilever) "end": [38, 22] # Required (bottom right corner [x, y] in pixels of cantilever) }, { "name": "D1a1", "width": 2.7E-6, "lin_ignore": 0, "fixed_edge": 26, "start": [28, 38], "end": [44, 49] } ] }
- Parameters
- sp_filenamestr
Filename string (passed to json.load()) pointing to scan parameter JSON file.
- Returns
- sc_paramsdict
Dictionary containing parameters from scan parameters JSON file.
pyMFD.summarize module#
- pyMFD.summarize.comp_mat_inspector(comp_mat, z_piezo, tm_defl, params, fig_width=10, r2s_mat=None)#
Create the interactive compliance map inspector. This tool shows the compliance map on the left, the selected force-deflection map in the middle, and an R^2 map on the right. Click on any pixel in the compliance map or the R^2 map to update the middle force-deflection map.
- Parameters
- comp_matndarray
Compliance matrix from get_com_mat()
- z_piezondarray
Piezo displacement data. Used for central plot.
- tm_deflndarray
Tapping mode deflection data. Used for central plot.
- paramsdict
Dictionary of parameters. Load from JSON using get_scan_params().
- fig_widthint, optional
Width of matplotlib figure in inches.
- r2s_matndarray, optional
R^2 matrix to plot in third column. If not included, third column is disabled.
- Returns
- axsAxes
Return matplotlibe axes used in figure.
- pyMFD.summarize.get_comp_mat(z_piezo, tm_defl, sc_params, linearize=True, savefile=None, smooth_func=<function smooth_z_tip>, **kwargs)#
Get the compliance map. In other words, convert each force-deflection ramp to a compliance value.
- Parameters
- z_piezondarray
Piezo displacement data as a numpy array.
- tm_deflndarray
Tapping mode deflection data as a numpy array.
- sc_paramsdict
Dictionary containg parameters loaded from JSON file with get_scan_params().
- linearize: boolean, optional, default: True
If true, will take the cube root of the compliance data. This linearizes the data in displacement, since the compliance equation depends on the position along the cantilever to the third power (see Euler cantilever equation).
- savefilestr, optional
If provided, the slopes will be saved to the file savefile.
- smooth_funcfunction, optional
This function will be applied to tm_defl to smooth the force-deflection data.
- Returns
- compndarray
Compliance matrix. Shape should be square, with the size of the sides being the square root of the number of force ramps. E.g. shape is (64, 64).
- r2sndarray
R^2 matrix. See comp for shape.
- pyMFD.summarize.get_start_end(z_piezo, z_tip)#
Get the start and end indices for the linear portion of z_piezo vs z_tip.
- Parameters
- z_piezondarray
Z_piezo data as a numpy array.
- z_tipndarray
Z_tip data as a numpy array.
- Returns
- start, endint
Start and end indices.
- pyMFD.summarize.line_slope(z_piezo, z_tip, index=None)#
Algorithm for getting the slope of a force ramp. Applied to all force ramps in the force volume data (4096 for 64x64 scans). The slope is used to find the compliance at each point in the map.
(The following diagram may not display properly in IDE tooltips.)
\ \ ^ \ | \ __________________ z_tip \ / | \/ v 0123456789... <- z_piezo index
Algorithm needs to find slope of the linear section from 0 to 5. However, the data is rarely this nice. A robust algorithm is needed to handle most cases.
Get an initial (start, end) estimate using get_start_end().
get_start_end() takes the derivative of z_tip and finds the z_piezo location where that derivative is highest. This is the end point.
The start point is just 0.8% of the length of z_piezo (8 for ramps with 1024 samples; 4 for ramps with 512 samples)
The end point is reduced until the first zero crossing (before the maximum) of the derivative of z_tip is found.
This (start, end) value is used to fit to the linear region of the force ramp. If R^2 is greater than 0.9, then this slope is returned. Otherwise, decrease the end value, fit again, and check R^2. This is repeated until any of these conditions are met:
R^2 is greater than 0.9, or
There are less than 15 points between the start and end values, or
The process has looped through 10 times without meeting either of the above criteria.
- Parameters
- z_piezondarray
Z_piezo data as a numpy array.
- z_tipndarray
Z_tip data as a numpy array.
- indexint, optional
If index is supplied, this function will not loop through all force-deflection ramps in the FV data. It will only look at the ramp where the index of z_tip is index. Useful for code that selects only one force-ramp to plot.
- Returns
- slopesndarray
Slopes for each force ramp in scan. Shape is (size,), where size is the total number of force ramps in scan.
- r2sndarray
R^2 array with same shape as slopes.
- s, eint
Start and end indices actually used to bracket region of interest.
- pyMFD.summarize.onclick_mat(event)#
Click event hander. Used to allow for inspection of the compliance map.
- Parameters
- eventmatplotlib.backend_bases.Event
Event fired when mouse clicked on compliance map.
- pyMFD.summarize.plot_z_tip(row, col, z_piezo, z_tip, size, ax1, ax2)#
Plot the z_tip data. Each pixel in the compliance map comes from fitting to z_tip.
- Parameters
- rowint
Row from compliance map. Used along with col to identify specific pixel.
- colint
Column from compliance map. Used along with row to identify s pecific pixel.
- z_piezondarray
Piezo displacement data.
- z_tipndarray
AFM tip displacement data.
- sizeint
Number of columns per compliance map.
- ax1, ax2Axes
Two axes on which to plot. ax1 is used for the z_tip data and ax2 is used of its derivative.
- pyMFD.summarize.smooth_z_tip(z_tip, method='movmean')#
The raw force-deflection data from the AFM scan is frequently noisy. This function performs either a moving average or a butterworth filter. I found that doing two moving averages with a window size of 5 and then 11 works well. The data is first flipped to avoid a “lip” at the beginning of the data.
- Returns
- z_tip_smoothndarray
Filtered data. Same shape as z_tip.