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 <algorithm>
11
12 #include "colvarmodule.h"
13 #include "colvarvalue.h"
14 #include "colvar.h"
15 #include "colvarcomp.h"
16
17
18
cvc()19 colvar::cvc::cvc()
20 {
21 description = "uninitialized colvar component";
22 b_try_scalable = true;
23 sup_coeff = 1.0;
24 sup_np = 1;
25 period = 0.0;
26 wrap_center = 0.0;
27 width = 0.0;
28 init_dependencies();
29 }
30
31
cvc(std::string const & conf)32 colvar::cvc::cvc(std::string const &conf)
33 {
34 description = "uninitialized colvar component";
35 b_try_scalable = true;
36 sup_coeff = 1.0;
37 sup_np = 1;
38 period = 0.0;
39 wrap_center = 0.0;
40 width = 0.0;
41 init_dependencies();
42 init(conf);
43 }
44
45
init(std::string const & conf)46 int colvar::cvc::init(std::string const &conf)
47 {
48 if (cvm::debug())
49 cvm::log("Initializing cvc base object.\n");
50
51 std::string const old_name(name);
52
53 if (name.size() > 0) {
54 cvm::log("Updating configuration for component \""+name+"\"\n");
55 }
56
57 if (get_keyval(conf, "name", name, name)) {
58 if (name.size() > 0) {
59 description = "cvc \"" + name + "\" of type " + function_type;
60 } else {
61 description = "unnamed cvc";
62 }
63 if ((name != old_name) && (old_name.size() > 0)) {
64 cvm::error("Error: cannot rename component \""+old_name+
65 "\" after initialization (new name = \""+name+"\")",
66 INPUT_ERROR);
67 name = old_name;
68 }
69 }
70
71 get_keyval(conf, "componentCoeff", sup_coeff, sup_coeff);
72 get_keyval(conf, "componentExp", sup_np, sup_np);
73 // TODO these could be condensed into get_keyval()
74 register_param("componentCoeff", reinterpret_cast<void *>(&sup_coeff));
75 register_param("componentExp", reinterpret_cast<void *>(&sup_np));
76
77 get_keyval(conf, "period", period, period);
78 get_keyval(conf, "wrapAround", wrap_center, wrap_center);
79 // TODO when init() is called after all constructors, check periodic flag
80 register_param("period", reinterpret_cast<void *>(&period));
81 register_param("wrapAround", reinterpret_cast<void *>(&wrap_center));
82
83 get_keyval_feature(this, conf, "debugGradients",
84 f_cvc_debug_gradient, false, parse_silent);
85
86 bool b_no_PBC = !is_enabled(f_cvc_pbc_minimum_image); // Enabled by default
87 get_keyval(conf, "forceNoPBC", b_no_PBC, b_no_PBC);
88 if (b_no_PBC) {
89 disable(f_cvc_pbc_minimum_image);
90 } else {
91 enable(f_cvc_pbc_minimum_image);
92 }
93
94 // Attempt scalable calculations when in parallel? (By default yes, if available)
95 get_keyval(conf, "scalable", b_try_scalable, b_try_scalable);
96
97 if (cvm::debug())
98 cvm::log("Done initializing cvc base object.\n");
99
100 return cvm::get_error();
101 }
102
103
init_total_force_params(std::string const & conf)104 int colvar::cvc::init_total_force_params(std::string const &conf)
105 {
106 if (cvm::get_error()) return COLVARS_ERROR;
107
108 if (get_keyval_feature(this, conf, "oneSiteSystemForce",
109 f_cvc_one_site_total_force, is_enabled(f_cvc_one_site_total_force))) {
110 cvm::log("Warning: keyword \"oneSiteSystemForce\" is deprecated: "
111 "please use \"oneSiteTotalForce\" instead.\n");
112 }
113 if (get_keyval_feature(this, conf, "oneSiteTotalForce",
114 f_cvc_one_site_total_force, is_enabled(f_cvc_one_site_total_force))) {
115 cvm::log("Computing total force on group 1 only\n");
116 }
117
118 if (! is_enabled(f_cvc_one_site_total_force)) {
119 // check whether any of the other atom groups is dummy
120 std::vector<cvm::atom_group *>::iterator agi = atom_groups.begin();
121 agi++;
122 for ( ; agi != atom_groups.end(); agi++) {
123 if ((*agi)->b_dummy) {
124 provide(f_cvc_inv_gradient, false);
125 provide(f_cvc_Jacobian, false);
126 }
127 }
128 }
129
130 return COLVARS_OK;
131 }
132
133
parse_group(std::string const & conf,char const * group_key,bool optional)134 cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
135 char const *group_key,
136 bool optional)
137 {
138 cvm::atom_group *group = NULL;
139 std::string group_conf;
140
141 if (key_lookup(conf, group_key, &group_conf)) {
142 group = new cvm::atom_group(group_key);
143
144 if (b_try_scalable) {
145 if (is_available(f_cvc_scalable_com)
146 && is_enabled(f_cvc_com_based)
147 && !is_enabled(f_cvc_debug_gradient)) {
148 enable(f_cvc_scalable_com);
149 enable(f_cvc_scalable);
150 // The CVC makes the feature available;
151 // the atom group will enable it unless it needs to compute a rotational fit
152 group->provide(f_ag_scalable_com);
153 }
154
155 // TODO check for other types of parallelism here
156 }
157
158 if (group_conf.size() == 0) {
159 cvm::error("Error: atom group \""+group->key+
160 "\" is set, but has no definition.\n",
161 INPUT_ERROR);
162 return group;
163 }
164
165 cvm::increase_depth();
166 if (group->parse(group_conf) == COLVARS_OK) {
167 register_atom_group(group);
168 }
169 group->check_keywords(group_conf, group_key);
170 if (cvm::get_error()) {
171 cvm::error("Error parsing definition for atom group \""+
172 std::string(group_key)+"\".", INPUT_ERROR);
173 }
174 cvm::decrease_depth();
175
176 } else {
177 if (! optional) {
178 cvm::error("Error: definition for atom group \""+
179 std::string(group_key)+"\" not found.\n");
180 }
181 }
182
183 return group;
184 }
185
186
init_dependencies()187 int colvar::cvc::init_dependencies() {
188 size_t i;
189 // Initialize static array once and for all
190 if (features().size() == 0) {
191 for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
192 modify_features().push_back(new feature);
193 }
194
195 init_feature(f_cvc_active, "active", f_type_dynamic);
196 // The dependency below may become useful if we use dynamic atom groups
197 // require_feature_children(f_cvc_active, f_ag_active);
198
199 init_feature(f_cvc_scalar, "scalar", f_type_static);
200
201 init_feature(f_cvc_periodic, "periodic", f_type_static);
202
203 init_feature(f_cvc_width, "defined_width", f_type_static);
204
205 init_feature(f_cvc_lower_boundary, "defined_lower_boundary", f_type_static);
206
207 init_feature(f_cvc_upper_boundary, "defined_upper_boundary", f_type_static);
208
209 init_feature(f_cvc_gradient, "gradient", f_type_dynamic);
210
211 init_feature(f_cvc_explicit_gradient, "explicit_gradient", f_type_static);
212 require_feature_children(f_cvc_explicit_gradient, f_ag_explicit_gradient);
213
214 init_feature(f_cvc_inv_gradient, "inverse_gradient", f_type_dynamic);
215 require_feature_self(f_cvc_inv_gradient, f_cvc_gradient);
216
217 init_feature(f_cvc_debug_gradient, "debug_gradient", f_type_user);
218 require_feature_self(f_cvc_debug_gradient, f_cvc_gradient);
219 require_feature_self(f_cvc_debug_gradient, f_cvc_explicit_gradient);
220
221 init_feature(f_cvc_Jacobian, "Jacobian_derivative", f_type_dynamic);
222 require_feature_self(f_cvc_Jacobian, f_cvc_inv_gradient);
223
224 // Compute total force on first site only to avoid unwanted
225 // coupling to other colvars (see e.g. Ciccotti et al., 2005)
226 init_feature(f_cvc_one_site_total_force, "total_force_from_one_group", f_type_user);
227 require_feature_self(f_cvc_one_site_total_force, f_cvc_com_based);
228
229 init_feature(f_cvc_com_based, "function_of_centers_of_mass", f_type_static);
230
231 init_feature(f_cvc_pbc_minimum_image, "use_minimum-image_with_PBCs", f_type_user);
232
233 init_feature(f_cvc_scalable, "scalable_calculation", f_type_static);
234 require_feature_self(f_cvc_scalable, f_cvc_scalable_com);
235
236 init_feature(f_cvc_scalable_com, "scalable_calculation_of_centers_of_mass", f_type_static);
237 require_feature_self(f_cvc_scalable_com, f_cvc_com_based);
238
239
240 // TODO only enable this when f_ag_scalable can be turned on for a pre-initialized group
241 // require_feature_children(f_cvc_scalable, f_ag_scalable);
242 // require_feature_children(f_cvc_scalable_com, f_ag_scalable_com);
243
244 // check that everything is initialized
245 for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
246 if (is_not_set(i)) {
247 cvm::error("Uninitialized feature " + cvm::to_str(i) + " in " + description);
248 }
249 }
250 }
251
252 // Initialize feature_states for each instance
253 // default as available, not enabled
254 // except dynamic features which default as unavailable
255 feature_states.reserve(f_cvc_ntot);
256 for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
257 bool avail = is_dynamic(i) ? false : true;
258 feature_states.push_back(feature_state(avail, false));
259 }
260
261 // Features that are implemented by all cvcs by default
262 // Each cvc specifies what other features are available
263 feature_states[f_cvc_active].available = true;
264 feature_states[f_cvc_gradient].available = true;
265
266 // CVCs are enabled from the start - get disabled based on flags
267 enable(f_cvc_active);
268 // feature_states[f_cvc_active].enabled = true;
269
270 // Explicit gradients are implemented in mosts CVCs. Exceptions must be specified explicitly.
271 // feature_states[f_cvc_explicit_gradient].enabled = true;
272 enable(f_cvc_explicit_gradient);
273
274 // Use minimum-image distances by default
275 // feature_states[f_cvc_pbc_minimum_image].enabled = true;
276 enable(f_cvc_pbc_minimum_image);
277
278 // Features that are implemented by default if their requirements are
279 feature_states[f_cvc_one_site_total_force].available = true;
280
281 // Features That are implemented only for certain simulation engine configurations
282 feature_states[f_cvc_scalable_com].available = (cvm::proxy->scalable_group_coms() == COLVARS_OK);
283 feature_states[f_cvc_scalable].available = feature_states[f_cvc_scalable_com].available;
284
285 return COLVARS_OK;
286 }
287
288
setup()289 int colvar::cvc::setup()
290 {
291 description = "cvc " + name;
292 return COLVARS_OK;
293 }
294
295
~cvc()296 colvar::cvc::~cvc()
297 {
298 free_children_deps();
299 remove_all_children();
300 for (size_t i = 0; i < atom_groups.size(); i++) {
301 if (atom_groups[i] != NULL) delete atom_groups[i];
302 }
303 }
304
305
init_as_distance()306 void colvar::cvc::init_as_distance()
307 {
308 x.type(colvarvalue::type_scalar);
309 enable(f_cvc_lower_boundary);
310 lower_boundary.type(colvarvalue::type_scalar);
311 lower_boundary.real_value = 0.0;
312 register_param("lowerBoundary", reinterpret_cast<void *>(&lower_boundary));
313 }
314
315
init_as_angle()316 void colvar::cvc::init_as_angle()
317 {
318 x.type(colvarvalue::type_scalar);
319 init_scalar_boundaries(0.0, 180);
320 }
321
322
init_scalar_boundaries(cvm::real lb,cvm::real ub)323 void colvar::cvc::init_scalar_boundaries(cvm::real lb, cvm::real ub)
324 {
325 enable(f_cvc_lower_boundary);
326 lower_boundary.type(colvarvalue::type_scalar);
327 lower_boundary.real_value = lb;
328 enable(f_cvc_upper_boundary);
329 upper_boundary.type(colvarvalue::type_scalar);
330 upper_boundary.real_value = ub;
331 register_param("lowerBoundary", reinterpret_cast<void *>(&lower_boundary));
332 register_param("upperBoundary", reinterpret_cast<void *>(&upper_boundary));
333 }
334
335
register_atom_group(cvm::atom_group * ag)336 void colvar::cvc::register_atom_group(cvm::atom_group *ag)
337 {
338 atom_groups.push_back(ag);
339 add_child(ag);
340 }
341
342
get_param_grad(std::string const & param_name)343 colvarvalue const *colvar::cvc::get_param_grad(std::string const ¶m_name)
344 {
345 colvarvalue const *ptr =
346 reinterpret_cast<colvarvalue const *>(get_param_grad_ptr(param_name));
347 return ptr != NULL ? ptr : NULL;
348 }
349
350
set_param(std::string const & param_name,void const * new_value)351 int colvar::cvc::set_param(std::string const ¶m_name,
352 void const *new_value)
353 {
354 if (param_map.count(param_name) > 0) {
355
356 // TODO When we can use C++11, make this a proper function map
357 if (param_name.compare("componentCoeff") == 0) {
358 sup_coeff = *(reinterpret_cast<cvm::real const *>(new_value));
359 }
360 if (param_name.compare("componentExp") == 0) {
361 sup_np = *(reinterpret_cast<int const *>(new_value));
362 }
363 if (is_enabled(f_cvc_periodic)) {
364 if (param_name.compare("period") == 0) {
365 period = *(reinterpret_cast<cvm::real const *>(new_value));
366 }
367 if (param_name.compare("wrapAround") == 0) {
368 wrap_center = *(reinterpret_cast<cvm::real const *>(new_value));
369 }
370 }
371 }
372
373 return colvarparams::set_param(param_name, new_value);
374 }
375
376
read_data()377 void colvar::cvc::read_data()
378 {
379 size_t ig;
380 for (ig = 0; ig < atom_groups.size(); ig++) {
381 cvm::atom_group &atoms = *(atom_groups[ig]);
382 atoms.reset_atoms_data();
383 atoms.read_positions();
384 atoms.calc_required_properties();
385 // each atom group will take care of its own fitting_group, if defined
386 }
387
388 //// Don't try to get atom velocities, as no back-end currently implements it
389 // if (tasks[task_output_velocity] && !tasks[task_fdiff_velocity]) {
390 // for (i = 0; i < cvcs.size(); i++) {
391 // for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
392 // cvcs[i]->atom_groups[ig]->read_velocities();
393 // }
394 // }
395 // }
396 }
397
398
get_atom_lists()399 std::vector<std::vector<int> > colvar::cvc::get_atom_lists()
400 {
401 std::vector<std::vector<int> > lists;
402
403 std::vector<cvm::atom_group *>::iterator agi = atom_groups.begin();
404 for ( ; agi != atom_groups.end(); ++agi) {
405 (*agi)->create_sorted_ids();
406 lists.push_back((*agi)->sorted_ids());
407 if ((*agi)->is_enabled(f_ag_fitting_group) && (*agi)->is_enabled(f_ag_fit_gradients)) {
408 cvm::atom_group &fg = *((*agi)->fitting_group);
409 fg.create_sorted_ids();
410 lists.push_back(fg.sorted_ids());
411 }
412 }
413 return lists;
414 }
415
416
collect_gradients(std::vector<int> const & atom_ids,std::vector<cvm::rvector> & atomic_gradients)417 void colvar::cvc::collect_gradients(std::vector<int> const &atom_ids, std::vector<cvm::rvector> &atomic_gradients)
418 {
419 // Coefficient: d(a * x^n) = a * n * x^(n-1) * dx
420 cvm::real coeff = sup_coeff * cvm::real(sup_np) *
421 cvm::integer_power(value().real_value, sup_np-1);
422
423 for (size_t j = 0; j < atom_groups.size(); j++) {
424
425 cvm::atom_group &ag = *(atom_groups[j]);
426
427 // If necessary, apply inverse rotation to get atomic
428 // gradient in the laboratory frame
429 if (ag.is_enabled(f_ag_rotate)) {
430 cvm::rotation const rot_inv = ag.rot.inverse();
431
432 for (size_t k = 0; k < ag.size(); k++) {
433 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
434 ag[k].id) - atom_ids.begin();
435 atomic_gradients[a] += coeff * rot_inv.rotate(ag[k].grad);
436 }
437
438 } else {
439
440 for (size_t k = 0; k < ag.size(); k++) {
441 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
442 ag[k].id) - atom_ids.begin();
443 atomic_gradients[a] += coeff * ag[k].grad;
444 }
445 }
446 if (ag.is_enabled(f_ag_fitting_group) && ag.is_enabled(f_ag_fit_gradients)) {
447 cvm::atom_group const &fg = *(ag.fitting_group);
448 for (size_t k = 0; k < fg.size(); k++) {
449 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
450 fg[k].id) - atom_ids.begin();
451 // fit gradients are in the unrotated (simulation) frame
452 atomic_gradients[a] += coeff * fg.fit_gradients[k];
453 }
454 }
455 }
456 }
457
458
calc_force_invgrads()459 void colvar::cvc::calc_force_invgrads()
460 {
461 cvm::error("Error: calculation of inverse gradients is not implemented "
462 "for colvar components of type \""+function_type+"\".\n",
463 COLVARS_NOT_IMPLEMENTED);
464 }
465
466
calc_Jacobian_derivative()467 void colvar::cvc::calc_Jacobian_derivative()
468 {
469 cvm::error("Error: calculation of inverse gradients is not implemented "
470 "for colvar components of type \""+function_type+"\".\n",
471 COLVARS_NOT_IMPLEMENTED);
472 }
473
474
calc_fit_gradients()475 void colvar::cvc::calc_fit_gradients()
476 {
477 for (size_t ig = 0; ig < atom_groups.size(); ig++) {
478 atom_groups[ig]->calc_fit_gradients();
479 }
480 }
481
482
debug_gradients()483 void colvar::cvc::debug_gradients()
484 {
485 // this function should work for any scalar cvc:
486 // the only difference will be the name of the atom group (here, "group")
487 // NOTE: this assumes that groups for this cvc are non-overlapping,
488 // since atom coordinates are modified only within the current group
489
490 cvm::log("Debugging gradients for " + description);
491
492 for (size_t ig = 0; ig < atom_groups.size(); ig++) {
493 cvm::atom_group *group = atom_groups[ig];
494 if (group->b_dummy) continue;
495
496 cvm::rotation const rot_0 = group->rot;
497 cvm::rotation const rot_inv = group->rot.inverse();
498
499 cvm::real x_0 = x.real_value;
500 if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0];
501
502 // cvm::log("gradients = "+cvm::to_str (gradients)+"\n");
503
504 cvm::atom_group *group_for_fit = group->fitting_group ? group->fitting_group : group;
505 cvm::atom_pos fit_gradient_sum, gradient_sum;
506
507 // print the values of the fit gradients
508 if (group->is_enabled(f_ag_center) || group->is_enabled(f_ag_rotate)) {
509 if (group->is_enabled(f_ag_fit_gradients)) {
510 size_t j;
511
512 // fit_gradients are in the simulation frame: we should print them in the rotated frame
513 cvm::log("Fit gradients:\n");
514 for (j = 0; j < group_for_fit->fit_gradients.size(); j++) {
515 cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) +
516 "[" + cvm::to_str(j) + "] = " +
517 (group->is_enabled(f_ag_rotate) ?
518 cvm::to_str(rot_0.rotate(group_for_fit->fit_gradients[j])) :
519 cvm::to_str(group_for_fit->fit_gradients[j])));
520 }
521 }
522 }
523
524 // debug the gradients
525 for (size_t ia = 0; ia < group->size(); ia++) {
526
527 // tests are best conducted in the unrotated (simulation) frame
528 cvm::rvector const atom_grad = (group->is_enabled(f_ag_rotate) ?
529 rot_inv.rotate((*group)[ia].grad) :
530 (*group)[ia].grad);
531 gradient_sum += atom_grad;
532
533 for (size_t id = 0; id < 3; id++) {
534 // (re)read original positions
535 group->read_positions();
536 // change one coordinate
537 (*group)[ia].pos[id] += cvm::debug_gradients_step_size;
538 group->calc_required_properties();
539 calc_value();
540 cvm::real x_1 = x.real_value;
541 if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_1 = x[0];
542 cvm::log("Atom "+cvm::to_str(ia)+", component "+cvm::to_str(id)+":\n");
543 cvm::log("dx(actual) = "+cvm::to_str(x_1 - x_0,
544 21, 14)+"\n");
545 cvm::real const dx_pred = (group->fit_gradients.size()) ?
546 (cvm::debug_gradients_step_size * (atom_grad[id] + group->fit_gradients[ia][id])) :
547 (cvm::debug_gradients_step_size * atom_grad[id]);
548 cvm::log("dx(interp) = "+cvm::to_str(dx_pred,
549 21, 14)+"\n");
550 cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+
551 cvm::to_str(cvm::fabs(x_1 - x_0 - dx_pred) /
552 cvm::fabs(x_1 - x_0), 12, 5)+"\n");
553 }
554 }
555
556 if ((group->is_enabled(f_ag_fit_gradients)) && (group->fitting_group != NULL)) {
557 cvm::atom_group *ref_group = group->fitting_group;
558 group->read_positions();
559 group->calc_required_properties();
560
561 for (size_t ia = 0; ia < ref_group->size(); ia++) {
562
563 // fit gradients are in the unrotated (simulation) frame
564 cvm::rvector const atom_grad = ref_group->fit_gradients[ia];
565 fit_gradient_sum += atom_grad;
566
567 for (size_t id = 0; id < 3; id++) {
568 // (re)read original positions
569 group->read_positions();
570 ref_group->read_positions();
571 // change one coordinate
572 (*ref_group)[ia].pos[id] += cvm::debug_gradients_step_size;
573 group->calc_required_properties();
574 calc_value();
575
576 cvm::real const x_1 = x.real_value;
577 cvm::log("refPosGroup atom "+cvm::to_str(ia)+", component "+cvm::to_str (id)+":\n");
578 cvm::log("dx(actual) = "+cvm::to_str (x_1 - x_0,
579 21, 14)+"\n");
580
581 cvm::real const dx_pred = cvm::debug_gradients_step_size * atom_grad[id];
582
583 cvm::log("dx(interp) = "+cvm::to_str (dx_pred,
584 21, 14)+"\n");
585 cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+
586 cvm::to_str(cvm::fabs (x_1 - x_0 - dx_pred) /
587 cvm::fabs (x_1 - x_0),
588 12, 5)+
589 ".\n");
590 }
591 }
592 }
593
594 cvm::log("Gradient sum: " + cvm::to_str(gradient_sum) +
595 " Fit gradient sum: " + cvm::to_str(fit_gradient_sum) +
596 " Total " + cvm::to_str(gradient_sum + fit_gradient_sum));
597 }
598 return;
599 }
600
601
dist2(colvarvalue const & x1,colvarvalue const & x2) const602 cvm::real colvar::cvc::dist2(colvarvalue const &x1,
603 colvarvalue const &x2) const
604 {
605 return x1.dist2(x2);
606 }
607
608
dist2_lgrad(colvarvalue const & x1,colvarvalue const & x2) const609 colvarvalue colvar::cvc::dist2_lgrad(colvarvalue const &x1,
610 colvarvalue const &x2) const
611 {
612 return x1.dist2_grad(x2);
613 }
614
615
dist2_rgrad(colvarvalue const & x1,colvarvalue const & x2) const616 colvarvalue colvar::cvc::dist2_rgrad(colvarvalue const &x1,
617 colvarvalue const &x2) const
618 {
619 return x2.dist2_grad(x1);
620 }
621
622
wrap(colvarvalue &) const623 void colvar::cvc::wrap(colvarvalue & /* x_unwrapped */) const
624 {
625 return;
626 }
627
628
629
630 // Static members
631
632 std::vector<colvardeps::feature *> colvar::cvc::cvc_features;
633