121
124
std::string numbers_conf = "";
123
126
std::vector<int> atom_indexes;
124
while (key_lookup (group_conf, "atomNumbers", numbers_conf, pos)) {
127
while (key_lookup(group_conf, "atomNumbers", numbers_conf, pos)) {
125
128
if (numbers_conf.size()) {
126
std::istringstream is (numbers_conf);
129
std::istringstream is(numbers_conf);
128
131
while (is >> ia) {
129
atom_indexes.push_back (ia);
132
atom_indexes.push_back(ia);
133
136
if (atom_indexes.size()) {
134
this->reserve (this->size()+atom_indexes.size());
137
this->reserve(this->size()+atom_indexes.size());
135
138
for (size_t i = 0; i < atom_indexes.size(); i++) {
136
this->push_back (cvm::atom (atom_indexes[i]));
139
this->push_back(cvm::atom(atom_indexes[i]));
139
cvm::fatal_error ("Error: no numbers provided for \""
141
if (cvm::get_error()) return COLVARS_ERROR;
143
cvm::error("Error: no numbers provided for \""
144
"atomNumbers\".\n", INPUT_ERROR);
145
return COLVARS_ERROR;
142
148
atom_indexes.clear();
145
151
std::string index_group_name;
146
if (get_keyval (group_conf, "indexGroup", index_group_name)) {
152
if (get_keyval(group_conf, "indexGroup", index_group_name)) {
147
153
// use an index group from the index file read globally
148
154
std::list<std::string>::iterator names_i = cvm::index_group_names.begin();
149
155
std::list<std::vector<int> >::iterator index_groups_i = cvm::index_groups.begin();
150
for ( ; names_i != cvm::index_group_names.end() ; names_i++, index_groups_i++) {
156
for ( ; names_i != cvm::index_group_names.end() ; ++names_i, ++index_groups_i) {
151
157
if (*names_i == index_group_name)
154
160
if (names_i == cvm::index_group_names.end()) {
155
cvm::fatal_error ("Error: could not find index group "+
156
index_group_name+" among those provided by the index file.\n");
161
cvm::error("Error: could not find index group "+
162
index_group_name+" among those provided by the index file.\n",
164
return COLVARS_ERROR;
158
this->reserve (index_groups_i->size());
166
this->reserve(index_groups_i->size());
159
167
for (size_t i = 0; i < index_groups_i->size(); i++) {
160
this->push_back (cvm::atom ((*index_groups_i)[i]));
168
this->push_back(cvm::atom((*index_groups_i)[i]));
170
if (cvm::get_error()) return COLVARS_ERROR;
166
175
std::string range_conf = "";
168
while (key_lookup (group_conf, "atomNumbersRange",
177
while (key_lookup(group_conf, "atomNumbersRange",
169
178
range_conf, pos)) {
171
180
if (range_conf.size()) {
172
std::istringstream is (range_conf);
181
std::istringstream is(range_conf);
173
182
int initial, final;
175
184
if ( (is >> initial) && (initial > 0) &&
176
185
(is >> dash) && (dash == '-') &&
177
186
(is >> final) && (final > 0) ) {
178
187
for (int anum = initial; anum <= final; anum++) {
179
this->push_back (cvm::atom (anum));
188
this->push_back(cvm::atom(anum));
190
if (cvm::get_error()) return COLVARS_ERROR;
186
cvm::fatal_error ("Error: no valid definition for \""
187
"atomNumbersRange\", \""+
196
cvm::error("Error: no valid definition for \"atomNumbersRange\", \""+
197
range_conf+"\".\n", INPUT_ERROR);
192
201
std::vector<std::string> psf_segids;
193
get_keyval (group_conf, "psfSegID", psf_segids, std::vector<std::string> (), mode);
202
get_keyval(group_conf, "psfSegID", psf_segids, std::vector<std::string> (), mode);
194
203
for (std::vector<std::string>::iterator psii = psf_segids.begin();
195
psii < psf_segids.end(); psii++) {
204
psii < psf_segids.end(); ++psii) {
197
206
if ( (psii->size() == 0) || (psii->size() > 4) ) {
198
cvm::fatal_error ("Error: invalid segmend identifier provided, \""+
207
cvm::error("Error: invalid segmend identifier provided, \""+
208
(*psii)+"\".\n", INPUT_ERROR);
227
236
(is >> dash) && (dash == '-') &&
228
237
(is >> final) && (final > 0) ) {
229
238
for (int resid = initial; resid <= final; resid++) {
230
this->push_back (cvm::atom (resid, atom_name, psf_segid));
239
this->push_back(cvm::atom(resid, atom_name, psf_segid));
241
if (cvm::get_error()) return COLVARS_ERROR;
234
cvm::fatal_error ("Error: cannot parse definition for \""
235
"atomNameResidueRange\", \""+
244
cvm::error("Error: cannot parse definition for \""
245
"atomNameResidueRange\", \""+
240
cvm::fatal_error ("Error: atomNameResidueRange with empty definition.\n");
250
cvm::error("Error: atomNameResidueRange with empty definition.\n");
243
253
if (psf_segid.size())
249
259
// read the atoms from a file
250
260
std::string atoms_file_name;
251
if (get_keyval (group_conf, "atomsFile", atoms_file_name, std::string (""), mode)) {
261
if (get_keyval(group_conf, "atomsFile", atoms_file_name, std::string(""), mode)) {
253
263
std::string atoms_col;
254
if (!get_keyval (group_conf, "atomsCol", atoms_col, std::string (""), mode)) {
255
cvm::fatal_error ("Error: parameter atomsCol is required if atomsFile is set.\n");
264
if (!get_keyval(group_conf, "atomsCol", atoms_col, std::string(""), mode)) {
265
cvm::error("Error: parameter atomsCol is required if atomsFile is set.\n",
258
269
double atoms_col_value;
259
bool const atoms_col_value_defined = get_keyval (group_conf, "atomsColValue", atoms_col_value, 0.0, mode);
260
if (atoms_col_value_defined && (!atoms_col_value))
261
cvm::fatal_error ("Error: atomsColValue, "
262
"if provided, must be non-zero.\n");
270
bool const atoms_col_value_defined = get_keyval(group_conf, "atomsColValue", atoms_col_value, 0.0, mode);
271
if (atoms_col_value_defined && (!atoms_col_value)) {
272
cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", INPUT_ERROR);
264
cvm::load_atoms (atoms_file_name.c_str(), *this, atoms_col, atoms_col_value);
275
cvm::load_atoms(atoms_file_name.c_str(), *this, atoms_col, atoms_col_value);
279
// Catch any errors from all the initialization steps above
280
if (cvm::get_error()) return COLVARS_ERROR;
268
282
for (std::vector<cvm::atom>::iterator a1 = this->begin();
269
a1 != this->end(); a1++) {
283
a1 != this->end(); ++a1) {
270
284
std::vector<cvm::atom>::iterator a2 = a1;
272
for ( ; a2 != this->end(); a2++) {
286
for ( ; a2 != this->end(); ++a2) {
273
287
if (a1->id == a2->id) {
274
288
if (cvm::debug())
275
cvm::log ("Discarding doubly counted atom with number "+
276
cvm::to_str (a1->id+1)+".\n");
277
a2 = this->erase (a2);
289
cvm::log("Discarding doubly counted atom with number "+
290
cvm::to_str(a1->id+1)+".\n");
291
a2 = this->erase(a2);
278
292
if (a2 == this->end())
284
if (get_keyval (group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos(), mode)) {
298
if (get_keyval(group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos(), mode)) {
286
300
this->total_mass = 1.0;
290
if (b_dummy && (this->size()))
291
cvm::fatal_error ("Error: cannot set up group \""+
292
std::string (key)+"\" as a dummy atom "
293
"and provide it with atom definitions.\n");
304
if (b_dummy && (this->size())) {
305
cvm::error("Error: cannot set up group \""+
306
std::string(key)+"\" as a dummy atom "
307
"and provide it with atom definitions.\n", INPUT_ERROR);
295
#if (! defined (COLVARS_STANDALONE))
310
#if(! defined(COLVARS_STANDALONE))
296
311
if ( (!b_dummy) && (!cvm::b_analysis) && (!(this->size())) ) {
297
cvm::fatal_error ("Error: no atoms defined for atom group \""+
298
std::string (key)+"\".\n");
312
cvm::error("Error: no atoms defined for atom group \""+
313
std::string(key)+"\".\n");
319
// calculate total mass (TODO: this is the step that most needs deferred re-initialization)
303
320
this->total_mass = 0.0;
304
321
for (cvm::atom_iter ai = this->begin();
305
322
ai != this->end(); ai++) {
306
323
this->total_mass += ai->mass;
326
// whether these atoms will ever receive forces or not
311
327
bool enable_forces = true;
312
328
// disableForces is deprecated
313
if (get_keyval (group_conf, "enableForces", enable_forces, true, mode)) {
329
if (get_keyval(group_conf, "enableForces", enable_forces, true, mode)) {
314
330
noforce = !enable_forces;
316
get_keyval (group_conf, "disableForces", noforce, false, mode);
332
get_keyval(group_conf, "disableForces", noforce, false, colvarparse::parse_silent);
335
get_keyval(group_conf, "weights", weights, weights, colvarparse::parse_silent);
320
338
// FITTING OPTIONS
322
bool b_defined_center = get_keyval (group_conf, "centerReference", b_center, false, mode);
323
bool b_defined_rotate = get_keyval (group_conf, "rotateReference", b_rotate, false, mode);
340
bool b_defined_center = get_keyval(group_conf, "centerReference", b_center, false, mode);
341
bool b_defined_rotate = get_keyval(group_conf, "rotateReference", b_rotate, false, mode);
324
342
// is the user setting explicit options?
325
343
b_user_defined_fit = b_defined_center || b_defined_rotate;
327
get_keyval (group_conf, "enableFitGradients", b_fit_gradients, true, mode);
345
get_keyval(group_conf, "enableFitGradients", b_fit_gradients, true, mode);
329
347
if (b_center || b_rotate) {
332
cvm::fatal_error ("Error: centerReference or rotateReference "
333
"cannot be defined for a dummy atom.\n");
350
cvm::error("Error: centerReference or rotateReference "
351
"cannot be defined for a dummy atom.\n");
335
if (key_lookup (group_conf, "refPositionsGroup")) {
353
if (key_lookup(group_conf, "refPositionsGroup")) {
336
354
// instead of this group, define another group to compute the fit
337
355
if (ref_pos_group) {
338
cvm::fatal_error ("Error: the atom group \""+
339
std::string (key)+"\" has already a reference group "
340
"for the rototranslational fit, which was communicated by the "
341
"colvar component. You should not use refPositionsGroup "
356
cvm::error("Error: the atom group \""+
357
std::string(key)+"\" has already a reference group "
358
"for the rototranslational fit, which was communicated by the "
359
"colvar component. You should not use refPositionsGroup "
344
cvm::log ("Within atom group \""+std::string (key)+"\":\n");
345
ref_pos_group = new atom_group (group_conf, "refPositionsGroup");
362
cvm::log("Within atom group \""+std::string(key)+"\":\n");
363
ref_pos_group = new atom_group(group_conf, "refPositionsGroup");
365
// regardless of the configuration, fit gradients must be calculated by refPositionsGroup
366
ref_pos_group->b_fit_gradients = this->b_fit_gradients;
367
this->b_fit_gradients = false;
348
370
atom_group *group_for_fit = ref_pos_group ? ref_pos_group : this;
350
get_keyval (group_conf, "refPositions", ref_pos, ref_pos, mode);
372
get_keyval(group_conf, "refPositions", ref_pos, ref_pos, mode);
352
374
std::string ref_pos_file;
353
if (get_keyval (group_conf, "refPositionsFile", ref_pos_file, std::string (""), mode)) {
375
if (get_keyval(group_conf, "refPositionsFile", ref_pos_file, std::string(""), mode)) {
355
377
if (ref_pos.size()) {
356
cvm::fatal_error ("Error: cannot specify \"refPositionsFile\" and "
357
"\"refPositions\" at the same time.\n");
378
cvm::error("Error: cannot specify \"refPositionsFile\" and "
379
"\"refPositions\" at the same time.\n");
360
382
std::string ref_pos_col;
361
383
double ref_pos_col_value;
363
if (get_keyval (group_conf, "refPositionsCol", ref_pos_col, std::string (""), mode)) {
385
if (get_keyval(group_conf, "refPositionsCol", ref_pos_col, std::string(""), mode)) {
364
386
// if provided, use PDB column to select coordinates
365
bool found = get_keyval (group_conf, "refPositionsColValue", ref_pos_col_value, 0.0, mode);
387
bool found = get_keyval(group_conf, "refPositionsColValue", ref_pos_col_value, 0.0, mode);
366
388
if (found && !ref_pos_col_value)
367
cvm::fatal_error ("Error: refPositionsColValue, "
368
"if provided, must be non-zero.\n");
389
cvm::error("Error: refPositionsColValue, "
390
"if provided, must be non-zero.\n");
370
392
// if not, rely on existing atom indices for the group
371
393
group_for_fit->create_sorted_ids();
372
ref_pos.resize (group_for_fit->size());
394
ref_pos.resize(group_for_fit->size());
375
cvm::load_coords (ref_pos_file.c_str(), ref_pos, group_for_fit->sorted_ids,
397
cvm::load_coords(ref_pos_file.c_str(), ref_pos, group_for_fit->sorted_ids,
376
398
ref_pos_col, ref_pos_col_value);
382
404
if (ref_pos.size() != group_for_fit->size())
383
cvm::fatal_error ("Error: the number of reference positions provided ("+
384
cvm::to_str (ref_pos.size())+
385
") does not match the number of atoms within \""+
387
"\" ("+cvm::to_str (group_for_fit->size())+
388
"): to perform a rotational fit, "+
389
"these numbers should be equal.\n");
405
cvm::error("Error: the number of reference positions provided("+
406
cvm::to_str(ref_pos.size())+
407
") does not match the number of atoms within \""+
409
"\" ("+cvm::to_str(group_for_fit->size())+
410
"): to perform a rotational fit, "+
411
"these numbers should be equal.\n", INPUT_ERROR);
392
414
// save the center of geometry of ref_pos and subtract it
393
415
center_ref_pos();
396
#if (! defined (COLVARS_STANDALONE))
397
cvm::fatal_error ("Error: no reference positions provided.\n");
418
#if(! defined(COLVARS_STANDALONE))
419
cvm::error("Error: no reference positions provided.\n");
401
423
if (b_fit_gradients) {
402
group_for_fit->fit_gradients.assign (group_for_fit->size(), cvm::atom_pos (0.0, 0.0, 0.0));
403
rot.request_group1_gradients (group_for_fit->size());
424
group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0));
425
rot.request_group1_gradients(group_for_fit->size());
406
428
if (b_rotate && !noforce) {
407
cvm::log ("Warning: atom group \""+std::string (key)+
429
cvm::log("Warning: atom group \""+std::string(key)+
408
430
"\" will be aligned to a fixed orientation given by the reference positions provided. "
409
431
"If the internal structure of the group changes too much (i.e. its RMSD is comparable "
410
432
"to its radius of gyration), the optimal rotation and its gradients may become discontinuous. "
411
433
"If that happens, use refPositionsGroup (or a different definition for it if already defined) "
412
434
"to align the coordinates.\n");
413
435
// initialize rot member data
414
rot.request_group1_gradients (this->size());
436
rot.request_group1_gradients(this->size());
419
441
if (cvm::debug())
420
cvm::log ("Done initializing atom group with name \""+
421
std::string (key)+"\".\n");
423
this->check_keywords (group_conf, key);
425
cvm::log ("Atom group \""+std::string (key)+"\" defined, "+
426
cvm::to_str (this->size())+" atoms initialized: total mass = "+
427
cvm::to_str (this->total_mass)+".\n");
442
cvm::log("Done initializing atom group with name \""+
443
std::string(key)+"\".\n");
445
this->check_keywords(group_conf, key);
446
if (cvm::get_error()) {
447
cvm::error("Error setting up atom group \""+std::string(key)+"\".");
448
return COLVARS_ERROR;
451
cvm::log("Atom group \""+std::string(key)+"\" defined, "+
452
cvm::to_str(this->size())+" atoms initialized: total mass = "+
453
cvm::to_str(this->total_mass)+".\n");
429
455
cvm::decrease_depth();
457
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
433
void cvm::atom_group::create_sorted_ids (void)
461
int cvm::atom_group::create_sorted_ids(void)
435
463
// Only do the work if the vector is not yet populated
436
464
if (sorted_ids.size())
439
467
std::list<int> temp_id_list;
440
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
441
temp_id_list.push_back (ai->id);
469
for (ai = this->begin(); ai != this->end(); ai++) {
470
temp_id_list.push_back(ai->id);
443
472
temp_id_list.sort();
444
473
temp_id_list.unique();
445
474
if (temp_id_list.size() != this->size()) {
446
cvm::fatal_error ("Error: duplicate atom IDs in atom group? (found " +
447
cvm::to_str(temp_id_list.size()) +
448
" unique atom IDs instead of" +
449
cvm::to_str(this->size()) + ").\n");
451
sorted_ids = std::vector<int> (temp_id_list.begin(), temp_id_list.end());
475
cvm::error("Error: duplicate atom IDs in atom group? (found " +
476
cvm::to_str(temp_id_list.size()) +
477
" unique atom IDs instead of" +
478
cvm::to_str(this->size()) + ").\n");
479
return COLVARS_ERROR;
481
sorted_ids = std::vector<int> (temp_id_list.size());
482
unsigned int id_i = 0;
483
std::list<int>::iterator li;
484
for (li = temp_id_list.begin(); li != temp_id_list.end(); ++li) {
485
sorted_ids[id_i] = *li;
488
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
455
491
void cvm::atom_group::center_ref_pos()