NSFopen 2.2.1__tar.gz → 2.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nsfopen-2.2.3/NSFopen/_version.py +1 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Force_Spectroscopy/Force_Spectroscopy.py +40 -23
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/process/__init__.py +1 -1
- nsfopen-2.2.3/NSFopen/process/colormaps.py +71 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/process/process.py +220 -187
- nsfopen-2.2.3/NSFopen/read/read.py +647 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3/NSFopen.egg-info}/PKG-INFO +1 -1
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen.egg-info/SOURCES.txt +1 -0
- {NSFopen-2.2.1/NSFopen.egg-info → nsfopen-2.2.3}/PKG-INFO +1 -1
- NSFopen-2.2.1/NSFopen/_version.py +0 -1
- NSFopen-2.2.1/NSFopen/read/read.py +0 -526
- {NSFopen-2.2.1 → nsfopen-2.2.3}/LICENSE +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/__init__.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Calculate_Roughness/Calculate_Roughness.html +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Calculate_Roughness/Calculate_Roughness.ipynb +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Calculate_Roughness/Calculate_Roughness.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Calculate_Roughness/__pycache__/Calculate_Roughness.cpython-310.pyc +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Calculate_Roughness/sapphire.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Force_Spectroscopy/Force_Spectroscopy.html +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Force_Spectroscopy/Force_Spectroscopy.ipynb +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Force_Spectroscopy/spectroscopy.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Lateral_Force/Lateral Force Processing.html +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Lateral_Force/Lateral Force Processing.ipynb +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Lateral_Force/Lateral Force Processing.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Lateral_Force/SBS-PMMA.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plane_Removal/Plane_Removal.html +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plane_Removal/Plane_Removal.ipynb +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plane_Removal/Plane_Removal.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plane_Removal/circles.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plane_Removal/circles_holes.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plane_Removal/grid.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plane_Removal/squares_holes.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plotting_Data/MoS2.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plotting_Data/Plotting Data.html +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plotting_Data/Plotting Data.ipynb +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Plotting_Data/Plotting Data.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Sharpen_Image/Sharpen Image.html +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Sharpen_Image/Sharpen Image.ipynb +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Sharpen_Image/Sharpen Image.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Sharpen_Image/grid.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Sharpen_Image/img.jpg +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/Spring_Constant.html +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/Spring_Constant.ipynb +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/Spring_Constant.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/__pycache__/Spring_Constant.cpython-310.pyc +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/__pycache__/__init__.cpython-310.pyc +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/sader.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/thermal.nid +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/example/Spring_Constant/thermal.png +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/read/__init__.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen/read/read_beta.py +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen.egg-info/dependency_links.txt +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen.egg-info/entry_points.txt +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen.egg-info/not-zip-safe +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen.egg-info/requires.txt +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/NSFopen.egg-info/top_level.txt +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/README.md +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/pyproject.toml +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/setup.cfg +0 -0
- {NSFopen-2.2.1 → nsfopen-2.2.3}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.2.3"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
# coding: utf-8
|
|
3
3
|
|
|
4
|
-
# ## This script demonstrates how to open a Nanosurf Force Spectroscopy map and analyze the data using the DMT contact mechanics model
|
|
4
|
+
# ## This script demonstrates how to open a Nanosurf Force Spectroscopy map and analyze the data using the DMT contact mechanics model
|
|
5
5
|
|
|
6
6
|
# In[1]:
|
|
7
7
|
|
|
@@ -16,23 +16,27 @@ from scipy.optimize import curve_fit
|
|
|
16
16
|
|
|
17
17
|
from glob import glob
|
|
18
18
|
|
|
19
|
-
filename =
|
|
20
|
-
filename_large =
|
|
19
|
+
filename = "spectroscopy.nid"
|
|
20
|
+
filename_large = "spectroscopy_large.nid"
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
# In[2]:
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
# If USE_LARGE_MAP is True, then it will use the larger force-curve map, downloading if not already locally available
|
|
26
|
+
# If USE_LARGE_MAP is True, then it will use the larger force-curve map, downloading if not already locally available
|
|
27
27
|
USE_LARGE_MAP = False
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
# In[3]:
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
if USE_LARGE_MAP and filename_large not in glob(
|
|
33
|
+
if USE_LARGE_MAP and filename_large not in glob("*nid"):
|
|
34
34
|
import urllib.request
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
urllib.request.urlretrieve(
|
|
37
|
+
"https://www.dropbox.com/s/knzuh588g0uvjfi/spectroscopy_large.nid?dl=1",
|
|
38
|
+
filename_large,
|
|
39
|
+
)
|
|
36
40
|
filename = filename_large
|
|
37
41
|
elif USE_LARGE_MAP:
|
|
38
42
|
filename = filename_large
|
|
@@ -47,20 +51,28 @@ data = afm.data
|
|
|
47
51
|
param = afm.param
|
|
48
52
|
|
|
49
53
|
# probe
|
|
50
|
-
k = param.Tip.Prop0[
|
|
51
|
-
sens = param.Tip.Sensitivity[
|
|
54
|
+
k = param.Tip.Prop0["Value"] # spring constant
|
|
55
|
+
sens = param.Tip.Sensitivity["Value"] # deflection sensitivity (if needed)
|
|
52
56
|
|
|
53
57
|
radius = 10e-9 # tip radius
|
|
54
58
|
nu = 0.35 # Poisson ratio (between 0.35 and 0.5)
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
direction = "Backward" # Forward or Backward modulation
|
|
61
|
+
|
|
62
|
+
spec_backward = data["Spec"][
|
|
63
|
+
direction
|
|
64
|
+
] # for DMT model we will use backward modulation
|
|
65
|
+
d = spec_backward["Deflection"] # force channel
|
|
58
66
|
|
|
59
67
|
z_signal = list(spec_backward.index)
|
|
60
|
-
z_chans = [
|
|
68
|
+
z_chans = [
|
|
69
|
+
"Z-Axis Sensor",
|
|
70
|
+
"Z-AxisSensor",
|
|
71
|
+
"Z-Axis",
|
|
72
|
+
] # depending on system, Z-Axis channel may be labeled differently
|
|
61
73
|
available_chan = [i for i in z_signal if i in z_chans][0]
|
|
62
74
|
|
|
63
|
-
z = data[
|
|
75
|
+
z = data["Spec"][direction][available_chan] # Z-axis data
|
|
64
76
|
|
|
65
77
|
sz = int(param.Spec.maps[4]) # Map size
|
|
66
78
|
|
|
@@ -72,6 +84,7 @@ extent = param.Spec.maps[:4] # X and Y physical dimensions of map
|
|
|
72
84
|
|
|
73
85
|
## Functions
|
|
74
86
|
|
|
87
|
+
|
|
75
88
|
# corrects for any baseline tilt
|
|
76
89
|
def baseline_correct(x, y, degree=1, start=0, end=0.5):
|
|
77
90
|
i0 = int(np.floor(len(x) * start))
|
|
@@ -90,14 +103,15 @@ def baseline_correct(x, y, degree=1, start=0, end=0.5):
|
|
|
90
103
|
def DMT(x, *param):
|
|
91
104
|
elast, depth, wadh = param
|
|
92
105
|
|
|
93
|
-
scale = 4
|
|
106
|
+
scale = 4.0 / 3.0 * elast * np.sqrt(radius) / (1 - nu**2)
|
|
94
107
|
x = x - depth
|
|
95
|
-
y = scale * np.sign(x) * np.abs(x)**(3
|
|
108
|
+
y = scale * np.sign(x) * np.abs(x) ** (3.0 / 2.0) - wadh
|
|
96
109
|
return y
|
|
97
110
|
|
|
98
111
|
|
|
99
112
|
def DMTfit(*args, maxForce=np.Inf):
|
|
100
113
|
import time
|
|
114
|
+
|
|
101
115
|
t = time.time()
|
|
102
116
|
# args are: [separation, load (force)]
|
|
103
117
|
if not isinstance(args[0], list):
|
|
@@ -108,7 +122,7 @@ def DMTfit(*args, maxForce=np.Inf):
|
|
|
108
122
|
# x = x - y / spring_constant # separation
|
|
109
123
|
lenY = int(np.floor(len(y) * 0.8))
|
|
110
124
|
a = min(y[lenY:]) # adhesion
|
|
111
|
-
|
|
125
|
+
|
|
112
126
|
i0 = np.where(y == a)[0][0] # contact point estimator index
|
|
113
127
|
i1 = np.where(y > maxForce)[0] # max force index
|
|
114
128
|
|
|
@@ -118,13 +132,15 @@ def DMTfit(*args, maxForce=np.Inf):
|
|
|
118
132
|
i1 = i1[0]
|
|
119
133
|
|
|
120
134
|
try:
|
|
121
|
-
coeff, var_matrix = curve_fit(
|
|
135
|
+
coeff, var_matrix = curve_fit(
|
|
136
|
+
DMT, x[i0:i1], y[i0:i1], p0=[1e9, x[i0], -a]
|
|
137
|
+
)
|
|
122
138
|
except RuntimeError:
|
|
123
139
|
E.append(np.nan)
|
|
124
140
|
else:
|
|
125
141
|
E.append(max(coeff[0], 0))
|
|
126
142
|
|
|
127
|
-
print(
|
|
143
|
+
print("Elapsed Time: %3.2f sec\n" % (time.time() - t))
|
|
128
144
|
return np.array(E), (coeff, i0, i1)
|
|
129
145
|
|
|
130
146
|
|
|
@@ -135,7 +151,7 @@ def DMTfit(*args, maxForce=np.Inf):
|
|
|
135
151
|
dd = [baseline_correct(z_, d_, start=0.5, end=0.8) for z_, d_ in zip(z, d)]
|
|
136
152
|
|
|
137
153
|
# separation
|
|
138
|
-
zz = [zz - dd/k for dd, zz in zip(dd, z)]
|
|
154
|
+
zz = [zz - dd / k for dd, zz in zip(dd, z)]
|
|
139
155
|
|
|
140
156
|
# elastic modulus
|
|
141
157
|
Eb, _ = DMTfit(zz, dd)
|
|
@@ -159,14 +175,16 @@ Adh = toMap(adh, sz)
|
|
|
159
175
|
# In[7]:
|
|
160
176
|
|
|
161
177
|
|
|
162
|
-
fig, ax = plt.subplots(
|
|
178
|
+
fig, ax = plt.subplots(
|
|
179
|
+
2, 2, figsize=(10, 8), gridspec_kw={"height_ratios": [2, 1]}, dpi=300
|
|
180
|
+
)
|
|
163
181
|
fig.tight_layout(w_pad=8.0, h_pad=1.0)
|
|
164
182
|
|
|
165
183
|
im = ax.copy()
|
|
166
184
|
|
|
167
185
|
cmap = "afmhot" # colormap
|
|
168
|
-
xlbl =
|
|
169
|
-
ylbl =
|
|
186
|
+
xlbl = "X [$\mu$m]"
|
|
187
|
+
ylbl = "Y [$\mu$m]"
|
|
170
188
|
zlbl = ["Young's Modulus [GPa]", "Adhesion [nN]"]
|
|
171
189
|
|
|
172
190
|
im[0, 0] = ax[0, 0].imshow(Ebim)
|
|
@@ -182,8 +200,7 @@ for i in range(2):
|
|
|
182
200
|
cb.set_label(zlbl[i])
|
|
183
201
|
|
|
184
202
|
ax[0, i].set(xlabel=xlbl, ylabel=ylbl)
|
|
185
|
-
ax[1, i].set(xlabel=zlbl[i], ylabel=
|
|
203
|
+
ax[1, i].set(xlabel=zlbl[i], ylabel="Counts")
|
|
186
204
|
|
|
187
205
|
|
|
188
206
|
plt.show()
|
|
189
|
-
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Thu May 23 13:04:53 2024
|
|
4
|
+
|
|
5
|
+
@author: nelson
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pandas as pd
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from matplotlib.colors import LinearSegmentedColormap
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class colors:
|
|
16
|
+
def __init__(self, name=None, gwy_dir=None, **kwargs):
|
|
17
|
+
self.name = name
|
|
18
|
+
self.gwy_dir = gwy_dir
|
|
19
|
+
if not gwy_dir:
|
|
20
|
+
self.gwy_dir = (
|
|
21
|
+
"C:\\Program Files\\Gwyddion\\share\\gwyddion\\gradients\\"
|
|
22
|
+
)
|
|
23
|
+
custom = ["BlueBlackRed"]
|
|
24
|
+
gwy_list = os.listdir(self.gwy_dir)
|
|
25
|
+
|
|
26
|
+
cmaps = {}
|
|
27
|
+
cmaps["Custom"] = custom
|
|
28
|
+
cmaps["Gwyddion"] = gwy_list
|
|
29
|
+
|
|
30
|
+
if name in gwy_list:
|
|
31
|
+
cmap = self.gwy_cmap()
|
|
32
|
+
elif name in custom:
|
|
33
|
+
cmap = self.custom()
|
|
34
|
+
else:
|
|
35
|
+
print("Name Not Found\n")
|
|
36
|
+
print("Use one of the following choices:\n")
|
|
37
|
+
print({x for v in cmaps.values() for x in v})
|
|
38
|
+
cmap = []
|
|
39
|
+
self.cmap = cmap
|
|
40
|
+
self.cmap_list = cmaps
|
|
41
|
+
|
|
42
|
+
def gwy_cmap(self):
|
|
43
|
+
cmap = pd.read_csv(
|
|
44
|
+
self.gwy_dir + self.name,
|
|
45
|
+
sep=" ",
|
|
46
|
+
header=None,
|
|
47
|
+
skiprows=1,
|
|
48
|
+
index_col=0,
|
|
49
|
+
)
|
|
50
|
+
nodes = cmap.index.values
|
|
51
|
+
colors = cmap.values
|
|
52
|
+
|
|
53
|
+
return LinearSegmentedColormap.from_list(
|
|
54
|
+
self.name, list(zip(nodes, colors))
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def custom(self):
|
|
58
|
+
if self.name == "BlueBlackRed":
|
|
59
|
+
# Blue-Black-Red
|
|
60
|
+
start = np.array(
|
|
61
|
+
[0.6196078431372549, 0.792156862745098, 0.8823529411764706]
|
|
62
|
+
)
|
|
63
|
+
mid = np.array([0, 0, 0])
|
|
64
|
+
end = np.array(
|
|
65
|
+
[0.9882352941176471, 0.5725490196078431, 0.4470588235294118]
|
|
66
|
+
)
|
|
67
|
+
nodes = [0, 0.5, 1]
|
|
68
|
+
|
|
69
|
+
return LinearSegmentedColormap.from_list(
|
|
70
|
+
self.name, list(zip(nodes, [start, mid, end]))
|
|
71
|
+
)
|