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