@@ -57,8 +57,16 @@ cvm::real colvar::coordnum::switching_function(cvm::real const &r0,
5757
5858 cvm::real const xn = cvm::integer_power (l2, en2);
5959 cvm::real const xd = cvm::integer_power (l2, ed2);
60- // The subtraction and division stretches the function back to the range of [0,1] from [pairlist_tol,1]
61- cvm::real const func_no_pairlist = (1.0 -xn)/(1.0 -xd);
60+ cvm::real const eps = 1.0e-8 ;
61+ cvm::real const h = l2 - 1.0 ;
62+ cvm::real const en2_r = (cvm::real) en2;
63+ cvm::real const ed2_r = (cvm::real) ed2;
64+
65+ // Function value: 1st-order Taylor expansion around l2 = 1
66+ cvm::real const func_no_pairlist = (std::abs (h) < eps) ?
67+ (en2_r / ed2_r) + h * (en2_r * (en2_r - ed2_r) / (2.0 * ed2_r)) :
68+ (1.0 - xn) / (1.0 - xd);
69+
6270 cvm::real func, inv_one_pairlist_tol;
6371 if (flags & ef_use_pairlist) {
6472 inv_one_pairlist_tol = 1 / (1.0 -pairlist_tol);
@@ -77,23 +85,19 @@ cvm::real colvar::coordnum::switching_function(cvm::real const &r0,
7785 return 0 ;
7886
7987 if (flags & ef_gradients) {
80- // This is the old, completely correct expression for dFdl2:
81- // cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) -
82- // func*ed2*(xd/l2))*(-1.0);
83- // This can become:
84- // cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2)*(1.0-xn)/(1.0-xn) -
85- // func*ed2*(xd/l2))*(-1.0);
86- // Recognizing that func = (1.0-xn)/(1.0-xd), we can group together the "func" and get a version of dFdl2 that is 0
87- // when func=0, which lets us skip this gradient calculation when func=0.
88- cvm::real dFdl2;
89- if (flags & ef_use_pairlist) {
90- dFdl2 = func_no_pairlist * inv_one_pairlist_tol * ((ed2*xd/((1.0 -xd)*l2)) - (en2*xn/((1.0 -xn)*l2)));
91- } else {
92- dFdl2 = func * ((ed2*xd/((1.0 -xd)*l2)) - (en2*xn/((1.0 -xn)*l2)));
93- }
88+ // Logarithmic derivative: 1st-order Taylor expansion around l2 = 1
89+ cvm::real const log_deriv = (std::abs (h) < eps) ?
90+ 0.5 * (en2_r - ed2_r) + h * ((en2_r - ed2_r) * (en2_r + ed2_r - 6.0 ) / 12.0 ) :
91+ ((ed2_r * xd / ((1.0 - xd) * l2)) - (en2_r * xn / ((1.0 - xn) * l2)));
92+
93+ cvm::real const dFdl2 = (flags & ef_use_pairlist) ?
94+ func_no_pairlist * inv_one_pairlist_tol * log_deriv :
95+ func * log_deriv;
96+
9497 cvm::rvector const dl2dx ((2.0 * inv_r0sq_vec.x ) * diff.x ,
9598 (2.0 * inv_r0sq_vec.y ) * diff.y ,
9699 (2.0 * inv_r0sq_vec.z ) * diff.z );
100+
97101 const cvm::rvector G = dFdl2*dl2dx;
98102 g1x += -1.0 *G.x ;
99103 g1y += -1.0 *G.y ;
0 commit comments