Simpatico  v1.10
simp/species/Species.cpp
1 /*
2 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
3 *
4 * Copyright 2010 - 2017, The Regents of the University of Minnesota
5 * Distributed under the terms of the GNU General Public License.
6 */
7 
8 #include "Species.h"
9 
10 #include <util/global.h>
11 #include <simp/species/SpeciesGroup.tpp>
12 #include <util/format/Int.h>
13 
14 namespace Simp
15 {
16 
17  using namespace Util;
18 
19  /*
20  * Default constructor.
21  */
23  : id_(-1),
24  moleculeCapacity_(0),
25  nAtom_(0),
26  atomTypeIds_(),
27  #ifdef SIMP_BOND
28  nBond_(0),
29  speciesBonds_(),
30  #endif
31  #ifdef SIMP_ANGLE
32  nAngle_(0),
33  speciesAngles_(),
34  #endif
35  #ifdef SIMP_DIHEDRAL
36  nDihedral_(0),
37  speciesDihedrals_(),
38  #endif
39  mutatorPtr_(0)
40  { setClassName("Species"); }
41 
42  /*
43  * Destructor.
44  */
46  {}
47 
48  /*
49  * Read parameters for species.
50  */
51  void Species::readParameters(std::istream &in)
52  {
53  read<int>(in, "moleculeCapacity", moleculeCapacity_);
54 
55  // Define chemical structure, after reading any parameters.
56  readSpeciesParam(in);
57 
58  // Check validity, throw exception if not valid
59  isValid();
60  }
61 
62  /*
63  * Load parameters for species.
64  */
66  {
67  loadParameter<int>(ar, "moleculeCapacity", moleculeCapacity_);
68 
69  // Read and define chemical structure.
70  loadSpeciesParam(ar);
71 
72  // Check validity, throw exception if not valid
73  isValid();
74  }
75 
76  /*
77  * Define molecular structure (default implementation).
78  */
79  void Species::readSpeciesParam(std::istream &in)
80  {
81  read<int>(in, "nAtom", nAtom_);
82  allocateAtoms();
83  readDArray<int>(in, "atomTypeIds", atomTypeIds_, nAtom_);
84 
85  #ifdef SIMP_BOND
86  nBond_ = 0;
87  readOptional<int>(in, "nBond", nBond_);
88  allocateBonds();
89  if (nBond_ > 0) {
90  readDArray<SpeciesBond>(in, "speciesBonds", speciesBonds_,
91  nBond_);
92  }
93  #endif
94 
95  #ifdef SIMP_ANGLE
96  nAngle_ = 0;
97  readOptional<int>(in, "nAngle", nAngle_);
99  if (nAngle_ > 0) {
100  readDArray<SpeciesAngle>(in, "speciesAngles", speciesAngles_,
101  nAngle_);
102  }
103  #endif
104 
105  #ifdef SIMP_DIHEDRAL
106  nDihedral_ = 0;
107  readOptional<int>(in, "nDihedral", nDihedral_);
109  if (nDihedral_ > 0) {
110  readDArray<SpeciesDihedral>(in, "speciesDihedrals",
112  }
113  #endif
114 
116  }
117 
118  /*
119  * Load molecular structure (default implementation).
120  */
122  {
123  loadParameter<int>(ar, "nAtom", nAtom_);
124  allocateAtoms();
125  loadDArray<int>(ar, "atomTypeIds", atomTypeIds_, nAtom_);
126 
127  #ifdef SIMP_BOND
128  loadParameter<int>(ar, "nBond", nBond_);
129  allocateBonds();
130  if (nBond_ > 0) {
131  loadDArray<SpeciesBond>(ar, "speciesBonds", speciesBonds_,
132  nBond_);
133  }
134  #endif
135 
136  #ifdef SIMP_ANGLE
137  loadParameter<int>(ar, "nAngle", nAngle_);
138  allocateAngles();
139  if (nAngle_ > 0) {
140  loadDArray<SpeciesAngle>(ar, "speciesAngles", speciesAngles_,
141  nAngle_);
142  }
143  #endif
144 
145  #ifdef SIMP_DIHEDRAL
146  loadParameter<int>(ar, "nDihedral", nDihedral_);
148  if (nDihedral_ > 0) {
149  loadDArray<SpeciesDihedral>(ar, "speciesDihedrals",
151  }
152  #endif
153 
155  }
156 
157  /*
158  * Read molecule structure from config/topo file format.
159  */
160  void Species::readStructure(std::istream& in)
161  {
162  using std::endl;
163  int k;
164 
165  // Atom type Ids
166  in >> Label("nAtom") >> nAtom_;
167  allocateAtoms();
168  for (int j = 0; j < nAtom_; j++) {
169  in >> k;
170  in >> atomTypeIds_[j];
171  }
172 
173  #ifdef SIMP_BOND
174  nBond_ = 0;
175  if (Label("nBond", false).match(in)) {
176  in >> nBond_;
177  }
178  allocateBonds();
179  if (nBond_ > 0) {
180  for (int j = 0; j < nBond_; j++) {
181  in >> k;
182  UTIL_CHECK(j == k);
183  in >> speciesBonds_[j];
184  }
185  }
186  #endif
187 
188  #ifdef SIMP_ANGLE
189  nAngle_ = 0;
190  if (Label("nAngle", false).match(in)) {
191  in >> nAngle_;
192  }
193  allocateAngles();
194  if (nAngle_ > 0) {
195  for (int j = 0; j < nAngle_; j++) {
196  in >> k;
197  UTIL_CHECK(j == k);
198  in >> speciesAngles_[j];
199  }
200  }
201  #endif
202 
203  #ifdef SIMP_DIHEDRAL
204  nDihedral_ = 0;
205  if (Label("nDihedral", false).match(in)) {
206  in >> nDihedral_;
207  }
209  if (nDihedral_ > 0) {
210  for (int j = 0; j < nDihedral_; j++) {
211  in >> k;
212  UTIL_CHECK(j == k);
213  in >> speciesDihedrals_[j];
214  }
215  }
216  #endif
217 
219 
220  // Check validity, throw exception if not valid
221  isValid();
222 
224  }
225 
226  /*
227  * Initialize atom group id arrays (references from atoms to groups).
228  */
230  {
231  UTIL_CHECK(nAtom_ > 0);
234 
235  #ifdef SIMP_BOND
236  UTIL_CHECK(nBond_ >= 0);
237  if (nBond_ > 0) {
238  UTIL_CHECK(speciesBonds_.isAllocated());
239  UTIL_CHECK(speciesBonds_.capacity() == nBond_);
240  UTIL_CHECK(atomBondIdArrays_.isAllocated());
241  UTIL_CHECK(atomBondIdArrays_.capacity() == nAtom_);
242  for (int atomId = 0; atomId < nAtom_; ++atomId) {
243  UTIL_CHECK(atomBondIdArrays_[atomId].size() == 0);
244  }
245  int bondId, atomId1, atomId2;
246  for (bondId = 0; bondId < nBond_; ++bondId) {
247  atomId1 = speciesBond(bondId).atomId(0);
248  atomId2 = speciesBond(bondId).atomId(1);
249  UTIL_CHECK(atomId1 >=0 && atomId1 < nAtom_);
250  UTIL_CHECK(atomId2 >=0 && atomId2 < nAtom_);
251  atomBondIdArrays_[atomId1].append(bondId);
252  atomBondIdArrays_[atomId2].append(bondId);
253  }
254  }
255  #endif
256  #ifdef SIMP_ANGLE
257  UTIL_CHECK(nAngle_ >= 0);
258  if (nAngle_ > 0) {
259  UTIL_CHECK(speciesAngles_.isAllocated());
260  UTIL_CHECK(speciesAngles_.capacity() == nAngle_);
261  UTIL_CHECK(atomAngleIdArrays_.isAllocated());
262  UTIL_CHECK(atomAngleIdArrays_.capacity() == nAtom_);
263  for (int atomId = 0; atomId < nAtom_; ++atomId) {
264  UTIL_CHECK(atomAngleIdArrays_[atomId].size() == 0);
265  }
266  int angleId, atomId1, atomId2, atomId3;
267  for (angleId = 0; angleId < nAngle_; ++angleId) {
268  atomId1 = speciesAngle(angleId).atomId(0);
269  atomId2 = speciesAngle(angleId).atomId(1);
270  atomId3 = speciesAngle(angleId).atomId(2);
271  UTIL_CHECK(atomId1 >=0 && atomId1 < nAtom_);
272  UTIL_CHECK(atomId2 >=0 && atomId2 < nAtom_);
273  UTIL_CHECK(atomId3 >=0 && atomId3 < nAtom_);
274  atomAngleIdArrays_[atomId1].append(angleId);
275  atomAngleIdArrays_[atomId2].append(angleId);
276  atomAngleIdArrays_[atomId3].append(angleId);
277  }
278  }
279  #endif
280  #ifdef SIMP_DIHEDRAL
281  UTIL_CHECK(nDihedral_ >= 0);
282  if (nDihedral_ > 0) {
283  UTIL_CHECK(speciesDihedrals_.isAllocated());
284  UTIL_CHECK(speciesDihedrals_.capacity() == nDihedral_);
285  UTIL_CHECK(atomDihedralIdArrays_.isAllocated());
286  UTIL_CHECK(atomDihedralIdArrays_.capacity() == nAtom_);
287  for (int atomId = 0; atomId < nAtom_; ++atomId) {
288  UTIL_CHECK(atomDihedralIdArrays_[atomId].size() == 0);
289  }
290  int dihedralId, atomId1, atomId2, atomId3, atomId4;
291  for (dihedralId = 0; dihedralId < nDihedral_; ++dihedralId) {
292  atomId1 = speciesDihedral(dihedralId).atomId(0);
293  atomId2 = speciesDihedral(dihedralId).atomId(1);
294  atomId3 = speciesDihedral(dihedralId).atomId(2);
295  atomId4 = speciesDihedral(dihedralId).atomId(3);
296  UTIL_CHECK(atomId1 >=0 && atomId1 < nAtom_);
297  UTIL_CHECK(atomId2 >=0 && atomId2 < nAtom_);
298  UTIL_CHECK(atomId3 >=0 && atomId3 < nAtom_);
299  UTIL_CHECK(atomId4 >=0 && atomId4 < nAtom_);
300  atomDihedralIdArrays_[atomId1].append(dihedralId);
301  atomDihedralIdArrays_[atomId2].append(dihedralId);
302  atomDihedralIdArrays_[atomId3].append(dihedralId);
303  atomDihedralIdArrays_[atomId4].append(dihedralId);
304  }
305  }
306  #endif
307  }
308 
309  /*
310  * Save internal state to an archive.
311  */
313  {
314  ar << moleculeCapacity_;
315  ar << nAtom_;
316  ar << atomTypeIds_;
317  #ifdef SIMP_BOND
318  ar << nBond_;
319  if (nBond_ > 0) {
320  ar << speciesBonds_;
321  }
322  #endif
323  #ifdef SIMP_ANGLE
324  ar << nAngle_;
325  if (nAngle_ > 0) {
326  ar << speciesAngles_;
327  }
328  #endif
329  #ifdef SIMP_DIHEDRAL
330  ar << nDihedral_;
331  if (nDihedral_ > 0) {
332  ar << speciesDihedrals_;
333  }
334  #endif
335  }
336 
337  /*
338  * Write molecule structure in config/topo file format.
339  */
340  void Species::writeStructure(std::ostream& out, std::string indent)
341  {
342  using std::endl;
343  std::string xIndent = indent;
344  xIndent += " ";
345 
346  // Atom type Ids
347  out << indent << "nAtom " << nAtom_;
348  for (int iAtom = 0; iAtom < nAtom_; iAtom++) {
349  out << endl << xIndent << Int(iAtom,2) << " "
350  << atomTypeIds_[iAtom];
351  }
352 
353  #ifdef SIMP_BOND
354  if (nBond_ > 0) {
355  out << endl << indent << "nBond " << nBond_;
356  for (int iBond = 0; iBond < nBond_; iBond++) {
357  out << endl << xIndent << Int(iBond,2) << " "
358  << speciesBonds_[iBond];
359  }
360  }
361  #endif
362 
363  #ifdef SIMP_ANGLE
364  if (nAngle_ > 0) {
365  out << endl << indent << "nAngle " << nAngle_;
366  for (int iAngle = 0; iAngle < nAngle_; iAngle++) {
367  out << endl << xIndent << Int(iAngle,2) << " "
368  << speciesAngles_[iAngle];
369  }
370  }
371  #endif
372 
373  #ifdef SIMP_DIHEDRAL
374  if (nDihedral_ > 0) {
375  out << endl << indent << "nDihedral " << nDihedral_;
376  for (int iDihedral = 0; iDihedral < nDihedral_; iDihedral++) {
377  out << endl << xIndent << Int(iDihedral,2) << " "
378  << speciesDihedrals_[iDihedral];
379  }
380  }
381  #endif
382  }
383 
384  /*
385  * Compare molecule structure in structure from file.
386  */
387  bool Species::matchStructure(std::istream& in)
388  {
389  using std::endl;
390  bool match = true;
391 
392  // Atom type Ids
393  int index, count, typeId;
394  in >> Label("nAtom") >> count;
395  if (count != nAtom()) match = false;
396  for (int iAtom = 0; iAtom < nAtom_; iAtom++) {
397  in >> index >> typeId;
398  if (index != iAtom) match = false;
399  if (typeId != atomTypeIds_[iAtom]) match = false;
400  }
401 
402  #ifdef SIMP_BOND
403  if (Label("nBond", false).match(in)) {
404  in >> count;
405  if (count != nBond()) match = false;
406  int i0, i1;
407  for (int iBond = 0; iBond < nBond_; iBond++) {
408  in >> index >> i0 >> i1 >> typeId;
409  if (i0 != speciesBonds_[iBond].atomId(0)) match = false;
410  if (i1 != speciesBonds_[iBond].atomId(1)) match = false;
411  }
412  }
413  #endif
414 
415  #ifdef SIMP_ANGLE
416  if (Label("nAngle", false).match(in)) {
417  in >> count;
418  if (count != nAngle()) match = false;
419  int i0, i1, i2;
420  for (int iAngle = 0; iAngle < nAngle_; iAngle++) {
421  in >> index >> i0 >> i1 >> i2 >> typeId;
422  if (i0 != speciesAngles_[iAngle].atomId(0)) match = false;
423  if (i1 != speciesAngles_[iAngle].atomId(1)) match = false;
424  if (i2 != speciesDihedrals_[iAngle].atomId(2)) match = false;
425  }
426  }
427  #endif
428 
429  #ifdef SIMP_DIHEDRAL
430  if (Label("nDihedral", false).match(in)) {
431  in >> count;
432  if (count != nDihedral()) match = false;
433  int i0, i1, i2, i3;
434  for (int iDihedral = 0; iDihedral < nDihedral_; iDihedral++) {
435  in >> index >> i0 >> i1 >> i2 >> i3 >> typeId;
436  if (i0 != speciesDihedrals_[iDihedral].atomId(0)) match = false;
437  if (i1 != speciesDihedrals_[iDihedral].atomId(1)) match = false;
438  if (i2 != speciesDihedrals_[iDihedral].atomId(2)) match = false;
439  if (i3 != speciesDihedrals_[iDihedral].atomId(3)) match = false;
440  }
441  }
442  #endif
443 
444  return match;
445  }
446 
447  // Setters
448 
449  /*
450  * Set value of integer id for this species.
451  */
452  void Species::setId(int id)
453  {
454  // Preconditions
455  if (id < 0) UTIL_THROW("Negative species id");
456  if (id_ >= 0) UTIL_THROW("Species id was set previously");
457 
458  id_ = id;
459  }
460 
461  /*
462  * Set a pointer to an associated SpeciesMutator object.
463  */
465  { mutatorPtr_ = mutatorPtr; }
466 
467  /*
468  * Allocate memory for arrays that describe chemical structure.
469  */
471  {
472  allocateAtoms();
473  #ifdef SIMP_BOND
474  allocateBonds();
475  #endif
476  #ifdef SIMP_ANGLE
477  allocateAngles();
478  #endif
479  #ifdef SIMP_DIHEDRAL
481  #endif
482  }
483 
484  /*
485  * Allocate and initialize atomTypeId array.
486  */
488  {
489  UTIL_CHECK(nAtom_ > 0);
491 
493 
494  // Initialize atom type Ids to null/invalid values
495  for (int i = 0; i < nAtom_; ++i) {
496  atomTypeIds_[i] = -1;
497  }
498  }
499 
500  /*
501  * Set the atom type for one atom
502  */
503  void Species::setAtomType(int atomId, int atomType)
504  { atomTypeIds_[atomId] = atomType; }
505 
506  #ifdef SIMP_BOND
507  /*
508  * Allocate memory for arrays that involve bonds.
509  */
511  {
512  UTIL_CHECK(nAtom_ > 0);
513  UTIL_CHECK(nBond_ >= 0);
514  UTIL_CHECK(!atomBondIdArrays_.isAllocated());
515 
516  atomBondIdArrays_.allocate(nAtom_);
517  if (nBond_ > 0) {
518  UTIL_CHECK(!speciesBonds_.isAllocated());
519  speciesBonds_.allocate(nBond_);
520  }
521  }
522 
523  /*
524  * Add a bond to the species chemical structure.
525  */
526  void Species::makeBond(int bondId, int atomId1, int atomId2,
527  int bondType)
528  {
529  // Preconditions
530  assert(bondId >= 0);
531  assert(atomId1 >= 0);
532  assert(atomId2 >= 0);
533  assert(bondId < nBond_);
534  assert(atomId1 < nAtom_);
535  assert(atomId2 < nAtom_);
536 
537  // Create a SpeciesGroup<2> object for this bond
538  speciesBonds_[bondId].setAtomId(0, atomId1);
539  speciesBonds_[bondId].setAtomId(1, atomId2);
540  speciesBonds_[bondId].setTypeId(bondType);
541 
542  // Add bond Id to AtomBondIdArray objects for both atoms
543  atomBondIdArrays_[atomId1].append(bondId);
544  atomBondIdArrays_[atomId2].append(bondId);
545 
546  }
547  #endif
548 
549  #ifdef SIMP_ANGLE
550  /*
551  * Allocate memory for arrays that involve angles.
552  */
554  {
555  UTIL_CHECK(nAtom_ > 0);
556  UTIL_CHECK(nAngle_ >= 0);
557  UTIL_CHECK(!atomAngleIdArrays_.isAllocated());
558 
559  atomAngleIdArrays_.allocate(nAtom_);
560  if (nAngle_ > 0) {
561  UTIL_CHECK(!speciesAngles_.isAllocated());
562  speciesAngles_.allocate(nAngle_);
563  }
564  }
565 
566  /*
567  * Add an angle to the species chemical structure.
568  */
570  int angleId, int atomId1, int atomId2, int atomId3, int angleType)
571  {
572  // Preconditions.
573  assert(angleId >= 0);
574  assert(atomId1 >= 0);
575  assert(atomId2 >= 0);
576  assert(atomId3 >= 0);
577  assert(angleId < nAngle_);
578  assert(atomId1 < nAtom_);
579  assert(atomId2 < nAtom_);
580  assert(atomId3 < nAtom_);
581 
582  // Create a SpeciesGroup<3> object for this angle.
583  speciesAngles_[angleId].setAtomId(0, atomId1);
584  speciesAngles_[angleId].setAtomId(1, atomId2);
585  speciesAngles_[angleId].setAtomId(2, atomId3);
586  speciesAngles_[angleId].setTypeId(angleType);
587 
588  // Add angle Id to AtomAngleIdArray objects for all atoms.
589  atomAngleIdArrays_[atomId1].append(angleId);
590  atomAngleIdArrays_[atomId2].append(angleId);
591  atomAngleIdArrays_[atomId3].append(angleId);
592  }
593  #endif
594 
595  #ifdef SIMP_DIHEDRAL
596  /*
597  * Allocate memory for arrays that involve dihedrals
598  */
600  {
601  UTIL_CHECK(nAtom_ > 0);
602  UTIL_CHECK(nDihedral_ >= 0);
603  UTIL_CHECK(!atomDihedralIdArrays_.isAllocated());
604 
605  atomDihedralIdArrays_.allocate(nAtom_);
606 
607  if (nDihedral_ > 0) {
608  UTIL_CHECK(!speciesDihedrals_.isAllocated());
609  speciesDihedrals_.allocate(nDihedral_);
610  }
611  }
612 
613  /*
614  * Add a dihedral to the species chemical structure.
615  */
616  void Species::makeDihedral(int dihedralId, int atomId1, int atomId2,
617  int atomId3, int atomId4, int dihedralType)
618  {
619  // Preconditions.
620  assert(dihedralId >= 0);
621  assert(atomId1 >= 0);
622  assert(atomId2 >= 0);
623  assert(atomId3 >= 0);
624  assert(atomId4 >= 0);
625  assert(dihedralId < nDihedral_);
626  assert(atomId1 < nAtom_);
627  assert(atomId2 < nAtom_);
628  assert(atomId3 < nAtom_);
629  assert(atomId4 < nAtom_);
630 
631  // Create a SpeciesGroup<4> object for this angle.
632  speciesDihedrals_[dihedralId].setAtomId(0, atomId1);
633  speciesDihedrals_[dihedralId].setAtomId(1, atomId2);
634  speciesDihedrals_[dihedralId].setAtomId(2, atomId3);
635  speciesDihedrals_[dihedralId].setAtomId(3, atomId4);
636  speciesDihedrals_[dihedralId].setTypeId(dihedralType);
637 
638  // Add angle Id to AtomAngleIdArray objects for all atoms.
639  atomDihedralIdArrays_[atomId1].append(dihedralId);
640  atomDihedralIdArrays_[atomId2].append(dihedralId);
641  atomDihedralIdArrays_[atomId3].append(dihedralId);
642  atomDihedralIdArrays_[atomId4].append(dihedralId);
643  }
644  #endif
645 
646  /*
647  * Check validity of Species. Return true if valid, or throw an Exception.
648  */
649  bool Species::isValid() const
650  {
651 
652  if (atomTypeIds_.isAllocated()) {
653 
655 
656  // Check atomTypeIds array
657  if (!isMutable()) {
658  for (int i = 0; i < nAtom_; ++i) {
659  if (atomTypeIds_[i] < 0) {
660  UTIL_THROW("Negative AtomTypeIds_ in non-mutable Species");
661  }
662  }
663  }
664 
665  #ifdef SIMP_BOND
666  if (nBond_ > 0) {
667  UTIL_CHECK(speciesBonds_.isAllocated());
668  UTIL_CHECK(speciesBonds_.capacity() == nBond_);
669  UTIL_CHECK(atomBondIdArrays_.isAllocated());
670  UTIL_CHECK(atomBondIdArrays_.capacity() == nAtom_);
671 
672  // Loop over all bonds (if any) in speciesBonds_ array
673  int atomId, bondId, atomId0, atomId1, j;
674  bool hasBond;
675  for (bondId = 0; bondId < nBond_; ++bondId) {
676 
677  atomId0 = speciesBond(bondId).atomId(0);
678  atomId1 = speciesBond(bondId).atomId(1);
679 
680  // Check that atomIds are in valid range and unequal
681  if (atomId0 < 0 || atomId0 >= nAtom_) {
682  UTIL_THROW("Invalid atomId0 in speciesBonds_");
683  }
684  if (atomId1 < 0 || atomId1 >= nAtom_) {
685  UTIL_THROW("Invalid atomId1 in speciesBonds_");
686  }
687  if (atomId0 == atomId1) {
688  UTIL_THROW("Equal atom ids in a SpeciesBond");
689  }
690 
691  // Check that bondId is in atombondIdArrays_ for atomId0
692  hasBond = false;
693  for (j = 0; j < atomBondIdArrays_[atomId0].size(); ++j) {
694  if (atomBondIdArrays_[atomId0][j] == bondId) {
695  hasBond = true;
696  break;
697  }
698  }
699  if (!hasBond) {
700  UTIL_THROW("BondId missing from atomBondIdArrays_");
701  }
702 
703  // Check that bondId is in atombondIdArrays_ for atomId1
704  hasBond = false;
705  for (j = 0; j < atomBondIdArrays_[atomId1].size(); ++j) {
706  if (atomBondIdArrays_[atomId1][j] == bondId) {
707  hasBond = true;
708  break;
709  }
710  }
711  if (!hasBond) {
712  UTIL_THROW("BondId missing from atomBondIdArrays_");
713  }
714 
715  }
716 
717  // Loop over atomBondIdArrays for all atoms
718  int bondCounter = 0;
719  for (atomId = 0; atomId < nAtom_; ++atomId) {
720  for (j = 0; j < atomBondIdArrays_[atomId].size(); ++j) {
721  bondId = atomBondIdArrays_[atomId][j];
722 
723  if (bondId < 0 || bondId >= nBond_)
724  UTIL_THROW("Bond index out of range");
725 
726  atomId0 = speciesBond(bondId).atomId(0);
727  atomId1 = speciesBond(bondId).atomId(1);
728  if (atomId != atomId0 && atomId != atomId1)
729  UTIL_THROW("Inconsistency in atomBondId and bond");
730  ++bondCounter;
731 
732  }
733  }
734  if (bondCounter != 2*nBond_) {
735  UTIL_THROW("Inconsistency in total number of bonds");
736  }
737  }
738  #endif
739 
740  #ifdef SIMP_ANGLE
741  if (nAngle_ > 0) {
742  UTIL_CHECK(speciesAngles_.isAllocated());
743  UTIL_CHECK(speciesAngles_.capacity() == nAngle_);
744  UTIL_CHECK(atomAngleIdArrays_.isAllocated());
745  UTIL_CHECK(atomAngleIdArrays_.capacity() == nAtom_);
746 
747  // Loop over all angles (if any) in speciesAngles_ array
748  int angleId, id, id2, atomId, atomId2(-1), j;
749  bool hasAngles;
750  for (angleId = 0; angleId < nAngle_; ++angleId) {
751 
752  for (id = 0; id < 3; ++id) {
753  atomId = speciesAngle(angleId).atomId(id);
754 
755  // Check that atomIds are in valid range and unequal
756  if (atomId < 0 || atomId >= nAtom_) {
757  UTIL_THROW("Invalid atomId in speciesAngles_");
758  }
759  for (id2 = id + 1; id2 < 3; ++id2) {
760  atomId2 = speciesAngle(angleId).atomId(id2);
761  if (atomId2 == atomId) {
762  UTIL_THROW("Equal atom ids in a SpeciesAngle");
763  }
764  }
765 
766  // Check that angleId is in atomAngleIdArrays_ for atomId
767  hasAngles = false;
768  for (j = 0; j < atomAngleIdArrays_[atomId].size(); ++j) {
769  if (atomAngleIdArrays_[atomId][j] == angleId) {
770  hasAngles = true;
771  break;
772  }
773  }
774  if (!hasAngles) {
775  UTIL_THROW("AngleId missing from atomAngleIdArrays_");
776  }
777  }
778 
779  }
780 
781  // Loop over atomAngleIdArrays for all atoms
782  int angleCounter = 0;
783  bool hasAtom;
784  for (atomId = 0; atomId < nAtom_; ++atomId) {
785  for (j = 0; j < atomAngleIdArrays_[atomId].size(); ++j) {
786  angleId = atomAngleIdArrays_[atomId][j];
787  if (angleId < 0 || angleId >= nAngle_)
788  UTIL_THROW("Angle index out of range");
789 
790  hasAtom = false;
791  for (id = 0; id < 3; ++id) {
792  atomId2 = speciesAngle(angleId).atomId(id);
793  if (atomId2 == atomId) {
794  hasAtom = true;
795  break;
796  }
797  }
798  if (!hasAtom) {
799  UTIL_THROW("Inconsistency in atomAngleId and angle");
800  }
801  ++angleCounter;
802  }
803  }
804  if (angleCounter != 3*nAngle_) {
805  UTIL_THROW("Inconsistency in total number of angles");
806  }
807  }
808  #endif
809 
810  #ifdef SIMP_DIHEDRAL
811  if (nDihedral_ > 0) {
812  UTIL_CHECK(speciesDihedrals_.isAllocated());
813  UTIL_CHECK(speciesDihedrals_.capacity() == nDihedral_);
814  UTIL_CHECK(atomDihedralIdArrays_.isAllocated());
815  UTIL_CHECK(atomDihedralIdArrays_.capacity() == nAtom_);
816 
817  // Loop over all dihedrals (if any) in speciesDihedrals_ array
818  int dihedralId, tId, tId2, tAtomId, tAtomId2, j;
819  bool hasDihedral;
820 
821  for (dihedralId = 0; dihedralId < nDihedral_; ++dihedralId) {
822 
823  for (tId = 0; tId < 4; ++tId) {
824  tAtomId = speciesDihedral(dihedralId).atomId(tId);
825 
826  // Check that atomIds are in valid range and unequal
827  if (tAtomId < 0 || tAtomId >= nAtom_) {
828  UTIL_THROW("Invalid atomId in speciesDihedral_");
829  }
830  for (tId2 = tId + 1; tId2 < 4; ++tId2) {
831  tAtomId2 = speciesDihedral(dihedralId).atomId(tId2);
832  if (tAtomId2 == tAtomId) {
833  UTIL_THROW("Equal atom ids in a SpeciesDihedral");
834  }
835  }
836 
837  // Check that dihedralId is in atomDihedralIdArrays_ for tAtomId
838  hasDihedral = false;
839  for (j = 0; j < atomDihedralIdArrays_[tAtomId].size(); ++j) {
840  if (atomDihedralIdArrays_[tAtomId][j] == dihedralId) {
841  hasDihedral = true;
842  break;
843  }
844  }
845  if (!hasDihedral) {
846  UTIL_THROW("DihedralId missing from atomDihedralIdArrays_");
847  }
848  }
849 
850  }
851 
852  // Loop over atomDihedralIdArrays for all atoms.
853  int dihedralCounter = 0;
854  bool tHasAtom;
855  for (tAtomId = 0; tAtomId < nAtom_; ++tAtomId) {
856  for (j = 0; j < atomDihedralIdArrays_[tAtomId].size(); ++j) {
857  dihedralId = atomDihedralIdArrays_[tAtomId][j];
858  if (dihedralId < 0 || dihedralId >= nDihedral_)
859  UTIL_THROW("Dihedral index out of range");
860 
861  tHasAtom = false;
862  for (tId = 0; tId < 4; ++tId) {
863  tAtomId2 = speciesDihedral(dihedralId).atomId(tId);
864  if (tAtomId2 == tAtomId) {
865  tHasAtom = true;
866  break;
867  }
868  }
869  if (!tHasAtom) {
870  UTIL_THROW("Inconsistency in atomDihedralId and dihedral");
871  }
872  ++dihedralCounter;
873  }
874  }
875  if (dihedralCounter != 4*nDihedral_) {
876  UTIL_THROW("Inconsistency in total number of dihedrals");
877  }
878  }
879  #endif
880 
881  } else {
882 
883  if (moleculeCapacity_ != 0) {
884  UTIL_THROW("Species not allocated but moleculeCapacity != 0");
885  }
886 
887  }
888 
889  return true;
890  }
891 
892 }
void setAtomType(int atomId, int atomType)
Set the type for one atom in a generic molecule of this Species.
const SpeciesDihedral & speciesDihedral(int iDihedral) const
Get a specific SpeciesDihedral object, by local angle index.
int nAtom() const
Get number of atoms per molecule for this Species.
int moleculeCapacity_
Number of molecules associated with the species.
DArray< SpeciesDihedral > speciesDihedrals_
Array of SpeciesDihedrals, indexed by local dihedral id.
void setMutatorPtr(McMd::SpeciesMutator *mutatorPtr)
Set pointer to associated McMd::SpeciesMutator for a mutable species.
void writeStructure(std::ostream &out, std::string indent=std::string())
Write molecular structure in config/topology file format.
DArray< SpeciesBond > speciesBonds_
Array of SpeciesBonds for all bonds, indexed by local bond id.
virtual void readSpeciesParam(std::istream &in)
Define chemical structure for this Species.
virtual ~Species()
Destructor.
void allocateAtoms()
Allocate and initialize array of atom type Ids.
File containing preprocessor macros for error handling.
Classes used by all simpatico molecular simulations.
Mix-in class for mutable subclasses of Species.
void allocateDihedrals()
Allocate arrays associated with dihedrals.
static bool isClear()
Is the input buffer clear?
Definition: Label.cpp:37
int nAtom_
Number of atoms per molecule.
Saving / output archive for binary ostream.
DArray< int > atomTypeIds_
Array of atom type Ids, indexed by local atom id.
const SpeciesBond & speciesBond(int iBond) const
Get a specific SpeciesBond object, by local bond index.
int nDihedral() const
Get number of dihedrals per molecule for this Species.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
Species()
Constructor.
DArray< SpeciesAngle > speciesAngles_
Array of SpeciesAngles for all angles, indexed by local angle id.
void makeDihedral(int dihedralId, int atomId1, int atomId2, int atomId3, int atomId4, int dihedralType)
Add a dihedral to the chemical structure of a generic molecule.
Utility classes for scientific computation.
Definition: accumulators.mod:1
const SpeciesAngle & speciesAngle(int iAngle) const
Get a specific SpeciesAngle object, by local angle index.
Wrapper for an int, for formatted ostream output.
Definition: Int.h:36
bool matchStructure(std::istream &in)
Read structure, return true iff it matches existing structure.
int nDihedral_
Number of dihedrals per molecule.
bool isAllocated() const
Return true if the DArray has been allocated, false otherwise.
Definition: DArray.h:222
int nAngle_
Number of angles per molecule.
bool isValid() const
Return true if Species is valid, or throw an Exception.
virtual void readParameters(std::istream &in)
Read parameters and initialize structure for this species.
void makeBond(int bondId, int atomId1, int atomId2, int bondType)
Add a bond to the chemical structure of a generic molecule.
void setId(int id)
Set integer id for this Species.
A label string in a file format.
Definition: Label.h:36
void allocateBonds()
Allocate arrays associated with Bonds.
int id_
Integer index for this Species.
int id() const
Get integer id of this Species.
Saving archive for binary istream.
int atomId(int i) const
Get the local id for a specific Atom.
Definition: SpeciesGroup.h:182
void makeAngle(int angleId, int atomId1, int atomId2, int atomId3, int angleType)
Add an angle to the chemical structure of a generic molecule.
void readStructure(std::istream &in)
Read structure from config/topology file format.
bool isMutable() const
Is this a mutable Species?
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
void setClassName(const char *className)
Set class name string.
virtual void loadSpeciesParam(Serializable::IArchive &ar)
Define chemical structure for this Species.
void allocate()
Allocate chemical structure arrays.
int capacity() const
Return allocated size.
Definition: Array.h:153
void allocate(int capacity)
Allocate the underlying C array.
Definition: DArray.h:191
int nBond() const
Get number of bonds per molecule for this Species.
int nAngle() const
Get number of angles per molecule for this Species.
std::string indent() const
Return indent string for this object (string of spaces).
int nBond_
Number of bonds per molecule.
void initializeAtomGroupIdArrays()
Initialize all atom groupId arrays (point from atoms to groups).
void allocateAngles()
Allocate arrays associated with angles.
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.