1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 Copyright (c) 2020 of Glen Hocky
3
4 The FISST module is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 The FISST module is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with plumed. If not, see <http://www.gnu.org/licenses/>.
16 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
17 #include "bias/Bias.h"
18 #include "core/ActionRegister.h"
19 #include "core/Atoms.h"
20 #include "core/PlumedMain.h"
21 #include "tools/File.h"
22 #include "tools/Matrix.h"
23 #include "tools/Random.h"
24 #include "legendre_rule_fast.h"
25
26 #include <iostream>
27
28
29 using namespace PLMD;
30 using namespace bias;
31
32 //namespace is lowercase to match
33 //module names being all lowercase
34
35 namespace PLMD {
36 namespace fisst {
37
38 //+PLUMEDOC FISSTMOD_BIAS FISST
39 /*
40 Compute and apply the optimal linear force on an observable to enhance sampling of conformational distributions over a range of applied forces.
41
42 This method is described in \cite Hartmann-FISST-2019
43
44 If the system's Hamiltonian is given by:
45 \f[
46 H(\vec{p},\vec{q}) = \sum_{j} \frac{p_j^2}{2m_j} + U(\vec{q}),
47 \f]
48
49 This bias modifies the Hamiltonian to be:
50 \f[
51 H'(\vec{p},\vec{q}) = H(\vec{p},\vec{q}) - \bar{F} Q
52 \f]
53
54 where for CV \f$Q\f$, a coupling constant \f${\bar{F}}\f$ is determined
55 adaptively according to the FISST algorithm.
56
57 Specifically,
58 \f[
59 \bar{F}(Q)=\frac{ \int_{F_{min}}^{F_{max}} e^{\beta F Q(\vec{q})} \omega(F) F dF}{\int_{F_{min}}^{F_{max}} e^{\beta F Q(\vec{q})} \omega(F) dF},
60 \f]
61
62 where \f$\vec{q}\f$ are the molecular coordinates of the system, and \f$w(F)\f$ is a weighting function that is learned on the fly for each force by the FISST algorithm (starting from an initial weight distribution, uniform by default).
63
64 The target for \f$w(F)=1/Z_q(F)\f$, where
65 \f[
66 Z_q(F) \equiv \int d\vec{q} e^{-\beta U(\vec{q}) + \beta F Q(\vec{q})}.
67 \f]
68
69 FISST also computes and writes Observable Weights \f$W_F(\vec{q}_t)\f$ for a molecular configuration at time \f$t\f$, so that averages of other quantities \f$A(\vec{q})\f$ can be reconstructed later at different force values (over a trajectory with \f$T\f$ samples):
70 \f[
71 \langle A \rangle_F = \frac{1}{T} \sum_t W_F(\vec{q}_t) A(\vec{q}_t).
72 \f]
73
74
75 \par Examples
76
77 In the following example, an adaptive restraint is learned to bias the distance between two atoms in a system, for a force range of 0-100 pN.
78
79 \plumedfile
80 UNITS LENGTH=A TIME=fs ENERGY=kcal/mol
81
82 b1: GROUP ATOMS=1
83 b2: GROUP ATOMS=12
84
85 dend: DISTANCE ATOMS=b1,b2
86
87 #The conversion factor is 69.4786 pN = 1 kcal/mol/Angstrom
88
89 #0 pN to 100 pN
90 f: FISST MIN_FORCE=0 MAX_FORCE=1.44 PERIOD=100 NINTERPOLATE=31 ARG=dend OUT_RESTART=pull.restart.txt OUT_OBSERVABLE=pull.observable.txt OBSERVABLE_FREQ=1000
91
92 PRINT ARG=dend,f.dend_fbar,f.bias,f.force2 FILE=pull.colvar.txt STRIDE=1000
93 \endplumedfile
94
95
96 */
97 //+ENDPLUMEDOC
98
99
100 class FISST : public Bias {
101
102
103 private:
104 /*We will get this and store it once, since on-the-fly changing number of CVs will be fatal*/
105 const unsigned int ncvs_;
106 std::vector<double> center_;
107 std::vector<double> current_avg_force_;
108
109 std::vector<double> forces_;
110 std::vector<double> force_weight_;
111 std::vector<double> gauss_weight_;
112 std::vector<double> partition_estimate_;
113 std::vector<double> observable_weight_;
114
115 std::string in_restart_name_;
116 std::string out_restart_name_;
117 std::string out_observable_name_;
118 std::string fmt_;
119 std::string initial_weight_dist_;
120 OFile out_restart_;
121 OFile out_observable_;
122 IFile in_restart_;
123 bool b_freeze_;
124 bool b_adaptive_;
125 bool b_restart_;
126 bool b_write_restart_;
127 bool b_write_observable_;
128 bool b_first_restart_sample_;
129 int period_;
130 int reset_period_;
131 int observable_freq_;
132 int n_interpolation_;
133 int n_samples_;
134 double kbt_;
135 double beta_;
136 //change min_force and max_force to vectors if going to do more than one cv
137 double max_force_;
138 double min_force_;
139 double initial_weight_rate_;
140 double threshold_;
141 Random rand_;
142
143
144 Value* value_force2_;
145 void readInRestart();
146 void NormalizeForceWeights();
147 /*setup output restart*/
148 void setupOutRestart();
149 void setupOutObservable();
150 /*write output restart*/
151 void writeOutRestart();
152 void writeOutObservable();
153 void update_statistics();
154 void update_bias();
155 void apply_bias();
156 void compute_observable_weight();
157
158 public:
159 explicit FISST(const ActionOptions&);
160 void calculate();
161 void update();
162 void turnOnDerivatives();
163 static void registerKeywords(Keywords& keys);
164 ~FISST();
165 };
166
167 PLUMED_REGISTER_ACTION(FISST,"FISST")
168
registerKeywords(Keywords & keys)169 void FISST::registerKeywords(Keywords& keys) {
170 Bias::registerKeywords(keys);
171 keys.use("ARG");
172 keys.add("compulsory","PERIOD","Steps corresponding to the learning rate");
173 keys.add("optional","RESET_PERIOD","Reset the learning statistics every time this number of steps comes around.");
174 keys.add("compulsory","NINTERPOLATE","Number of grid points on which to do interpolation.");
175 keys.add("compulsory","MIN_FORCE","Minimum force (per CV) to use for sampling. Units: [Energy]/[CV] (can be negative).");
176 keys.add("compulsory","MAX_FORCE","Maximum force (per CV) to use for sampling.");
177 keys.add("compulsory","CENTER","0","The CV value at which the applied bias energy will be zero");
178 keys.add("optional","KBT","The system temperature in units of KB*T. If not provided will be taken from MD code (if available)");
179
180 keys.add("optional","INITIAL_WEIGHT_DIST","Starting distribution for the force weights (options: UNIFORM, EXP, GAUSS).");
181 keys.add("optional","INITIAL_WEIGHT_RATE","Rate of decay for exponential and gaussian distributions. W(F)~exp(-r |F|^d).");
182
183 keys.add("optional","RESTART_FMT","the format that should be used to output real numbers in FISST restarts.");
184 keys.add("optional","OUT_RESTART","Output file for all information needed to continue FISST simulation."
185 "If you have the RESTART directive set (global or for FISST), this file will be appended to."
186 "Note that the header will be printed again if appending.");
187 keys.add("optional","IN_RESTART","Read this file to continue an FISST simulation. "
188 "If same as OUT_RESTART and you have not set the RESTART directive, the file will be backed-up and overwritten with new output."
189 "If you do have the RESTART flag set and it is the same name as OUT_RESTART, this file will be appended.");
190 keys.add("optional","OUT_OBSERVABLE","Output file putting weights needed to compute observables at different force values."
191 "If you have the RESTART directive set (global or for FISST), this file will be appended to. "
192 "Note that the header will be printed again if appending.");
193 keys.add("optional","OBSERVABLE_FREQ","How often to write out observable weights (default=period).");
194 keys.addFlag("FREEZE",false,"Fix bias weights at current level (only used for restarting).");
195 keys.use("RESTART");
196 keys.addOutputComponent("force2","default","squared value of force from the bias.");
197 keys.addOutputComponent("_fbar","default", "For each named CV biased, there will be a corresponding output CV_fbar storing the current linear bias prefactor.");
198 }
199
FISST(const ActionOptions & ao)200 FISST::FISST(const ActionOptions&ao):
201 PLUMED_BIAS_INIT(ao),
202 ncvs_(getNumberOfArguments()),
203 current_avg_force_(ncvs_,0.0),
204 center_(ncvs_,0.0),
205 //change min_force and max_force to vectors if going to do more than one cv
206 min_force_(0.0),
207 max_force_(0.0),
208 in_restart_name_(""),
209 out_restart_name_(""),
210 out_observable_name_(""),
211 fmt_("%e"),
212 b_freeze_(false),
213 b_restart_(false),
214 b_write_restart_(false),
215 b_write_observable_(false),
216 b_first_restart_sample_(true),
217 n_interpolation_(0),
218 n_samples_(0),
219 initial_weight_rate_(0),
220 initial_weight_dist_("UNIFORM"),
221 period_(0),
222 reset_period_(0),
223 observable_freq_(0),
224 kbt_(0.0),
225 value_force2_(NULL)
226 {
227 if(ncvs_==0)
228 error("Must specify at least one CV with ARG");
229
230 //temporary
231 if(ncvs_>1)
232 error("FISST only supports using one CV right now");
233
234 addComponent("force2");
235 componentIsNotPeriodic("force2");
236 value_force2_ = getPntrToComponent("force2");
237
238 for(unsigned int i = 0; i<ncvs_; i++) {
239 std::string comp = getPntrToArgument(i)->getName() + "_fbar";
240 addComponent(comp);
241 componentIsNotPeriodic(comp);
242 }
243
244 parseVector("CENTER",center_);
245 //change min_force and max_force to vectors if going to do more than one cv
246 parse("MIN_FORCE",min_force_);
247 parse("MAX_FORCE",max_force_);
248 parse("PERIOD",period_);
249 parse("RESET_PERIOD",reset_period_);
250 parse("INITIAL_WEIGHT_DIST",initial_weight_dist_);
251 parse("INITIAL_WEIGHT_RATE",initial_weight_rate_);
252 parse("OBSERVABLE_FREQ",observable_freq_);
253 parse("NINTERPOLATE",n_interpolation_);
254 parseFlag("FREEZE",b_freeze_);
255 parse("KBT",kbt_);
256 parse("RESTART_FMT", fmt_);
257 fmt_ = " " + fmt_;//add space since parse strips them
258 parse("OUT_RESTART",out_restart_name_);
259 parse("OUT_OBSERVABLE",out_observable_name_);
260 parse("IN_RESTART",in_restart_name_);
261 checkRead();
262
263 if(center_.size() != ncvs_)
264 error("Must have same number of CENTER arguments as ARG arguments");
265
266 if(in_restart_name_ != "") {
267 b_restart_ = true;
268 log.printf(" reading simulation information from file: %s\n",in_restart_name_.c_str());
269 readInRestart();
270 } else {
271
272 if(! kbt_ > 0.0)
273 kbt_ = plumed.getAtoms().getKbT();
274
275 //in driver, this results in kbt of 0
276 if(kbt_ == 0) {
277 error(" Unable to determine valid kBT. "
278 "Could be because you are runnning from driver or MD didn't give temperature.\n"
279 "Consider setting temperature manually with the KBT keyword.");
280 }
281
282 log.printf(" kBT = %f\n",kbt_);
283 log.printf(" Updating with a time scale of %i steps\n",period_);
284
285 log.printf(" Using centers for CVs of:");
286 for(unsigned int i = 0; i< ncvs_; i++) {
287 log.printf(" %f ",center_[i]);
288 }
289 log.printf("\n");
290 observable_weight_.resize(n_interpolation_);
291 for(unsigned int i = 0; i<n_interpolation_; i++) observable_weight_[i] = 1.0;
292
293 forces_.resize(n_interpolation_);
294 force_weight_.resize(n_interpolation_);
295 //using code from the MIST project
296 gauss_weight_.resize(n_interpolation_);
297 legendre_compute_glr(n_interpolation_, &forces_[0], &gauss_weight_[0]);
298 rescale(min_force_, max_force_, n_interpolation_, &forces_[0], &gauss_weight_[0]);
299
300 log.printf("Using weight distribution %s with rate %f\n",initial_weight_dist_.c_str(),initial_weight_rate_);
301 if(initial_weight_dist_ == "UNIFORM" ) {
302 for(unsigned int i = 0; i<n_interpolation_; i++) force_weight_[i] = 1.0;
303 }
304 else if (initial_weight_dist_ == "EXP" ) {
305 for(unsigned int i = 0; i<n_interpolation_; i++) force_weight_[i] = exp(-fabs(forces_[i])*initial_weight_rate_);
306 }
307 else if (initial_weight_dist_ == "GAUSS" ) {
308 for(unsigned int i = 0; i<n_interpolation_; i++) force_weight_[i] = exp(-pow(forces_[i],2)*initial_weight_rate_);
309 }
310 else {
311 error(" Specified weight distribution is not from the allowed list.");
312
313 }
314
315 partition_estimate_.resize(n_interpolation_);
316 NormalizeForceWeights();
317 double sum = 0.0;
318 for(unsigned int i = 0; i<n_interpolation_; i++) {
319 //setting partition estimate as 1/w_i
320 partition_estimate_[i] = 1/force_weight_[i];
321 log.printf("force/gauss weight/force_weight: %i %f %f %f\n",i,forces_[i],gauss_weight_[i],force_weight_[i]);
322 sum+=gauss_weight_[i]*force_weight_[i];
323 }
324 log.printf("--Sum_i w_i g_i: %f\n",sum);
325
326 }
327
328 //set inverse temperature
329 beta_ = 1/kbt_;
330
331 if(b_freeze_ && b_restart_) {
332 log.printf(" freezing weights read in from the restart file\n");
333 }
334
335 if(out_restart_name_.length()>0) {
336 log.printf(" writing restart information every %i steps to file %s with format %s\n",abs(period_),out_restart_name_.c_str(), fmt_.c_str());
337 b_write_restart_ = true;
338 setupOutRestart();
339 }
340 if(out_observable_name_.length()>0) {
341 if(observable_freq_==0) observable_freq_ = period_;
342 log.printf(" writing observable information every %i steps to file %s with format %s\n",observable_freq_,out_observable_name_.c_str(), fmt_.c_str());
343 b_write_observable_ = true;
344 setupOutObservable();
345 }
346
347 //add citation later:
348 //log<<" Bibliography "<<plumed.cite("")<<"\n";
349 }
350
NormalizeForceWeights()351 void FISST::NormalizeForceWeights() {
352 double denom = 0.0;
353
354 for(unsigned i=0; i<n_interpolation_; i++)
355 denom += gauss_weight_[i] * force_weight_[i];
356
357 for(unsigned i=0; i<n_interpolation_; i++)
358 force_weight_[i] /= denom;
359 }
360
readInRestart()361 void FISST::readInRestart() {
362 in_restart_.open(in_restart_name_);
363
364 if(in_restart_.FieldExist("kbt")) {
365 in_restart_.scanField("kbt",kbt_);
366 } else { error("No field 'kbt' in restart file"); }
367 log.printf(" with kBT = %f\n",kbt_);
368
369 if(in_restart_.FieldExist("period")) {
370 in_restart_.scanField("period",period_);
371 } else { error("No field 'period' in restart file"); }
372 log.printf(" Updating every %i steps\n",period_);
373
374 //this one can be optional
375 if(in_restart_.FieldExist("reset_period")) {
376 in_restart_.scanField("reset_period",reset_period_);
377 }
378 log.printf(" Resetting statistics every %i steps\n",reset_period_);
379
380 if(in_restart_.FieldExist("n_interpolation")) {
381 in_restart_.scanField("n_interpolation",n_interpolation_);
382 } else { error("No field 'n_interpolation' in restart file"); }
383
384 if(in_restart_.FieldExist("min_force")) {
385 in_restart_.scanField("min_force",min_force_);
386 } else { error("No field 'min_force' in restart file"); }
387 if(in_restart_.FieldExist("max_force")) {
388 in_restart_.scanField("max_force",max_force_);
389 } else { error("No field 'max_force' in restart file"); }
390 log.printf(" with forces from min_force=%e to max_force=%e over %i bins\n",min_force_,max_force_,n_interpolation_);
391
392 unsigned int N = 0;
393 std::string cv_name;
394 double tmp, time;
395
396 while(in_restart_.scanField("time",time)) {
397 in_restart_.scanField("nsamples",n_samples_);
398
399 observable_weight_.resize(n_interpolation_);
400 partition_estimate_.resize(n_interpolation_);
401 force_weight_.resize(n_interpolation_);
402 gauss_weight_.resize(n_interpolation_);
403 forces_.resize(n_interpolation_);
404
405 for(unsigned int i = 0; i<ncvs_; ++i) {
406 cv_name = getPntrToArgument(i)->getName();
407 in_restart_.scanField(cv_name,tmp);
408 for(unsigned int j =0; j<n_interpolation_; ++j) {
409 in_restart_.scanField(cv_name + "_f"+std::to_string(j),forces_[j]);
410 in_restart_.scanField(cv_name + "_g"+std::to_string(j),gauss_weight_[j]);
411 in_restart_.scanField(cv_name + "_w"+std::to_string(j),force_weight_[j]);
412 in_restart_.scanField(cv_name + "_z"+std::to_string(j),partition_estimate_[j]);
413 }
414 }
415 N++;
416
417 in_restart_.scanField();
418 }
419
420 double sum = 0.0;
421 for(unsigned int j =0; j<n_interpolation_; ++j) {
422 //clear observable weight, which will be set later
423 observable_weight_[j] = 1.0;
424
425 //setting partition estimate as 1/w_i
426 log.printf("force/gauss weight/force_weight: %i %e %e %e\n",j,forces_[j],gauss_weight_[j],force_weight_[j]);
427 sum+=gauss_weight_[j]*force_weight_[j];
428 }
429 log.printf("--Sum_i w_i g_i: %f\n",sum);
430
431 in_restart_.close();
432 }
433
setupOutObservable()434 void FISST::setupOutObservable() {
435 out_observable_.link(*this);
436 out_observable_.fmtField(fmt_);
437 out_observable_.open(out_observable_name_);
438 out_observable_.setHeavyFlush();
439
440 out_observable_.addConstantField("kbt").printField("kbt",kbt_);
441 out_observable_.addConstantField("n_interpolation").printField("n_interpolation",n_interpolation_);
442 out_observable_.addConstantField("period").printField("period",period_);
443 out_observable_.addConstantField("min_force").printField("min_force",min_force_);
444 out_observable_.addConstantField("max_force").printField("max_force",max_force_);
445 }
446
setupOutRestart()447 void FISST::setupOutRestart() {
448 out_restart_.link(*this);
449 out_restart_.fmtField(fmt_);
450 out_restart_.open(out_restart_name_);
451 out_restart_.setHeavyFlush();
452
453 out_restart_.addConstantField("kbt").printField("kbt",kbt_);
454 out_restart_.addConstantField("n_interpolation").printField("n_interpolation",n_interpolation_);
455 out_restart_.addConstantField("period").printField("period",period_);
456 if(reset_period_>0) out_restart_.addConstantField("reset_period").printField("reset_period",reset_period_);
457 out_restart_.addConstantField("min_force").printField("min_force",min_force_);
458 out_restart_.addConstantField("max_force").printField("max_force",max_force_);
459 }
460
writeOutRestart()461 void FISST::writeOutRestart() {
462 std::string cv_name;
463 out_restart_.printField("time",getTimeStep()*getStep());
464 out_restart_.printField("nsamples",n_samples_);
465
466 for(unsigned int i = 0; i<ncvs_; ++i) {
467 cv_name = getPntrToArgument(i)->getName();
468 double Q_i = difference(i, center_[i], getArgument(i));
469 out_restart_.printField(cv_name,Q_i);
470 for(int j = 0; j < n_interpolation_; j++ ) {
471 //have to update this for multiple cvs
472 out_restart_.printField(cv_name + "_f"+std::to_string(j),forces_[j]);
473 out_restart_.printField(cv_name + "_g"+std::to_string(j),gauss_weight_[j]);
474 out_restart_.printField(cv_name + "_w"+std::to_string(j),force_weight_[j]);
475 out_restart_.printField(cv_name + "_z"+std::to_string(j),partition_estimate_[j]);
476 }
477 }
478 out_restart_.printField();
479 }
480
writeOutObservable()481 void FISST::writeOutObservable() {
482 std::string cv_name;
483 out_observable_.printField("time",getTimeStep()*getStep());
484 out_observable_.printField("nsamples",n_samples_);
485
486 for(unsigned int i = 0; i<ncvs_; ++i) {
487 cv_name = getPntrToArgument(i)->getName();
488 double Q_i = difference(i, center_[i], getArgument(i));
489 out_observable_.printField(cv_name,Q_i);
490 out_observable_.printField(cv_name + "_fbar",current_avg_force_[i]);
491 for(int j = 0; j < n_interpolation_; j++ ) {
492 //have to update this for multiple cvs
493 out_observable_.printField(cv_name + "_f"+std::to_string(j),forces_[j]);
494 out_observable_.printField(cv_name + "_ow"+std::to_string(j),observable_weight_[j]);
495 }
496 }
497 out_observable_.printField();
498 }
499
500
calculate()501 void FISST::calculate() {
502 if(getStep() == 0 ) {
503 if(b_write_restart_) writeOutRestart();
504 if(b_write_observable_) writeOutObservable();
505 }
506
507 if(! b_freeze_) {
508 if(b_restart_ && b_first_restart_sample_) {
509 //dont' update statistics if restarting and first sample
510 b_first_restart_sample_ = false;
511 }
512 else {
513 update_statistics();
514 }
515 }
516 update_bias();
517 apply_bias();
518
519 //check about writing restart file
520 if(getStep()>0 && getStep()%period_==0) {
521 if(b_write_restart_) writeOutRestart();
522 }
523 if(getStep()>0 && getStep()%observable_freq_==0) {
524 if(b_write_observable_) {
525 compute_observable_weight();
526 writeOutObservable();
527 }
528 }
529 }
530
531
apply_bias()532 void FISST::apply_bias() {
533 //Compute linear force as in "restraint"
534 double ene = 0, totf2 = 0, cv, m, f;
535
536 for(unsigned int i = 0; i < ncvs_; ++i) {
537 cv = difference(i, center_[i], getArgument(i));
538 double fbar = current_avg_force_[i];
539 ene -= fbar*cv;
540 setOutputForce(i,fbar);
541 totf2 += fbar*fbar;
542
543 std::string fbar_name_ = getPntrToArgument(i)->getName() + "_fbar";
544 Value* fbar_ = getPntrToComponent(fbar_name_);
545 fbar_->set(fbar);
546 };
547
548 setBias(ene);
549 value_force2_->set(totf2);
550 //log.flush();
551 }
552
update_statistics()553 void FISST::update_statistics() {
554 //get stride is for multiple time stepping
555 double dt=getTimeStep()*getStride();
556 double h = dt/(period_*getTimeStep());
557 double fbar_denum_integral = 0.0;
558
559 int step = getStep();
560 if(reset_period_>0 && step>0 && step%reset_period_==0) {
561 n_samples_=1;
562 }
563 else {
564 n_samples_++;
565 }
566 double d_n_samples = (double)n_samples_;
567
568 for(unsigned int i = 0; i < ncvs_; ++i) {
569 double Q_i = difference(i, center_[i], getArgument(i));
570 for(unsigned int j=0; j<n_interpolation_; j++)
571 {
572 //if multiple cvs, these need to be updated to have 2 columns
573 double f_j = forces_[j];
574 double w_j = force_weight_[j];
575 double g_j = gauss_weight_[j];
576
577 fbar_denum_integral += g_j * w_j * exp(beta_*f_j * Q_i);
578 }
579
580 for(unsigned int j=0; j<n_interpolation_; j++)
581 {
582 double f_j = forces_[j];
583 double sample_weight = exp(beta_*f_j * Q_i) / fbar_denum_integral;
584
585 partition_estimate_[j] = sample_weight/d_n_samples + partition_estimate_[j]*(d_n_samples-1)/(d_n_samples);
586
587 double w_jn = force_weight_[j];
588 double z_jn = partition_estimate_[j];
589
590 double w_jp1 = (1.0 - h) * w_jn + h / z_jn;
591 force_weight_[j] = w_jp1;
592 }
593 }
594
595 // make sure that the weights are normalised
596 NormalizeForceWeights();
597 }
598
599
update_bias()600 void FISST::update_bias()
601 {
602 for(unsigned int i = 0; i < ncvs_; ++i) {
603 double Q_i = difference(i, center_[i], getArgument(i));
604 double fbar_num_integral = 0.0;
605 double fbar_denum_integral = 0.0;
606
607 for(unsigned int j=0; j<n_interpolation_; j++ ) {
608 double f_j = forces_[j];
609 double w_j = force_weight_[j];
610 double g_j = gauss_weight_[j];
611
612 fbar_num_integral += g_j * f_j * w_j * exp(beta_*f_j*Q_i);
613 fbar_denum_integral += g_j * w_j * exp(beta_*f_j*Q_i);
614 }
615
616 current_avg_force_[i] = fbar_num_integral/fbar_denum_integral;
617 }
618 }
619
compute_observable_weight()620 void FISST::compute_observable_weight() {
621 double obs_num = (max_force_ - min_force_);
622
623 for(unsigned int i = 0; i < ncvs_; ++i) {
624 double Q_i = difference(i, center_[i], getArgument(i));
625
626 for(unsigned int j=0; j<n_interpolation_; j++ ) {
627 double z_j = partition_estimate_[j];
628 double f_j = forces_[j];
629 double denum_integral = 0.0;
630
631 for( unsigned int k=0; k<n_interpolation_; k++ ) {
632 double f_k = forces_[k];
633 double w_k = force_weight_[k];
634 double g_k = gauss_weight_[k];
635
636 denum_integral += g_k * w_k * exp(beta_*(f_k-f_j)*Q_i);
637 }
638 observable_weight_[j] = obs_num/(denum_integral*z_j);
639 }
640 }
641 }
642
643
644
update()645 void FISST::update() {
646 //pass
647 }
648
~FISST()649 FISST::~FISST() {
650 out_restart_.close();
651 out_observable_.close();
652 }
653
turnOnDerivatives()654 void FISST::turnOnDerivatives() {
655 // do nothing
656 // this is to avoid errors triggered when a bias is used as a CV
657 // (This is done in ExtendedLagrangian.cpp)
658 }
659
660
661 }
662 }//close the 2 namespaces
663