Skip to content

Commit 6989d73

Browse files
authored
Merge pull request #169 from sandialabs/rescale-potential-stiffness
rescale potential stiffness
2 parents 5b23566 + dff54f6 commit 6989d73

File tree

19 files changed

+528
-790
lines changed

19 files changed

+528
-790
lines changed

docs/source/physics/single_chain/fjc/thermodynamics/modified_canonical/example_asymptotic.ipynb

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,11 @@
2727
},
2828
{
2929
"cell_type": "markdown",
30-
"id": "8abeab96",
31-
"metadata": {},
32-
"source": [
33-
"## Strong potential"
34-
]
35-
},
36-
{
37-
"cell_type": "markdown",
38-
"id": "8c7dadae",
30+
"id": "1592d36b",
3931
"metadata": {},
4032
"source": [
33+
"## Strong potential\n",
34+
"\n",
4135
"For sufficiently strong potentials, the modified canonical ensemble can be accurately approximated using the reference system (the isometric ensemble) and an asymptotic correction. For example, the nondimensional force $\\eta$ as a function of the nondimensional potential distance $\\gamma$ is approximated as\n",
4236
"\n",
4337
"$$\n",
@@ -68,11 +62,10 @@
6862
"source": [
6963
"gamma = np.linspace(1e-3, 99e-2, 256)\n",
7064
"for varpi in [1e0, 1e1, 1e2]:\n",
71-
" w = varpi*fjc.number_of_links**2\n",
72-
" eta = fjc.nondimensional_force(gamma, w)\n",
65+
" eta = fjc.nondimensional_force(gamma, varpi)\n",
7366
" line = plt.plot(gamma, eta, label=r'$\\varpi=$' + str(varpi))\n",
7467
" eta_asymptotic = \\\n",
75-
" fjc.asymptotic.strong_potential.nondimensional_force(gamma, w)\n",
68+
" fjc.asymptotic.strong_potential.nondimensional_force(gamma, varpi)\n",
7669
" plt.plot(gamma, eta_asymptotic, ':', color=line[0].get_color())\n",
7770
"plt.legend()\n",
7871
"plt.xlim([0, 1])\n",
@@ -84,17 +77,11 @@
8477
},
8578
{
8679
"cell_type": "markdown",
87-
"id": "1d21a64d",
88-
"metadata": {},
89-
"source": [
90-
"## Weak potential"
91-
]
92-
},
93-
{
94-
"cell_type": "markdown",
95-
"id": "dce6f3d2",
80+
"id": "8a77ab06",
9681
"metadata": {},
9782
"source": [
83+
"## Weak potential\n",
84+
"\n",
9885
"For sufficiently distant potentials, the modified canonical ensemble can be accurately approximated using the reference system (the isotensional ensemble) and an asymptotic correction. The potential is considered sufficiently distant when the length of center of the potential well to the end of the chain experiencing it is much larger than the expected end-to-end length of the chain. This disparity in length is only typically possible considering weak potentials. For example, if $\\eta/N_b\\varpi$ is the nondimensional potential distance, the nondimensional end-to-end length per link $\\gamma$ as a function of the effective nondimensional potential force $\\eta$ is approximated as\n",
9986
"\n",
10087
"$$\n",
@@ -105,14 +92,9 @@
10592
"\n",
10693
"$$\n",
10794
" \\gamma(\\eta) = \\frac{1}{N_b}\\frac{\\partial}{\\partial\\eta}\\,\\ln\\left[\\iiint Q_0(\\boldsymbol{\\gamma}') \\, e^{N_b\\boldsymbol{\\eta}\\cdot\\boldsymbol{\\gamma}'} e^{-\\tfrac{\\varpi}{2} N_b^2\\left(\\boldsymbol{\\gamma}'\\right)^2} d^3\\boldsymbol{\\gamma}'\\right].\n",
108-
"$$\n"
109-
]
110-
},
111-
{
112-
"cell_type": "markdown",
113-
"id": "8a77ab06",
114-
"metadata": {},
115-
"source": [
95+
"$$\n",
96+
"\n",
97+
"\n",
11698
"This exact relation is plotted below along with the asymptotic relation while varying $\\varpi$, the nondimensional potential stiffness. As $\\varpi$ decreases and/or the nondimensional force $\\eta$ increases (the nondimensional potential distance $\\eta/N_b\\varpi$ increases), the asymptotic approach appears to do increasingly well. Notably, the asymptoic approach appears to succeed for sufficiently distance potentials for any value of $\\varpi$. This is because the freely-jointed chain model has inextensible links, so even a stiff potential that is distant ($\\eta/N_b\\varpi\\gg 1$) will not stretch the chain past $\\gamma=1$. For chain models which have extensible links, the link stiffness will compete with the potential stiffness, such that the potential would need to be weak ($\\varpi\\ll 1$) in addition to distant ($\\eta/N_b\\varpi\\gg 1$) in order for the asymptotic approach to become accurate."
11799
]
118100
},
@@ -125,11 +107,10 @@
125107
"source": [
126108
"gamma_in = np.linspace(5e-1, 5, 256)\n",
127109
"for varpi in [1e0, 1e-1, 1e-2]:\n",
128-
" w = varpi*fjc.number_of_links**2\n",
129-
" gamma = fjc.nondimensional_end_to_end_length_per_link(gamma_in, w)\n",
110+
" gamma = fjc.nondimensional_end_to_end_length_per_link(gamma_in, varpi)\n",
130111
" line = plt.plot(gamma, gamma_in, label=r'$\\varpi=$' + str(varpi))\n",
131112
" gamma_asymptotic = \\\n",
132-
" fjc.asymptotic.weak_potential.nondimensional_end_to_end_length_per_link(gamma_in, w)\n",
113+
" fjc.asymptotic.weak_potential.nondimensional_end_to_end_length_per_link(gamma_in, varpi)\n",
133114
" plt.plot(gamma_asymptotic, gamma_in, ':', color=line[0].get_color())\n",
134115
"plt.legend()\n",
135116
"plt.xlim([0, 1])\n",

src/physics/single_chain/fjc/thermodynamics/modified_canonical/asymptotic/strong_potential/mod.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ pub struct FJC
3030
/// The expected force as a function of the applied potential distance, potential stiffness, and temperature, parameterized by the number of links and link length.
3131
pub fn force(number_of_links: &u8, link_length: &f64, potential_distance: &f64, potential_stiffness: &f64, temperature: &f64) -> f64
3232
{
33-
let contour_length = (*number_of_links as f64)*link_length;
34-
BOLTZMANN_CONSTANT*temperature/link_length*nondimensional_force(number_of_links, &(*potential_distance/contour_length), &(potential_stiffness*contour_length.powi(2)/BOLTZMANN_CONSTANT/temperature))
33+
BOLTZMANN_CONSTANT*temperature/link_length*nondimensional_force(number_of_links, &(*potential_distance/((*number_of_links as f64)*link_length)), &(potential_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature))
3534
}
3635

3736
/// The expected nondimensional force as a function of the applied nondimensional potential distance and nondimensional potential stiffness, parameterized by the number of links.
@@ -46,21 +45,19 @@ pub fn nondimensional_force(number_of_links: &u8, nondimensional_potential_dista
4645
let sum_1: f64 = (0..=k-1).collect::<Vec::<u128>>().iter().map(|s| (-1.0_f64).powf(*s as f64)*(((1..=n).product::<u128>()/(1..=*s).product::<u128>()/(1..=n-s).product::<u128>()) as f64)*(m - (*s as f64)/number_of_links_f64).powi(p - 1)).sum();
4746
let sum_2: f64 = (0..=k-1).collect::<Vec::<u128>>().iter().map(|s| (-1.0_f64).powf(*s as f64)*(((1..=n).product::<u128>()/(1..=*s).product::<u128>()/(1..=n-s).product::<u128>()) as f64)*(m - (*s as f64)/number_of_links_f64).powi(p - 2)).sum();
4847
let sum_3: f64 = (0..=k-1).collect::<Vec::<u128>>().iter().map(|s| (-1.0_f64).powf(*s as f64)*(((1..=n).product::<u128>()/(1..=*s).product::<u128>()/(1..=n-s).product::<u128>()) as f64)*(m - (*s as f64)/number_of_links_f64).powi(p - 3)).sum();
49-
(1.0/nondimensional_potential_distance + (0.5*number_of_links_f64 - 1.0)*sum_1/sum_0)/number_of_links_f64 + 0.5/nondimensional_potential_stiffness/number_of_links_f64*((0.5*number_of_links_f64 - 1.0)*((0.5*number_of_links_f64 - 1.0)*sum_1/sum_0*((number_of_links_f64 - 2.0)*(sum_1/sum_0).powi(2) - (number_of_links_f64 - 3.0)*sum_2/sum_0) - (0.5*number_of_links_f64 - 1.5)*((0.5*number_of_links_f64 - 1.0)*sum_1*sum_2/sum_0.powi(2) - (0.5*number_of_links_f64 - 2.0)*sum_3/sum_0)) + 2.0*nondimensional_potential_distance.powi(-3) - 2.0*((0.5*number_of_links_f64 - 1.0)*sum_1/sum_0 + nondimensional_potential_distance.powi(-1))*((0.5*number_of_links_f64 - 1.0)*((0.5*number_of_links_f64 - 1.0)*(sum_1/sum_0).powi(2) - (0.5*number_of_links_f64 - 1.5)*sum_2/sum_0) - nondimensional_potential_distance.powi(-2)))
48+
(1.0/nondimensional_potential_distance + (0.5*number_of_links_f64 - 1.0)*sum_1/sum_0)/number_of_links_f64 + 0.5/nondimensional_potential_stiffness/number_of_links_f64.powi(3)*((0.5*number_of_links_f64 - 1.0)*((0.5*number_of_links_f64 - 1.0)*sum_1/sum_0*((number_of_links_f64 - 2.0)*(sum_1/sum_0).powi(2) - (number_of_links_f64 - 3.0)*sum_2/sum_0) - (0.5*number_of_links_f64 - 1.5)*((0.5*number_of_links_f64 - 1.0)*sum_1*sum_2/sum_0.powi(2) - (0.5*number_of_links_f64 - 2.0)*sum_3/sum_0)) + 2.0*nondimensional_potential_distance.powi(-3) - 2.0*((0.5*number_of_links_f64 - 1.0)*sum_1/sum_0 + nondimensional_potential_distance.powi(-1))*((0.5*number_of_links_f64 - 1.0)*((0.5*number_of_links_f64 - 1.0)*(sum_1/sum_0).powi(2) - (0.5*number_of_links_f64 - 1.5)*sum_2/sum_0) - nondimensional_potential_distance.powi(-2)))
5049
}
5150

5251
/// The Helmholtz free energy as a function of the applied potential distance, potential stiffness, and temperature, parameterized by the number of links, link length, and hinge mass.
5352
pub fn helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, potential_distance: &f64, potential_stiffness: &f64, temperature: &f64) -> f64
5453
{
55-
let contour_length = (*number_of_links as f64)*link_length;
56-
nondimensional_helmholtz_free_energy(number_of_links, link_length, hinge_mass, &(potential_distance/contour_length), &(potential_stiffness*contour_length.powi(2)/BOLTZMANN_CONSTANT/temperature), temperature)*BOLTZMANN_CONSTANT*temperature
54+
nondimensional_helmholtz_free_energy(number_of_links, link_length, hinge_mass, &(potential_distance/((*number_of_links as f64)*link_length)), &(potential_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), temperature)*BOLTZMANN_CONSTANT*temperature
5755
}
5856

5957
/// The Helmholtz free energy per link as a function of the applied potential distance, potential stiffness, and temperature, parameterized by the number of links, link length, and hinge mass.
6058
pub fn helmholtz_free_energy_per_link(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, potential_distance: &f64, potential_stiffness: &f64, temperature: &f64) -> f64
6159
{
62-
let contour_length = (*number_of_links as f64)*link_length;
63-
nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, &(potential_distance/contour_length), &(potential_stiffness*contour_length.powi(2)/BOLTZMANN_CONSTANT/temperature), temperature)*BOLTZMANN_CONSTANT*temperature
60+
nondimensional_helmholtz_free_energy_per_link(number_of_links, link_length, hinge_mass, &(potential_distance/((*number_of_links as f64)*link_length)), &(potential_stiffness*link_length.powi(2)/BOLTZMANN_CONSTANT/temperature), temperature)*BOLTZMANN_CONSTANT*temperature
6461
}
6562

6663
/// The relative Helmholtz free energy as a function of the applied potential distance, potential stiffness, and temperature, parameterized by the number of links and link length.
@@ -74,10 +71,12 @@ pub fn relative_helmholtz_free_energy_per_link(number_of_links: &u8, link_length
7471
{
7572
helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, potential_distance, potential_stiffness, temperature) - helmholtz_free_energy_per_link(number_of_links, link_length, &1.0, &(ZERO*(*number_of_links as f64)*link_length), potential_stiffness, temperature)
7673
}
74+
7775
/// The nondimensional Helmholtz free energy as a function of the applied nondimensional potential distance, nondimensional potential stiffness, and temperature, parameterized by the number of links, link length, and hinge mass.
7876
pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: &f64, hinge_mass: &f64, nondimensional_potential_distance: &f64, nondimensional_potential_stiffness: &f64, temperature: &f64) -> f64
7977
{
8078
let number_of_links_f64 = *number_of_links as f64;
79+
let number_of_links_squared = number_of_links_f64.powi(2);
8180
let contour_length = number_of_links_f64*link_length;
8281
let n = *number_of_links as u128;
8382
let p: i32 = (number_of_links - 2).into();
@@ -86,7 +85,7 @@ pub fn nondimensional_helmholtz_free_energy(number_of_links: &u8, link_length: &
8685
let sum_0: f64 = (0..=k-1).collect::<Vec::<u128>>().iter().map(|s| (-1.0_f64).powf(*s as f64)*(((1..=n).product::<u128>()/(1..=*s).product::<u128>()/(1..=n-s).product::<u128>()) as f64)*(m - (*s as f64)/number_of_links_f64).powi(p)).sum();
8786
let sum_1: f64 = (0..=k-1).collect::<Vec::<u128>>().iter().map(|s| (-1.0_f64).powf(*s as f64)*(((1..=n).product::<u128>()/(1..=*s).product::<u128>()/(1..=n-s).product::<u128>()) as f64)*(m - (*s as f64)/number_of_links_f64).powi(p - 1)).sum();
8887
let sum_2: f64 = (0..=k-1).collect::<Vec::<u128>>().iter().map(|s| (-1.0_f64).powf(*s as f64)*(((1..=n).product::<u128>()/(1..=*s).product::<u128>()/(1..=n-s).product::<u128>()) as f64)*(m - (*s as f64)/number_of_links_f64).powi(p - 2)).sum();
89-
-(0.125/PI/nondimensional_potential_distance*(n.pow(n as u32) as f64)/((1..=n-2).product::<u128>() as f64)*sum_0/contour_length.powi(3)).ln() - (number_of_links_f64 - 1.0)*(8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln() - 1.5*(2.0*PI/nondimensional_potential_stiffness).ln() - 3.0*(contour_length).ln() + 0.5/nondimensional_potential_stiffness*((0.5*number_of_links_f64 - 1.0)*((0.5*number_of_links_f64 - 1.0)*(sum_1/sum_0).powi(2) - (0.5*number_of_links_f64 - 1.5)*sum_2/sum_0) - nondimensional_potential_distance.powi(-2) - ((0.5*number_of_links_f64 - 1.0)*sum_1/sum_0 + nondimensional_potential_distance.powi(-1)).powi(2))
88+
-(0.125/PI/nondimensional_potential_distance*(n.pow(n as u32) as f64)/((1..=n-2).product::<u128>() as f64)*sum_0/contour_length.powi(3)).ln() - (number_of_links_f64 - 1.0)*(8.0*PI.powi(2)*hinge_mass*link_length.powi(2)*BOLTZMANN_CONSTANT*temperature/PLANCK_CONSTANT.powi(2)).ln() - 1.5*(2.0*PI/nondimensional_potential_stiffness/number_of_links_squared).ln() - 3.0*(contour_length).ln() + 0.5/nondimensional_potential_stiffness/number_of_links_squared*((0.5*number_of_links_f64 - 1.0)*((0.5*number_of_links_f64 - 1.0)*(sum_1/sum_0).powi(2) - (0.5*number_of_links_f64 - 1.5)*sum_2/sum_0) - nondimensional_potential_distance.powi(-2) - ((0.5*number_of_links_f64 - 1.0)*sum_1/sum_0 + nondimensional_potential_distance.powi(-1)).powi(2))
9089
}
9190

9291
/// The nondimensional Helmholtz free energy per link as a function of the applied nondimensional potential distance, nondimensional potential stiffness, and temperature, parameterized by the number of links, link length, and hinge mass.

src/physics/single_chain/fjc/thermodynamics/modified_canonical/asymptotic/strong_potential/test.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ end
9393
potential_distance =
9494
nondimensional_potential_distance * number_of_links * link_length
9595
potential_stiffness =
96-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
96+
nondimensional_potential_stiffness / link_length^2 *
9797
BOLTZMANN_CONSTANT *
9898
temperature
9999
force = model.force(potential_distance, potential_stiffness, temperature)
@@ -128,7 +128,7 @@ end
128128
potential_distance =
129129
nondimensional_potential_distance * number_of_links * link_length
130130
potential_stiffness =
131-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
131+
nondimensional_potential_stiffness / link_length^2 *
132132
BOLTZMANN_CONSTANT *
133133
temperature
134134
helmholtz_free_energy = model.helmholtz_free_energy(
@@ -169,7 +169,7 @@ end
169169
potential_distance =
170170
nondimensional_potential_distance * number_of_links * link_length
171171
potential_stiffness =
172-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
172+
nondimensional_potential_stiffness / link_length^2 *
173173
BOLTZMANN_CONSTANT *
174174
temperature
175175
helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(
@@ -209,7 +209,7 @@ end
209209
potential_distance =
210210
nondimensional_potential_distance * number_of_links * link_length
211211
potential_stiffness =
212-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
212+
nondimensional_potential_stiffness / link_length^2 *
213213
BOLTZMANN_CONSTANT *
214214
temperature
215215
relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(
@@ -249,7 +249,7 @@ end
249249
potential_distance =
250250
nondimensional_potential_distance * number_of_links * link_length
251251
potential_stiffness =
252-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
252+
nondimensional_potential_stiffness / link_length^2 *
253253
BOLTZMANN_CONSTANT *
254254
temperature
255255
relative_helmholtz_free_energy_per_link =
@@ -285,7 +285,7 @@ end
285285
potential_distance =
286286
nondimensional_potential_distance * number_of_links * link_length
287287
potential_stiffness =
288-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
288+
nondimensional_potential_stiffness / link_length^2 *
289289
BOLTZMANN_CONSTANT *
290290
temperature
291291
helmholtz_free_energy = model.helmholtz_free_energy(
@@ -325,7 +325,7 @@ end
325325
potential_distance =
326326
nondimensional_potential_distance * number_of_links * link_length
327327
potential_stiffness =
328-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
328+
nondimensional_potential_stiffness / link_length^2 *
329329
BOLTZMANN_CONSTANT *
330330
temperature
331331
relative_helmholtz_free_energy = model.relative_helmholtz_free_energy(
@@ -438,7 +438,7 @@ end
438438
potential_distance =
439439
nondimensional_potential_distance * number_of_links * link_length
440440
potential_stiffness =
441-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
441+
nondimensional_potential_stiffness / link_length^2 *
442442
BOLTZMANN_CONSTANT *
443443
temperature
444444
helmholtz_free_energy = model.helmholtz_free_energy(
@@ -482,7 +482,7 @@ end
482482
potential_distance =
483483
nondimensional_potential_distance * number_of_links * link_length
484484
potential_stiffness =
485-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
485+
nondimensional_potential_stiffness / link_length^2 *
486486
BOLTZMANN_CONSTANT *
487487
temperature
488488
helmholtz_free_energy_per_link = model.helmholtz_free_energy_per_link(
@@ -605,7 +605,7 @@ end
605605
temperature =
606606
parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand())
607607
potential_stiffness =
608-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
608+
nondimensional_potential_stiffness / link_length^2 *
609609
BOLTZMANN_CONSTANT *
610610
temperature
611611
relative_helmholtz_free_energy_0 = model.relative_helmholtz_free_energy(
@@ -633,7 +633,7 @@ end
633633
temperature =
634634
parameters.temperature_reference + parameters.temperature_scale * (0.5 - rand())
635635
potential_stiffness =
636-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
636+
nondimensional_potential_stiffness / link_length^2 *
637637
BOLTZMANN_CONSTANT *
638638
temperature
639639
relative_helmholtz_free_energy_per_link_0 =
@@ -707,7 +707,7 @@ end
707707
potential_distance =
708708
nondimensional_potential_distance * number_of_links * link_length
709709
potential_stiffness =
710-
nondimensional_potential_stiffness / (number_of_links * link_length)^2 *
710+
nondimensional_potential_stiffness / link_length^2 *
711711
BOLTZMANN_CONSTANT *
712712
temperature
713713
force = model.force(potential_distance, potential_stiffness, temperature)

0 commit comments

Comments
 (0)