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