1 // -*- c++ -*-
2 
3 // This file is part of the Collective Variables module (Colvars).
4 // The original version of Colvars and its updates are located at:
5 // https://github.com/Colvars/colvars
6 // Please update all Colvars source files before making any changes.
7 // If you wish to distribute your changes, please submit them to the
8 // Colvars repository at GitHub.
9 
10 #include "colvarmodule.h"
11 #include "colvarproxy.h"
12 #include "colvarvalue.h"
13 #include "colvarbias_restraint.h"
14 
15 
16 
colvarbias_restraint(char const * key)17 colvarbias_restraint::colvarbias_restraint(char const *key)
18   : colvarbias(key), colvarbias_ti(key)
19 {
20   state_keyword = "restraint";
21 }
22 
23 
init(std::string const & conf)24 int colvarbias_restraint::init(std::string const &conf)
25 {
26   colvarbias::init(conf);
27   enable(f_cvb_apply_force);
28 
29   colvarbias_ti::init(conf);
30 
31   if (cvm::debug())
32     cvm::log("Initializing a new restraint bias.\n");
33 
34   return COLVARS_OK;
35 }
36 
37 
update()38 int colvarbias_restraint::update()
39 {
40   // Update base class (bias_energy and colvar_forces are zeroed there)
41   colvarbias::update();
42 
43   // Force and energy calculation
44   for (size_t i = 0; i < num_variables(); i++) {
45     bias_energy += restraint_potential(i);
46     colvar_forces[i].type(variables(i)->value());
47     colvar_forces[i].is_derivative();
48     colvar_forces[i] = restraint_force(i);
49   }
50 
51   if (cvm::debug())
52     cvm::log("Done updating the restraint bias \""+this->name+"\".\n");
53 
54   if (cvm::debug())
55     cvm::log("Current forces for the restraint bias \""+
56              this->name+"\": "+cvm::to_str(colvar_forces)+".\n");
57 
58   return COLVARS_OK;
59 }
60 
61 
~colvarbias_restraint()62 colvarbias_restraint::~colvarbias_restraint()
63 {
64 }
65 
66 
get_state_params() const67 std::string const colvarbias_restraint::get_state_params() const
68 {
69   return colvarbias::get_state_params();
70 }
71 
72 
set_state_params(std::string const & conf)73 int colvarbias_restraint::set_state_params(std::string const &conf)
74 {
75   return colvarbias::set_state_params(conf);
76 }
77 
78 
write_traj_label(std::ostream & os)79 std::ostream & colvarbias_restraint::write_traj_label(std::ostream &os)
80 {
81   return colvarbias::write_traj_label(os);
82 }
83 
84 
write_traj(std::ostream & os)85 std::ostream & colvarbias_restraint::write_traj(std::ostream &os)
86 {
87   return colvarbias::write_traj(os);
88 }
89 
90 
91 
colvarbias_restraint_centers(char const * key)92 colvarbias_restraint_centers::colvarbias_restraint_centers(char const *key)
93   : colvarbias(key), colvarbias_ti(key), colvarbias_restraint(key)
94 {
95 }
96 
97 
init(std::string const & conf)98 int colvarbias_restraint_centers::init(std::string const &conf)
99 {
100   size_t i;
101 
102   bool null_centers = (colvar_centers.size() == 0);
103   if (null_centers) {
104     // try to initialize the restraint centers for the first time
105     colvar_centers.resize(num_variables());
106     for (i = 0; i < num_variables(); i++) {
107       colvar_centers[i].type(variables(i)->value());
108       colvar_centers[i].reset();
109     }
110   }
111 
112   if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
113     for (i = 0; i < num_variables(); i++) {
114       if (cvm::debug()) {
115         cvm::log("colvarbias_restraint: parsing initial centers, i = "+cvm::to_str(i)+".\n");
116       }
117       colvar_centers[i].apply_constraints();
118     }
119     null_centers = false;
120   }
121 
122   if (null_centers) {
123     colvar_centers.clear();
124     cvm::error("Error: must define the initial centers of the restraints.\n", INPUT_ERROR);
125     return INPUT_ERROR;
126   }
127 
128   if (colvar_centers.size() != num_variables()) {
129     cvm::error("Error: number of centers does not match "
130                "that of collective variables.\n", INPUT_ERROR);
131     return INPUT_ERROR;
132   }
133 
134   return COLVARS_OK;
135 }
136 
137 
change_configuration(std::string const & conf)138 int colvarbias_restraint_centers::change_configuration(std::string const &conf)
139 {
140   if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
141     for (size_t i = 0; i < num_variables(); i++) {
142       colvar_centers[i].type(variables(i)->value());
143       colvar_centers[i].apply_constraints();
144     }
145   }
146   return COLVARS_OK;
147 }
148 
149 
150 
colvarbias_restraint_k(char const * key)151 colvarbias_restraint_k::colvarbias_restraint_k(char const *key)
152   : colvarbias(key), colvarbias_ti(key), colvarbias_restraint(key)
153 {
154   force_k = -1.0;
155   check_positive_k = true;
156 }
157 
158 
init(std::string const & conf)159 int colvarbias_restraint_k::init(std::string const &conf)
160 {
161   get_keyval(conf, "forceConstant", force_k, (force_k > 0.0 ? force_k : 1.0));
162   if (check_positive_k && (force_k < 0.0)) {
163     cvm::error("Error: undefined or invalid force constant.\n", INPUT_ERROR);
164     return INPUT_ERROR;
165   }
166   return COLVARS_OK;
167 }
168 
169 
change_configuration(std::string const & conf)170 int colvarbias_restraint_k::change_configuration(std::string const &conf)
171 {
172   get_keyval(conf, "forceConstant", force_k, force_k);
173   return COLVARS_OK;
174 }
175 
176 
177 
colvarbias_restraint_moving(char const *)178 colvarbias_restraint_moving::colvarbias_restraint_moving(char const * /* key */)
179 {
180   target_nstages = 0;
181   target_nsteps = 0L;
182   stage = 0;
183   acc_work = 0.0;
184   b_chg_centers = false;
185   b_chg_force_k = false;
186 }
187 
188 
init(std::string const & conf)189 int colvarbias_restraint_moving::init(std::string const &conf)
190 {
191   if (b_chg_centers && b_chg_force_k) {
192     cvm::error("Error: cannot specify both targetCenters and targetForceConstant.\n",
193                INPUT_ERROR);
194     return INPUT_ERROR;
195   }
196 
197   if (b_chg_centers || b_chg_force_k) {
198 
199     get_keyval(conf, "targetNumSteps", target_nsteps, target_nsteps);
200     if (!target_nsteps) {
201       cvm::error("Error: targetNumSteps must be non-zero.\n", INPUT_ERROR);
202       return cvm::get_error();
203     }
204 
205     if (get_keyval(conf, "targetNumStages", target_nstages, target_nstages) &&
206         lambda_schedule.size()) {
207       cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", INPUT_ERROR);
208       return cvm::get_error();
209     }
210 
211     get_keyval_feature(this, conf, "outputAccumulatedWork",
212                        f_cvb_output_acc_work,
213                        is_enabled(f_cvb_output_acc_work));
214     if (is_enabled(f_cvb_output_acc_work) && (target_nstages > 0)) {
215       return cvm::error("Error: outputAccumulatedWork and targetNumStages "
216                         "are incompatible.\n", INPUT_ERROR);
217     }
218   }
219 
220   return COLVARS_OK;
221 }
222 
223 
get_state_params() const224 std::string const colvarbias_restraint_moving::get_state_params() const
225 {
226   std::ostringstream os;
227   os.setf(std::ios::scientific, std::ios::floatfield);
228   if (b_chg_centers || b_chg_force_k) {
229     // TODO move this
230     if (target_nstages) {
231       os << "stage " << std::setw(cvm::it_width)
232          << stage << "\n";
233     }
234   }
235   return os.str();
236 }
237 
238 
set_state_params(std::string const & conf)239 int colvarbias_restraint_moving::set_state_params(std::string const &conf)
240 {
241   if (b_chg_centers || b_chg_force_k) {
242     if (target_nstages) {
243       get_keyval(conf, "stage", stage, stage,
244                  colvarparse::parse_restart | colvarparse::parse_required);
245     }
246   }
247   return COLVARS_OK;
248 }
249 
250 
251 
colvarbias_restraint_centers_moving(char const * key)252 colvarbias_restraint_centers_moving::colvarbias_restraint_centers_moving(char const *key)
253   : colvarbias(key),
254     colvarbias_ti(key),
255     colvarbias_restraint(key),
256     colvarbias_restraint_centers(key),
257     colvarbias_restraint_moving(key)
258 {
259   b_chg_centers = false;
260   b_output_centers = false;
261 }
262 
263 
init(std::string const & conf)264 int colvarbias_restraint_centers_moving::init(std::string const &conf)
265 {
266   colvarbias_restraint_centers::init(conf);
267 
268   if (cvm::debug()) {
269     cvm::log("colvarbias_restraint: parsing target centers.\n");
270   }
271 
272   size_t i;
273   if (get_keyval(conf, "targetCenters", target_centers, colvar_centers)) {
274     if (target_centers.size() != num_variables()) {
275       cvm::error("Error: number of target centers does not match "
276                  "that of collective variables.\n", INPUT_ERROR);
277     }
278     b_chg_centers = true;
279     for (i = 0; i < target_centers.size(); i++) {
280       target_centers[i].apply_constraints();
281       centers_incr.push_back(colvar_centers[i]);
282       centers_incr[i].reset();
283     }
284   }
285 
286   if (b_chg_centers) {
287     // parse moving schedule options
288     colvarbias_restraint_moving::init(conf);
289     if (initial_centers.size() == 0) {
290       // One-time init
291       initial_centers = colvar_centers;
292     }
293     // Call to check that the definition is correct
294     for (i = 0; i < num_variables(); i++) {
295       colvarvalue const midpoint =
296         colvarvalue::interpolate(initial_centers[i],
297                                  target_centers[i],
298                                  0.5);
299     }
300 
301   } else {
302     target_centers.clear();
303   }
304 
305   // Output restraint centers even when they do not change; some NAMD REUS
306   // scripts expect this behavior
307   get_keyval(conf, "outputCenters", b_output_centers, b_output_centers);
308 
309   return COLVARS_OK;
310 }
311 
312 
update_centers(cvm::real lambda)313 int colvarbias_restraint_centers_moving::update_centers(cvm::real lambda)
314 {
315   if (cvm::debug()) {
316     cvm::log("Updating centers for the restraint bias \""+
317              this->name+"\": "+cvm::to_str(colvar_centers)+".\n");
318   }
319   size_t i;
320   for (i = 0; i < num_variables(); i++) {
321     colvarvalue const c_new = colvarvalue::interpolate(initial_centers[i],
322                                                        target_centers[i],
323                                                        lambda);
324     centers_incr[i] = 0.5 * c_new.dist2_grad(colvar_centers[i]);
325     colvar_centers[i] = c_new;
326     variables(i)->wrap(colvar_centers[i]);
327   }
328   if (cvm::debug()) {
329     cvm::log("New centers for the restraint bias \""+
330              this->name+"\": "+cvm::to_str(colvar_centers)+".\n");
331   }
332   return cvm::get_error();
333 }
334 
335 
update()336 int colvarbias_restraint_centers_moving::update()
337 {
338   if (b_chg_centers) {
339 
340     if (target_nstages) {
341       // Staged update
342       if (stage <= target_nstages) {
343         if ((cvm::step_relative() > 0) &&
344             ((cvm::step_absolute() % target_nsteps) == 1)) {
345           cvm::real const lambda =
346             cvm::real(stage)/cvm::real(target_nstages);
347           update_centers(lambda);
348           stage++;
349           cvm::log("Moving restraint \"" + this->name +
350                    "\" stage " + cvm::to_str(stage) +
351                    " : setting centers to " + cvm::to_str(colvar_centers) +
352                    " at step " +  cvm::to_str(cvm::step_absolute()));
353         } else {
354           for (size_t i = 0; i < num_variables(); i++) {
355             centers_incr[i].reset();
356           }
357         }
358       }
359     } else {
360       // Continuous update
361       if (cvm::step_absolute() <= target_nsteps) {
362         cvm::real const lambda =
363           cvm::real(cvm::step_absolute())/cvm::real(target_nsteps);
364         update_centers(lambda);
365       } else {
366         for (size_t i = 0; i < num_variables(); i++) {
367           centers_incr[i].reset();
368         }
369       }
370     }
371 
372     if (cvm::step_relative() == 0) {
373       for (size_t i = 0; i < num_variables(); i++) {
374         // finite differences are undefined when restarting
375         centers_incr[i].reset();
376       }
377     }
378 
379     if (cvm::debug()) {
380       cvm::log("Center increment for the restraint bias \""+
381                this->name+"\": "+cvm::to_str(centers_incr)+
382                " at stage "+cvm::to_str(stage)+ ".\n");
383     }
384   }
385 
386   return cvm::get_error();
387 }
388 
389 
update_acc_work()390 int colvarbias_restraint_centers_moving::update_acc_work()
391 {
392   if (b_chg_centers) {
393     if (is_enabled(f_cvb_output_acc_work)) {
394       if ((cvm::step_relative() > 0) &&
395           (cvm::step_absolute() <= target_nsteps)) {
396         for (size_t i = 0; i < num_variables(); i++) {
397           // project forces on the calculated increments at this step
398           acc_work += colvar_forces[i] * centers_incr[i];
399         }
400       }
401     }
402   }
403   return COLVARS_OK;
404 }
405 
406 
get_state_params() const407 std::string const colvarbias_restraint_centers_moving::get_state_params() const
408 {
409   std::ostringstream os;
410   os.setf(std::ios::scientific, std::ios::floatfield);
411 
412   if (b_chg_centers) {
413     size_t i;
414     os << "centers ";
415     for (i = 0; i < num_variables(); i++) {
416       os << " "
417          << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
418          << colvar_centers[i];
419     }
420     os << "\n";
421 
422     if (is_enabled(f_cvb_output_acc_work)) {
423       os << "accumulatedWork "
424          << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
425          << acc_work << "\n";
426     }
427   }
428 
429   return os.str();
430 }
431 
432 
set_state_params(std::string const & conf)433 int colvarbias_restraint_centers_moving::set_state_params(std::string const &conf)
434 {
435   colvarbias_restraint::set_state_params(conf);
436 
437   if (b_chg_centers) {
438     get_keyval(conf, "centers", colvar_centers, colvar_centers,
439                colvarparse::parse_restart | colvarparse::parse_required);
440   }
441 
442   if (is_enabled(f_cvb_output_acc_work)) {
443     get_keyval(conf, "accumulatedWork", acc_work, acc_work,
444                colvarparse::parse_restart | colvarparse::parse_required);
445   }
446 
447   return COLVARS_OK;
448 }
449 
450 
write_traj_label(std::ostream & os)451 std::ostream & colvarbias_restraint_centers_moving::write_traj_label(std::ostream &os)
452 {
453   if (b_output_centers) {
454     for (size_t i = 0; i < num_variables(); i++) {
455       size_t const this_cv_width = (variables(i)->value()).output_width(cvm::cv_width);
456       os << " x0_"
457          << cvm::wrap_string(variables(i)->name, this_cv_width-3);
458     }
459   }
460 
461   if (b_chg_centers && is_enabled(f_cvb_output_acc_work)) {
462     os << " W_"
463        << cvm::wrap_string(this->name, cvm::en_width-2);
464   }
465 
466   return os;
467 }
468 
469 
write_traj(std::ostream & os)470 std::ostream & colvarbias_restraint_centers_moving::write_traj(std::ostream &os)
471 {
472   if (b_output_centers) {
473     for (size_t i = 0; i < num_variables(); i++) {
474       os << " "
475          << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
476          << colvar_centers[i];
477     }
478   }
479 
480   if (b_chg_centers && is_enabled(f_cvb_output_acc_work)) {
481     os << " "
482        << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
483        << acc_work;
484   }
485 
486   return os;
487 }
488 
489 
490 
colvarbias_restraint_k_moving(char const * key)491 colvarbias_restraint_k_moving::colvarbias_restraint_k_moving(char const *key)
492   : colvarbias(key),
493     colvarbias_ti(key),
494     colvarbias_restraint(key),
495     colvarbias_restraint_k(key),
496     colvarbias_restraint_moving(key)
497 {
498   b_chg_force_k = false;
499   target_equil_steps = 0;
500   target_force_k = -1.0;
501   starting_force_k = -1.0;
502   force_k_exp = 1.0;
503   restraint_FE = 0.0;
504   force_k_incr = 0.0;
505 }
506 
507 
init(std::string const & conf)508 int colvarbias_restraint_k_moving::init(std::string const &conf)
509 {
510   colvarbias_restraint_k::init(conf);
511 
512   if (get_keyval(conf, "targetForceConstant", target_force_k, target_force_k)) {
513     starting_force_k = force_k;
514     b_chg_force_k = true;
515   }
516 
517   if (b_chg_force_k) {
518     // parse moving restraint options
519     colvarbias_restraint_moving::init(conf);
520   } else {
521     return COLVARS_OK;
522   }
523 
524   get_keyval(conf, "targetEquilSteps", target_equil_steps, target_equil_steps);
525 
526   if (get_keyval(conf, "lambdaSchedule", lambda_schedule, lambda_schedule) &&
527       target_nstages > 0) {
528     cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", INPUT_ERROR);
529     return cvm::get_error();
530   }
531 
532   if (lambda_schedule.size()) {
533     // There is one more lambda-point than stages
534     target_nstages = lambda_schedule.size() - 1;
535   }
536 
537   if (get_keyval(conf, "targetForceExponent", force_k_exp, force_k_exp)) {
538     if (! b_chg_force_k)
539       cvm::log("Warning: not changing force constant: targetForceExponent will be ignored\n");
540   }
541   if (force_k_exp < 1.0) {
542     cvm::log("Warning: for all practical purposes, targetForceExponent should be 1.0 or greater.\n");
543   }
544 
545   return COLVARS_OK;
546 }
547 
548 
update()549 int colvarbias_restraint_k_moving::update()
550 {
551   if (b_chg_force_k) {
552 
553     cvm::real lambda;
554 
555     if (target_nstages) {
556 
557       if (cvm::step_absolute() == 0) {
558         // Setup first stage of staged variable force constant calculation
559         if (lambda_schedule.size()) {
560           lambda = lambda_schedule[0];
561         } else {
562           lambda = 0.0;
563         }
564         force_k = starting_force_k + (target_force_k - starting_force_k)
565           * cvm::pow(lambda, force_k_exp);
566           cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage)
567                   + " : lambda = " + cvm::to_str(lambda)
568                   + ", k = " + cvm::to_str(force_k));
569       }
570 
571       // TI calculation: estimate free energy derivative
572       // need current lambda
573       if (lambda_schedule.size()) {
574         lambda = lambda_schedule[stage];
575       } else {
576         lambda = cvm::real(stage) / cvm::real(target_nstages);
577       }
578 
579       if (target_equil_steps == 0 || cvm::step_absolute() % target_nsteps >= target_equil_steps) {
580         // Start averaging after equilibration period, if requested
581 
582         // Derivative of energy with respect to force_k
583         cvm::real dU_dk = 0.0;
584         for (size_t i = 0; i < num_variables(); i++) {
585           dU_dk += d_restraint_potential_dk(i);
586         }
587         restraint_FE += force_k_exp * cvm::pow(lambda, force_k_exp - 1.0)
588           * (target_force_k - starting_force_k) * dU_dk;
589       }
590 
591       // Finish current stage...
592       if (cvm::step_absolute() % target_nsteps == 0 &&
593           cvm::step_absolute() > 0) {
594 
595         cvm::log("Restraint " + this->name + " Lambda= "
596                  + cvm::to_str(lambda) + " dA/dLambda= "
597                  + cvm::to_str(restraint_FE / cvm::real(target_nsteps - target_equil_steps)));
598 
599         //  ...and move on to the next one
600         if (stage < target_nstages) {
601 
602           restraint_FE = 0.0;
603           stage++;
604           if (lambda_schedule.size()) {
605             lambda = lambda_schedule[stage];
606           } else {
607             lambda = cvm::real(stage) / cvm::real(target_nstages);
608           }
609           force_k = starting_force_k + (target_force_k - starting_force_k)
610             * cvm::pow(lambda, force_k_exp);
611           cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage)
612                   + " : lambda = " + cvm::to_str(lambda)
613                   + ", k = " + cvm::to_str(force_k));
614         }
615       }
616 
617     } else if (cvm::step_absolute() <= target_nsteps) {
618 
619 
620       // update force constant (slow growth)
621       lambda = cvm::real(cvm::step_absolute()) / cvm::real(target_nsteps);
622       cvm::real const force_k_old = force_k;
623       force_k = starting_force_k + (target_force_k - starting_force_k)
624         * cvm::pow(lambda, force_k_exp);
625       force_k_incr = force_k - force_k_old;
626     }
627   }
628 
629   return COLVARS_OK;
630 }
631 
632 
update_acc_work()633 int colvarbias_restraint_k_moving::update_acc_work()
634 {
635   if (b_chg_force_k) {
636     if (is_enabled(f_cvb_output_acc_work)) {
637       if (cvm::step_relative() > 0) {
638         cvm::real dU_dk = 0.0;
639         for (size_t i = 0; i < num_variables(); i++) {
640           dU_dk += d_restraint_potential_dk(i);
641         }
642         acc_work += dU_dk * force_k_incr;
643       }
644     }
645   }
646   return COLVARS_OK;
647 }
648 
649 
get_state_params() const650 std::string const colvarbias_restraint_k_moving::get_state_params() const
651 {
652   std::ostringstream os;
653   os.setf(std::ios::scientific, std::ios::floatfield);
654   if (b_chg_force_k) {
655     os << "forceConstant "
656        << std::setprecision(cvm::en_prec)
657        << std::setw(cvm::en_width) << force_k << "\n";
658 
659     if (is_enabled(f_cvb_output_acc_work)) {
660       os << "accumulatedWork "
661          << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
662          << acc_work << "\n";
663     }
664   }
665   return os.str();
666 }
667 
668 
set_state_params(std::string const & conf)669 int colvarbias_restraint_k_moving::set_state_params(std::string const &conf)
670 {
671   colvarbias_restraint::set_state_params(conf);
672 
673   if (b_chg_force_k) {
674     get_keyval(conf, "forceConstant", force_k, force_k,
675                colvarparse::parse_restart | colvarparse::parse_required);
676   }
677 
678   if (is_enabled(f_cvb_output_acc_work)) {
679     get_keyval(conf, "accumulatedWork", acc_work, acc_work,
680                colvarparse::parse_restart | colvarparse::parse_required);
681   }
682 
683   return COLVARS_OK;
684 }
685 
686 
write_traj_label(std::ostream & os)687 std::ostream & colvarbias_restraint_k_moving::write_traj_label(std::ostream &os)
688 {
689   if (b_chg_force_k && is_enabled(f_cvb_output_acc_work)) {
690     os << " W_"
691        << cvm::wrap_string(this->name, cvm::en_width-2);
692   }
693   return os;
694 }
695 
696 
write_traj(std::ostream & os)697 std::ostream & colvarbias_restraint_k_moving::write_traj(std::ostream &os)
698 {
699   if (b_chg_force_k && is_enabled(f_cvb_output_acc_work)) {
700     os << " "
701        << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
702        << acc_work;
703   }
704   return os;
705 }
706 
707 
708 
colvarbias_restraint_harmonic(char const * key)709 colvarbias_restraint_harmonic::colvarbias_restraint_harmonic(char const *key)
710   : colvarbias(key),
711     colvarbias_ti(key),
712     colvarbias_restraint(key),
713     colvarbias_restraint_centers(key),
714     colvarbias_restraint_moving(key),
715     colvarbias_restraint_k(key),
716     colvarbias_restraint_centers_moving(key),
717     colvarbias_restraint_k_moving(key)
718 {
719 }
720 
721 
init(std::string const & conf)722 int colvarbias_restraint_harmonic::init(std::string const &conf)
723 {
724   colvarbias_restraint::init(conf);
725   colvarbias_restraint_moving::init(conf);
726   colvarbias_restraint_centers_moving::init(conf);
727   colvarbias_restraint_k_moving::init(conf);
728 
729   for (size_t i = 0; i < num_variables(); i++) {
730     cvm::real const w = variables(i)->width;
731     cvm::log("The force constant for colvar \""+variables(i)->name+
732              "\" will be rescaled to "+
733              cvm::to_str(force_k/(w*w))+
734              " according to the specified width ("+cvm::to_str(w)+").\n");
735   }
736 
737   return COLVARS_OK;
738 }
739 
740 
update()741 int colvarbias_restraint_harmonic::update()
742 {
743   int error_code = COLVARS_OK;
744 
745   // update the TI estimator (if defined)
746   error_code |= colvarbias_ti::update();
747 
748   // update parameters (centers or force constant)
749   error_code |= colvarbias_restraint_centers_moving::update();
750   error_code |= colvarbias_restraint_k_moving::update();
751 
752   // update restraint energy and forces
753   error_code |= colvarbias_restraint::update();
754 
755   // update accumulated work using the current forces
756   error_code |= colvarbias_restraint_centers_moving::update_acc_work();
757   error_code |= colvarbias_restraint_k_moving::update_acc_work();
758 
759   return error_code;
760 }
761 
762 
restraint_potential(size_t i) const763 cvm::real colvarbias_restraint_harmonic::restraint_potential(size_t i) const
764 {
765   return 0.5 * force_k / (variables(i)->width * variables(i)->width) *
766     variables(i)->dist2(variables(i)->value(), colvar_centers[i]);
767 }
768 
769 
restraint_force(size_t i) const770 colvarvalue const colvarbias_restraint_harmonic::restraint_force(size_t i) const
771 {
772   return -0.5 * force_k / (variables(i)->width * variables(i)->width) *
773     variables(i)->dist2_lgrad(variables(i)->value(), colvar_centers[i]);
774 }
775 
776 
d_restraint_potential_dk(size_t i) const777 cvm::real colvarbias_restraint_harmonic::d_restraint_potential_dk(size_t i) const
778 {
779   return 0.5 / (variables(i)->width * variables(i)->width) *
780     variables(i)->dist2(variables(i)->value(), colvar_centers[i]);
781 }
782 
783 
get_state_params() const784 std::string const colvarbias_restraint_harmonic::get_state_params() const
785 {
786   return colvarbias_restraint::get_state_params() +
787     colvarbias_restraint_moving::get_state_params() +
788     colvarbias_restraint_centers_moving::get_state_params() +
789     colvarbias_restraint_k_moving::get_state_params();
790 }
791 
792 
set_state_params(std::string const & conf)793 int colvarbias_restraint_harmonic::set_state_params(std::string const &conf)
794 {
795   int error_code = COLVARS_OK;
796   error_code |= colvarbias_restraint::set_state_params(conf);
797   error_code |= colvarbias_restraint_moving::set_state_params(conf);
798   error_code |= colvarbias_restraint_centers_moving::set_state_params(conf);
799   error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
800   return error_code;
801 }
802 
803 
write_state_data(std::ostream & os)804 std::ostream & colvarbias_restraint_harmonic::write_state_data(std::ostream &os)
805 {
806   return colvarbias_ti::write_state_data(os);
807 }
808 
809 
read_state_data(std::istream & is)810 std::istream & colvarbias_restraint_harmonic::read_state_data(std::istream &is)
811 {
812   return colvarbias_ti::read_state_data(is);
813 }
814 
815 
write_traj_label(std::ostream & os)816 std::ostream & colvarbias_restraint_harmonic::write_traj_label(std::ostream &os)
817 {
818   colvarbias_restraint::write_traj_label(os);
819   colvarbias_restraint_centers_moving::write_traj_label(os);
820   colvarbias_restraint_k_moving::write_traj_label(os);
821   return os;
822 }
823 
824 
write_traj(std::ostream & os)825 std::ostream & colvarbias_restraint_harmonic::write_traj(std::ostream &os)
826 {
827   colvarbias_restraint::write_traj(os);
828   colvarbias_restraint_centers_moving::write_traj(os);
829   colvarbias_restraint_k_moving::write_traj(os);
830   return os;
831 }
832 
833 
change_configuration(std::string const & conf)834 int colvarbias_restraint_harmonic::change_configuration(std::string const &conf)
835 {
836   return colvarbias_restraint_centers::change_configuration(conf) |
837     colvarbias_restraint_k::change_configuration(conf);
838 }
839 
840 
energy_difference(std::string const & conf)841 cvm::real colvarbias_restraint_harmonic::energy_difference(std::string const &conf)
842 {
843   cvm::real const old_bias_energy = bias_energy;
844   cvm::real const old_force_k = force_k;
845   std::vector<colvarvalue> const old_centers = colvar_centers;
846 
847   change_configuration(conf);
848   update();
849 
850   cvm::real const result = (bias_energy - old_bias_energy);
851 
852   bias_energy = old_bias_energy;
853   force_k = old_force_k;
854   colvar_centers = old_centers;
855 
856   return result;
857 }
858 
859 
860 
colvarbias_restraint_harmonic_walls(char const * key)861 colvarbias_restraint_harmonic_walls::colvarbias_restraint_harmonic_walls(char const *key)
862   : colvarbias(key),
863     colvarbias_ti(key),
864     colvarbias_restraint(key),
865     colvarbias_restraint_k(key),
866     colvarbias_restraint_moving(key),
867     colvarbias_restraint_k_moving(key)
868 {
869   lower_wall_k = -1.0;
870   upper_wall_k = -1.0;
871   // This bias implements the bias_actual_colvars feature (most others do not)
872   provide(f_cvb_bypass_ext_lagrangian);
873   set_enabled(f_cvb_bypass_ext_lagrangian); // Defaults to enabled
874 }
875 
876 
init(std::string const & conf)877 int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
878 {
879   colvarbias_restraint::init(conf);
880   colvarbias_restraint_moving::init(conf);
881   colvarbias_restraint_k_moving::init(conf);
882 
883   enable(f_cvb_scalar_variables);
884 
885   size_t i;
886 
887   bool b_null_lower_walls = false;
888   if (lower_walls.size() == 0) {
889     b_null_lower_walls = true;
890     lower_walls.resize(num_variables());
891     for (i = 0; i < num_variables(); i++) {
892       lower_walls[i].type(variables(i)->value());
893       lower_walls[i].reset();
894     }
895   }
896   if (!get_keyval(conf, "lowerWalls", lower_walls, lower_walls) &&
897       b_null_lower_walls) {
898     cvm::log("Lower walls were not provided.\n");
899     lower_walls.clear();
900   }
901 
902   bool b_null_upper_walls = false;
903   if (upper_walls.size() == 0) {
904     b_null_upper_walls = true;
905     upper_walls.resize(num_variables());
906     for (i = 0; i < num_variables(); i++) {
907       upper_walls[i].type(variables(i)->value());
908       upper_walls[i].reset();
909     }
910   }
911   if (!get_keyval(conf, "upperWalls", upper_walls, upper_walls) &&
912       b_null_upper_walls) {
913     cvm::log("Upper walls were not provided.\n");
914     upper_walls.clear();
915   }
916 
917   if ((lower_walls.size() == 0) && (upper_walls.size() == 0)) {
918     return cvm::error("Error: no walls provided.\n", INPUT_ERROR);
919   }
920 
921   if (lower_walls.size() > 0) {
922     get_keyval(conf, "lowerWallConstant", lower_wall_k,
923                (lower_wall_k > 0.0) ? lower_wall_k : force_k);
924   }
925   if (upper_walls.size() > 0) {
926     get_keyval(conf, "upperWallConstant", upper_wall_k,
927                (upper_wall_k > 0.0) ? upper_wall_k : force_k);
928   }
929 
930   if ((lower_walls.size() == 0) || (upper_walls.size() == 0)) {
931     for (i = 0; i < num_variables(); i++) {
932       if (variables(i)->is_enabled(f_cv_periodic)) {
933         return cvm::error("Error: at least one variable is periodic, "
934                           "both walls must be provided.\n", INPUT_ERROR);
935       }
936     }
937   }
938 
939   if ((lower_walls.size() > 0) && (upper_walls.size() > 0)) {
940     for (i = 0; i < num_variables(); i++) {
941       if (lower_walls[i] >= upper_walls[i]) {
942         return cvm::error("Error: one upper wall, "+
943                           cvm::to_str(upper_walls[i])+
944                           ", is not higher than the lower wall, "+
945                           cvm::to_str(lower_walls[i])+".\n",
946                           INPUT_ERROR);
947       }
948       if (variables(i)->dist2(lower_walls[i], upper_walls[i]) < 1.0e-12) {
949         return cvm::error("Error: lower wall and upper wall are equal "
950                           "in the domain of the variable \""+
951                           variables(i)->name+"\".\n", INPUT_ERROR);
952       }
953     }
954     if (lower_wall_k * upper_wall_k == 0.0) {
955       cvm::error("Error: lowerWallConstant and upperWallConstant, "
956                  "when defined, must both be positive.\n",
957                  INPUT_ERROR);
958       return INPUT_ERROR;
959     }
960     force_k = cvm::sqrt(lower_wall_k * upper_wall_k);
961     // transform the two constants to relative values using gemetric mean as ref
962     // to preserve force_k if provided as single parameter
963     // (allow changing both via force_k)
964     lower_wall_k /= force_k;
965     upper_wall_k /= force_k;
966   } else {
967     // If only one wall is defined, need to rescale as well
968     if (lower_walls.size() > 0) {
969       force_k = lower_wall_k;
970       lower_wall_k = 1.0;
971     }
972     if (upper_walls.size() > 0) {
973       force_k = upper_wall_k;
974       upper_wall_k = 1.0;
975     }
976   }
977 
978   // Initialize starting value of the force constant (in case it's changing)
979   starting_force_k = force_k;
980 
981   if (lower_walls.size() > 0) {
982     for (i = 0; i < num_variables(); i++) {
983       cvm::real const w = variables(i)->width;
984       cvm::log("The lower wall force constant for colvar \""+
985                variables(i)->name+"\" will be rescaled to "+
986                cvm::to_str(lower_wall_k * force_k / (w*w))+
987                " according to the specified width ("+cvm::to_str(w)+").\n");
988     }
989   }
990 
991   if (upper_walls.size() > 0) {
992     for (i = 0; i < num_variables(); i++) {
993       cvm::real const w = variables(i)->width;
994       cvm::log("The upper wall force constant for colvar \""+
995                variables(i)->name+"\" will be rescaled to "+
996                cvm::to_str(upper_wall_k * force_k / (w*w))+
997                " according to the specified width ("+cvm::to_str(w)+").\n");
998     }
999   }
1000 
1001   return COLVARS_OK;
1002 }
1003 
1004 
update()1005 int colvarbias_restraint_harmonic_walls::update()
1006 {
1007   int error_code = COLVARS_OK;
1008 
1009   error_code |= colvarbias_ti::update();
1010 
1011   error_code |= colvarbias_restraint_k_moving::update();
1012 
1013   error_code |= colvarbias_restraint::update();
1014 
1015   error_code |= colvarbias_restraint_k_moving::update_acc_work();
1016 
1017   return error_code;
1018 }
1019 
1020 
colvar_distance(size_t i) const1021 cvm::real colvarbias_restraint_harmonic_walls::colvar_distance(size_t i) const
1022 {
1023   colvar *cv = variables(i);
1024 
1025   colvarvalue const &cvv = is_enabled(f_cvb_bypass_ext_lagrangian) ?
1026     variables(i)->actual_value() :
1027     variables(i)->value();
1028 
1029   // For a periodic colvar, both walls may be applicable at the same time
1030   // in which case we pick the closer one
1031 
1032   if (cv->is_enabled(f_cv_periodic)) {
1033     cvm::real const lower_wall_dist2 = cv->dist2(cvv, lower_walls[i]);
1034     cvm::real const upper_wall_dist2 = cv->dist2(cvv, upper_walls[i]);
1035     if (lower_wall_dist2 < upper_wall_dist2) {
1036       cvm::real const grad = cv->dist2_lgrad(cvv, lower_walls[i]);
1037       if (grad < 0.0) { return 0.5 * grad; }
1038     } else {
1039       cvm::real const grad = cv->dist2_lgrad(cvv, upper_walls[i]);
1040       if (grad > 0.0) { return 0.5 * grad; }
1041     }
1042     return 0.0;
1043   }
1044 
1045   if (lower_walls.size() > 0) {
1046     cvm::real const grad = cv->dist2_lgrad(cvv, lower_walls[i]);
1047     if (grad < 0.0) { return 0.5 * grad; }
1048   }
1049   if (upper_walls.size() > 0) {
1050     cvm::real const grad = cv->dist2_lgrad(cvv, upper_walls[i]);
1051     if (grad > 0.0) { return 0.5 * grad; }
1052   }
1053   return 0.0;
1054 }
1055 
1056 
restraint_potential(size_t i) const1057 cvm::real colvarbias_restraint_harmonic_walls::restraint_potential(size_t i) const
1058 {
1059   cvm::real const dist = colvar_distance(i);
1060   cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
1061   return 0.5 * force_k * scale / (variables(i)->width * variables(i)->width) *
1062     dist * dist;
1063 }
1064 
1065 
restraint_force(size_t i) const1066 colvarvalue const colvarbias_restraint_harmonic_walls::restraint_force(size_t i) const
1067 {
1068   cvm::real const dist = colvar_distance(i);
1069   cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
1070   return - force_k * scale / (variables(i)->width * variables(i)->width) * dist;
1071 }
1072 
1073 
d_restraint_potential_dk(size_t i) const1074 cvm::real colvarbias_restraint_harmonic_walls::d_restraint_potential_dk(size_t i) const
1075 {
1076   cvm::real const dist = colvar_distance(i);
1077   cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
1078   return 0.5 * scale / (variables(i)->width * variables(i)->width) *
1079     dist * dist;
1080 }
1081 
1082 
get_state_params() const1083 std::string const colvarbias_restraint_harmonic_walls::get_state_params() const
1084 {
1085   return colvarbias_restraint::get_state_params() +
1086     colvarbias_restraint_moving::get_state_params() +
1087     colvarbias_restraint_k_moving::get_state_params();
1088 }
1089 
1090 
set_state_params(std::string const & conf)1091 int colvarbias_restraint_harmonic_walls::set_state_params(std::string const &conf)
1092 {
1093   int error_code = COLVARS_OK;
1094   error_code |= colvarbias_restraint::set_state_params(conf);
1095   error_code |= colvarbias_restraint_moving::set_state_params(conf);
1096   error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
1097   return error_code;
1098 }
1099 
1100 
write_state_data(std::ostream & os)1101 std::ostream & colvarbias_restraint_harmonic_walls::write_state_data(std::ostream &os)
1102 {
1103   return colvarbias_ti::write_state_data(os);
1104 }
1105 
1106 
read_state_data(std::istream & is)1107 std::istream & colvarbias_restraint_harmonic_walls::read_state_data(std::istream &is)
1108 {
1109   return colvarbias_ti::read_state_data(is);
1110 }
1111 
1112 
write_traj_label(std::ostream & os)1113 std::ostream & colvarbias_restraint_harmonic_walls::write_traj_label(std::ostream &os)
1114 {
1115   colvarbias_restraint::write_traj_label(os);
1116   colvarbias_restraint_k_moving::write_traj_label(os);
1117   return os;
1118 }
1119 
1120 
write_traj(std::ostream & os)1121 std::ostream & colvarbias_restraint_harmonic_walls::write_traj(std::ostream &os)
1122 {
1123   colvarbias_restraint::write_traj(os);
1124   colvarbias_restraint_k_moving::write_traj(os);
1125   return os;
1126 }
1127 
1128 
1129 
colvarbias_restraint_linear(char const * key)1130 colvarbias_restraint_linear::colvarbias_restraint_linear(char const *key)
1131   : colvarbias(key),
1132     colvarbias_ti(key),
1133     colvarbias_restraint(key),
1134     colvarbias_restraint_centers(key),
1135     colvarbias_restraint_moving(key),
1136     colvarbias_restraint_k(key),
1137     colvarbias_restraint_centers_moving(key),
1138     colvarbias_restraint_k_moving(key)
1139 {
1140   check_positive_k = false;
1141 }
1142 
1143 
init(std::string const & conf)1144 int colvarbias_restraint_linear::init(std::string const &conf)
1145 {
1146   colvarbias_restraint::init(conf);
1147   colvarbias_restraint_moving::init(conf);
1148   colvarbias_restraint_centers_moving::init(conf);
1149   colvarbias_restraint_k_moving::init(conf);
1150 
1151   for (size_t i = 0; i < num_variables(); i++) {
1152     if (variables(i)->is_enabled(f_cv_periodic)) {
1153       cvm::error("Error: linear biases cannot be applied to periodic variables.\n",
1154                  INPUT_ERROR);
1155       return INPUT_ERROR;
1156     }
1157     cvm::real const w = variables(i)->width;
1158     cvm::log("The force constant for colvar \""+variables(i)->name+
1159              "\" will be rescaled to "+
1160              cvm::to_str(force_k / w)+
1161              " according to the specified width ("+cvm::to_str(w)+").\n");
1162   }
1163 
1164   return COLVARS_OK;
1165 }
1166 
1167 
update()1168 int colvarbias_restraint_linear::update()
1169 {
1170   int error_code = COLVARS_OK;
1171 
1172   // update the TI estimator (if defined)
1173   error_code |= colvarbias_ti::update();
1174 
1175   // update parameters (centers or force constant)
1176   error_code |= colvarbias_restraint_centers_moving::update();
1177   error_code |= colvarbias_restraint_k_moving::update();
1178 
1179   // update restraint energy and forces
1180   error_code |= colvarbias_restraint::update();
1181 
1182   // update accumulated work using the current forces
1183   error_code |= colvarbias_restraint_centers_moving::update_acc_work();
1184   error_code |= colvarbias_restraint_k_moving::update_acc_work();
1185 
1186   return error_code;
1187 }
1188 
1189 
change_configuration(std::string const & conf)1190 int colvarbias_restraint_linear::change_configuration(std::string const &conf)
1191 {
1192   // Only makes sense to change the force constant
1193   return colvarbias_restraint_k::change_configuration(conf);
1194 }
1195 
1196 
energy_difference(std::string const & conf)1197 cvm::real colvarbias_restraint_linear::energy_difference(std::string const &conf)
1198 {
1199   cvm::real const old_bias_energy = bias_energy;
1200   cvm::real const old_force_k = force_k;
1201 
1202   change_configuration(conf);
1203   update();
1204 
1205   cvm::real const result = (bias_energy - old_bias_energy);
1206 
1207   bias_energy = old_bias_energy;
1208   force_k = old_force_k;
1209 
1210   return result;
1211 }
1212 
1213 
restraint_potential(size_t i) const1214 cvm::real colvarbias_restraint_linear::restraint_potential(size_t i) const
1215 {
1216   return force_k / variables(i)->width * (variables(i)->value() -
1217                                           colvar_centers[i]).sum();
1218 }
1219 
1220 
restraint_force(size_t i) const1221 colvarvalue const colvarbias_restraint_linear::restraint_force(size_t i) const
1222 {
1223   colvarvalue dummy(variables(i)->value());
1224   dummy.set_ones();
1225   return -1.0 * force_k / variables(i)->width * dummy;
1226 }
1227 
1228 
d_restraint_potential_dk(size_t i) const1229 cvm::real colvarbias_restraint_linear::d_restraint_potential_dk(size_t i) const
1230 {
1231   return 1.0 / variables(i)->width * (variables(i)->value() -
1232                                       colvar_centers[i]).sum();
1233 }
1234 
1235 
get_state_params() const1236 std::string const colvarbias_restraint_linear::get_state_params() const
1237 {
1238   return colvarbias_restraint::get_state_params() +
1239     colvarbias_restraint_moving::get_state_params() +
1240     colvarbias_restraint_centers_moving::get_state_params() +
1241     colvarbias_restraint_k_moving::get_state_params();
1242 }
1243 
1244 
set_state_params(std::string const & conf)1245 int colvarbias_restraint_linear::set_state_params(std::string const &conf)
1246 {
1247   int error_code = COLVARS_OK;
1248   error_code |= colvarbias_restraint::set_state_params(conf);
1249   error_code |= colvarbias_restraint_moving::set_state_params(conf);
1250   error_code |= colvarbias_restraint_centers_moving::set_state_params(conf);
1251   error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
1252   return error_code;
1253 }
1254 
1255 
write_state_data(std::ostream & os)1256 std::ostream & colvarbias_restraint_linear::write_state_data(std::ostream &os)
1257 {
1258   return colvarbias_ti::write_state_data(os);
1259 }
1260 
1261 
read_state_data(std::istream & is)1262 std::istream & colvarbias_restraint_linear::read_state_data(std::istream &is)
1263 {
1264   return colvarbias_ti::read_state_data(is);
1265 }
1266 
1267 
write_traj_label(std::ostream & os)1268 std::ostream & colvarbias_restraint_linear::write_traj_label(std::ostream &os)
1269 {
1270   colvarbias_restraint::write_traj_label(os);
1271   colvarbias_restraint_centers_moving::write_traj_label(os);
1272   colvarbias_restraint_k_moving::write_traj_label(os);
1273   return os;
1274 }
1275 
1276 
write_traj(std::ostream & os)1277 std::ostream & colvarbias_restraint_linear::write_traj(std::ostream &os)
1278 {
1279   colvarbias_restraint::write_traj(os);
1280   colvarbias_restraint_centers_moving::write_traj(os);
1281   colvarbias_restraint_k_moving::write_traj(os);
1282   return os;
1283 }
1284 
1285 
1286 
colvarbias_restraint_histogram(char const * key)1287 colvarbias_restraint_histogram::colvarbias_restraint_histogram(char const *key)
1288   : colvarbias(key)
1289 {
1290   lower_boundary = 0.0;
1291   upper_boundary = 0.0;
1292   width = 0.0;
1293   gaussian_width = 0.0;
1294 }
1295 
1296 
init(std::string const & conf)1297 int colvarbias_restraint_histogram::init(std::string const &conf)
1298 {
1299   colvarbias::init(conf);
1300   enable(f_cvb_apply_force);
1301 
1302   get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary);
1303   get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary);
1304   get_keyval(conf, "width", width, width);
1305 
1306   if (width <= 0.0) {
1307     cvm::error("Error: \"width\" must be positive.\n", INPUT_ERROR);
1308   }
1309 
1310   get_keyval(conf, "gaussianWidth", gaussian_width, 2.0 * width, colvarparse::parse_silent);
1311   get_keyval(conf, "gaussianSigma", gaussian_width, 2.0 * width);
1312 
1313   if (lower_boundary >= upper_boundary) {
1314     cvm::error("Error: the upper boundary, "+
1315                cvm::to_str(upper_boundary)+
1316                ", is not higher than the lower boundary, "+
1317                cvm::to_str(lower_boundary)+".\n",
1318                INPUT_ERROR);
1319   }
1320 
1321   cvm::real const nbins = (upper_boundary - lower_boundary) / width;
1322   int const nbins_round = (int)(nbins);
1323 
1324   if (cvm::fabs(nbins - cvm::real(nbins_round)) > 1.0E-10) {
1325     cvm::log("Warning: grid interval ("+
1326              cvm::to_str(lower_boundary, cvm::cv_width, cvm::cv_prec)+" - "+
1327              cvm::to_str(upper_boundary, cvm::cv_width, cvm::cv_prec)+
1328              ") is not commensurate to its bin width ("+
1329              cvm::to_str(width, cvm::cv_width, cvm::cv_prec)+").\n");
1330   }
1331 
1332   p.resize(nbins_round);
1333   ref_p.resize(nbins_round);
1334   p_diff.resize(nbins_round);
1335 
1336   bool const inline_ref_p =
1337     get_keyval(conf, "refHistogram", ref_p.data_array(), ref_p.data_array());
1338   std::string ref_p_file;
1339   get_keyval(conf, "refHistogramFile", ref_p_file, std::string(""));
1340   if (ref_p_file.size()) {
1341     if (inline_ref_p) {
1342       cvm::error("Error: cannot specify both refHistogram and refHistogramFile at the same time.\n",
1343                  INPUT_ERROR);
1344     } else {
1345       std::ifstream is(ref_p_file.c_str());
1346       std::string data_s = "";
1347       std::string line;
1348       while (getline_nocomments(is, line)) {
1349         data_s.append(line+"\n");
1350       }
1351       if (data_s.size() == 0) {
1352         cvm::error("Error: file \""+ref_p_file+"\" empty or unreadable.\n", FILE_ERROR);
1353       }
1354       is.close();
1355       cvm::vector1d<cvm::real> data;
1356       if (data.from_simple_string(data_s) != 0) {
1357         cvm::error("Error: could not read histogram from file \""+ref_p_file+"\".\n");
1358       }
1359       if (data.size() == 2*ref_p.size()) {
1360         // file contains both x and p(x)
1361         size_t i;
1362         for (i = 0; i < ref_p.size(); i++) {
1363           ref_p[i] = data[2*i+1];
1364         }
1365       } else if (data.size() == ref_p.size()) {
1366         ref_p = data;
1367       } else {
1368         cvm::error("Error: file \""+ref_p_file+"\" contains a histogram of different length.\n",
1369                    INPUT_ERROR);
1370       }
1371     }
1372   }
1373   cvm::real const ref_integral = ref_p.sum() * width;
1374   if (cvm::fabs(ref_integral - 1.0) > 1.0e-03) {
1375     cvm::log("Reference distribution not normalized, normalizing to unity.\n");
1376     ref_p /= ref_integral;
1377   }
1378 
1379   get_keyval(conf, "writeHistogram", b_write_histogram, false);
1380   get_keyval(conf, "forceConstant", force_k, 1.0);
1381 
1382   return COLVARS_OK;
1383 }
1384 
1385 
~colvarbias_restraint_histogram()1386 colvarbias_restraint_histogram::~colvarbias_restraint_histogram()
1387 {
1388   p.clear();
1389   ref_p.clear();
1390   p_diff.clear();
1391 }
1392 
1393 
update()1394 int colvarbias_restraint_histogram::update()
1395 {
1396   if (cvm::debug())
1397     cvm::log("Updating the histogram restraint bias \""+this->name+"\".\n");
1398 
1399   size_t vector_size = 0;
1400   size_t icv;
1401   for (icv = 0; icv < num_variables(); icv++) {
1402     vector_size += variables(icv)->value().size();
1403   }
1404 
1405   cvm::real const norm = 1.0/(cvm::sqrt(2.0*PI)*gaussian_width*vector_size);
1406 
1407   // calculate the histogram
1408   p.reset();
1409   for (icv = 0; icv < num_variables(); icv++) {
1410     colvarvalue const &cv = variables(icv)->value();
1411     if (cv.type() == colvarvalue::type_scalar) {
1412       cvm::real const cv_value = cv.real_value;
1413       size_t igrid;
1414       for (igrid = 0; igrid < p.size(); igrid++) {
1415         cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
1416         p[igrid] += norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
1417                                     (2.0 * gaussian_width * gaussian_width));
1418       }
1419     } else if (cv.type() == colvarvalue::type_vector) {
1420       size_t idim;
1421       for (idim = 0; idim < cv.vector1d_value.size(); idim++) {
1422         cvm::real const cv_value = cv.vector1d_value[idim];
1423         size_t igrid;
1424         for (igrid = 0; igrid < p.size(); igrid++) {
1425           cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
1426           p[igrid] += norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
1427                                       (2.0 * gaussian_width * gaussian_width));
1428         }
1429       }
1430     } else {
1431       cvm::error("Error: unsupported type for variable "+variables(icv)->name+".\n",
1432                  COLVARS_NOT_IMPLEMENTED);
1433       return COLVARS_NOT_IMPLEMENTED;
1434     }
1435   }
1436 
1437   cvm::real const force_k_cv = force_k * vector_size;
1438 
1439   // calculate the difference between current and reference
1440   p_diff = p - ref_p;
1441   bias_energy = 0.5 * force_k_cv * p_diff * p_diff;
1442 
1443   // calculate the forces
1444   for (icv = 0; icv < num_variables(); icv++) {
1445     colvarvalue const &cv = variables(icv)->value();
1446     colvarvalue &cv_force = colvar_forces[icv];
1447     cv_force.type(cv);
1448     cv_force.reset();
1449 
1450     if (cv.type() == colvarvalue::type_scalar) {
1451       cvm::real const cv_value = cv.real_value;
1452       cvm::real &force = cv_force.real_value;
1453       size_t igrid;
1454       for (igrid = 0; igrid < p.size(); igrid++) {
1455         cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
1456         force += force_k_cv * p_diff[igrid] *
1457           norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
1458                           (2.0 * gaussian_width * gaussian_width)) *
1459           (-1.0 * (x_grid - cv_value) / (gaussian_width * gaussian_width));
1460       }
1461     } else if (cv.type() == colvarvalue::type_vector) {
1462       size_t idim;
1463       for (idim = 0; idim < cv.vector1d_value.size(); idim++) {
1464         cvm::real const cv_value = cv.vector1d_value[idim];
1465         cvm::real &force = cv_force.vector1d_value[idim];
1466         size_t igrid;
1467         for (igrid = 0; igrid < p.size(); igrid++) {
1468           cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
1469           force += force_k_cv * p_diff[igrid] *
1470             norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
1471                             (2.0 * gaussian_width * gaussian_width)) *
1472             (-1.0 * (x_grid - cv_value) / (gaussian_width * gaussian_width));
1473         }
1474       }
1475     } else {
1476       // TODO
1477     }
1478   }
1479 
1480   return COLVARS_OK;
1481 }
1482 
1483 
write_output_files()1484 int colvarbias_restraint_histogram::write_output_files()
1485 {
1486   if (b_write_histogram) {
1487     std::string file_name(cvm::output_prefix()+"."+this->name+".hist.dat");
1488     std::ostream *os = cvm::proxy->output_stream(file_name);
1489     *os << "# " << cvm::wrap_string(variables(0)->name, cvm::cv_width)
1490         << "  " << "p(" << cvm::wrap_string(variables(0)->name, cvm::cv_width-3)
1491         << ")\n";
1492 
1493     os->setf(std::ios::fixed, std::ios::floatfield);
1494 
1495     size_t igrid;
1496     for (igrid = 0; igrid < p.size(); igrid++) {
1497       cvm::real const x_grid = (lower_boundary + (igrid+1)*width);
1498       *os << "  "
1499           << std::setprecision(cvm::cv_prec)
1500           << std::setw(cvm::cv_width)
1501           << x_grid
1502           << "  "
1503           << std::setprecision(cvm::cv_prec)
1504           << std::setw(cvm::cv_width)
1505           << p[igrid] << "\n";
1506     }
1507     cvm::proxy->close_output_stream(file_name);
1508   }
1509   return COLVARS_OK;
1510 }
1511 
1512 
write_traj_label(std::ostream & os)1513 std::ostream & colvarbias_restraint_histogram::write_traj_label(std::ostream &os)
1514 {
1515   os << " ";
1516   if (b_output_energy) {
1517     os << " E_"
1518        << cvm::wrap_string(this->name, cvm::en_width-2);
1519   }
1520   return os;
1521 }
1522 
1523 
write_traj(std::ostream & os)1524 std::ostream & colvarbias_restraint_histogram::write_traj(std::ostream &os)
1525 {
1526   os << " ";
1527   if (b_output_energy) {
1528     os << " "
1529        << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
1530        << bias_energy;
1531   }
1532   return os;
1533 }
1534