44#include "types/FragmentStamp.hpp" 
   58  template<
class ContainerType>
 
   59  bool hasDuplicateElement(
const ContainerType& cont) {
 
   60    ContainerType tmp = cont;
 
   61    std::sort(tmp.begin(), tmp.end());
 
   62    tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
 
   63    return tmp.size() != cont.size();
 
   66  FragmentStamp::FragmentStamp() { DefineParameter(Name, 
"name"); }
 
   68  FragmentStamp::~FragmentStamp() {
 
   69    Utils::deletePointers(atomStamps_);
 
   70    Utils::deletePointers(bondStamps_);
 
   71    Utils::deletePointers(bendStamps_);
 
   72    Utils::deletePointers(torsionStamps_);
 
   73    Utils::deletePointers(inversionStamps_);
 
   74    Utils::deletePointers(rigidBodyStamps_);
 
   75    Utils::deletePointers(cutoffGroupStamps_);
 
   76    Utils::deletePointers(nodesStamps_);
 
   77    Utils::deletePointers(constraintStamps_);
 
   80  bool FragmentStamp::addAtomStamp(AtomStamp* atom) {
 
   81    bool ret = addIndexSensitiveStamp(atomStamps_, atom);
 
   83      std::ostringstream oss;
 
   84      oss << 
"Error in Fragment " << getName()
 
   85          << 
": multiple atoms have the same indices" << atom->getIndex()
 
   87      throw OpenMDException(oss.str());
 
   92  bool FragmentStamp::addBondStamp(BondStamp* bond) {
 
   93    bondStamps_.push_back(bond);
 
   97  bool FragmentStamp::addBendStamp(BendStamp* bend) {
 
   98    bendStamps_.push_back(bend);
 
  102  bool FragmentStamp::addTorsionStamp(TorsionStamp* torsion) {
 
  103    torsionStamps_.push_back(torsion);
 
  106  bool FragmentStamp::addInversionStamp(InversionStamp* inversion) {
 
  107    inversionStamps_.push_back(inversion);
 
  111  bool FragmentStamp::addRigidBodyStamp(RigidBodyStamp* rigidbody) {
 
  112    bool ret = addIndexSensitiveStamp(rigidBodyStamps_, rigidbody);
 
  114      std::ostringstream oss;
 
  115      oss << 
"Error in Fragment " << getName()
 
  116          << 
": multiple rigidbodies have the same indices: " 
  117          << rigidbody->getIndex() << 
"\n";
 
  118      throw OpenMDException(oss.str());
 
  123  bool FragmentStamp::addCutoffGroupStamp(CutoffGroupStamp* cutoffgroup) {
 
  124    cutoffGroupStamps_.push_back(cutoffgroup);
 
  128  bool FragmentStamp::addNodesStamp(NodesStamp* nodes) {
 
  129    nodesStamps_.push_back(nodes);
 
  133  bool FragmentStamp::addConstraintStamp(ConstraintStamp* constraint) {
 
  134    constraintStamps_.push_back(constraint);
 
  138  void FragmentStamp::validate() {
 
  139    DataHolder::validate();
 
  140    CheckParameter(Name, isNotEmpty());
 
  142    atom2Rigidbody.resize(getNAtoms());
 
  148    for (
unsigned int i = 0; i < atom2Rigidbody.size(); ++i) {
 
  149      atom2Rigidbody[i] = -1 - int(i);
 
  151    for (std::size_t i = 0; i < getNRigidBodies(); ++i) {
 
  152      RigidBodyStamp* rbStamp  = getRigidBodyStamp(i);
 
  153      std::vector<int> members = rbStamp->getMembers();
 
  154      for (std::vector<int>::iterator j = members.begin(); j != members.end();
 
  156        atom2Rigidbody[*j] = i;
 
  171  void FragmentStamp::checkAtoms() {
 
  172    std::vector<AtomStamp*>::iterator ai = std::find(
 
  173        atomStamps_.begin(), atomStamps_.end(), 
static_cast<AtomStamp*
>(NULL));
 
  174    if (ai != atomStamps_.end()) {
 
  175      std::ostringstream oss;
 
  176      oss << 
"Error in Fragment " << getName() << 
": atom[" 
  177          << ai - atomStamps_.begin() << 
"] is missing\n";
 
  178      throw OpenMDException(oss.str());
 
  182  void FragmentStamp::checkBonds() {
 
  183    std::ostringstream oss;
 
  185    int natoms = getNAtoms();
 
  186    for (std::size_t i = 0; i < getNBonds(); ++i) {
 
  187      BondStamp* bondStamp = getBondStamp(i);
 
  188      if (bondStamp->getA() > natoms - 1 || bondStamp->getA() < 0 ||
 
  189          bondStamp->getB() > natoms - 1 || bondStamp->getB() < 0 ||
 
  190          bondStamp->getA() == bondStamp->getB()) {
 
  191        oss << 
"Error in Fragment " << getName() << 
": bond(" 
  192            << bondStamp->getA() << 
", " << bondStamp->getB()
 
  194        throw OpenMDException(oss.str());
 
  199    std::set<std::pair<int, int>> allBonds;
 
  200    for (std::size_t i = 0; i < getNBonds(); ++i) {
 
  201      BondStamp* bondStamp = getBondStamp(i);
 
  202      std::pair<int, int> bondPair(bondStamp->getA(), bondStamp->getB());
 
  205      if (bondPair.first > bondPair.second) {
 
  206        std::swap(bondPair.first, bondPair.second);
 
  209      std::set<std::pair<int, int>>::iterator iter = allBonds.find(bondPair);
 
  210      if (iter != allBonds.end()) {
 
  211        oss << 
"Error in Fragment " << getName() << 
": " 
  212            << 
"bond(" << iter->first << 
", " << iter->second
 
  213            << 
") appears multiple times\n";
 
  214        throw OpenMDException(oss.str());
 
  216        allBonds.insert(bondPair);
 
  221    for (std::size_t i = 0; i < getNBonds(); ++i) {
 
  222      BondStamp* bondStamp = getBondStamp(i);
 
  223      if (atom2Rigidbody[bondStamp->getA()] ==
 
  224          atom2Rigidbody[bondStamp->getB()]) {
 
  225        oss << 
"Error in Fragment " << getName() << 
": " 
  226            << 
"bond(" << bondStamp->getA() << 
", " << bondStamp->getB()
 
  227            << 
") belong to same rigidbody " 
  228            << atom2Rigidbody[bondStamp->getA()] << 
"\n";
 
  229        throw OpenMDException(oss.str());
 
  234  void FragmentStamp::checkBends() {
 
  235    std::ostringstream oss;
 
  236    for (std::size_t i = 0; i < getNBends(); ++i) {
 
  237      BendStamp* bendStamp         = getBendStamp(i);
 
  238      std::vector<int> bendAtoms   = bendStamp->getMembers();
 
  239      std::vector<int>::iterator j = std::find_if(
 
  240          bendAtoms.begin(), bendAtoms.end(),
 
  241          std::bind(std::greater<int>(), placeholders::_1, getNAtoms() - 1));
 
  242      std::vector<int>::iterator k =
 
  243          std::find_if(bendAtoms.begin(), bendAtoms.end(),
 
  244                       std::bind(std::less<int>(), placeholders::_1, 0));
 
  246      if (j != bendAtoms.end() || k != bendAtoms.end()) {
 
  247        oss << 
"Error in Fragment " << getName() << 
" : atoms of bend" 
  248            << containerToString(bendAtoms) << 
" have invalid indices\n";
 
  249        throw OpenMDException(oss.str());
 
  252      if (hasDuplicateElement(bendAtoms)) {
 
  253        oss << 
"Error in Fragment " << getName() << 
" : atoms of bend" 
  254            << containerToString(bendAtoms) << 
" have duplicated indices\n";
 
  255        throw OpenMDException(oss.str());
 
  258      if (bendAtoms.size() == 2) {
 
  259        if (!bendStamp->haveGhostVectorSource()) {
 
  260          oss << 
"Error in Fragment " << getName()
 
  261              << 
": ghostVectorSouce is missing\n";
 
  262          throw OpenMDException(oss.str());
 
  264          std::size_t ghostIndex = bendStamp->getGhostVectorSource();
 
  265          if (ghostIndex < getNAtoms()) {
 
  266            if (std::find(bendAtoms.begin(), bendAtoms.end(), ghostIndex) ==
 
  268              oss << 
"Error in Fragment " << getName() << 
": ghostVectorSouce " 
  269                  << ghostIndex << 
"is invalid\n";
 
  270              throw OpenMDException(oss.str());
 
  272            if (!getAtomStamp(ghostIndex)->haveOrientation()) {
 
  273              oss << 
"Error in Fragment " << getName()
 
  274                  << 
": ghost atom must be a directional atom\n";
 
  275              throw OpenMDException(oss.str());
 
  278            oss << 
"Error in Fragment " << getName() << 
": ghostVectorSource " 
  279                << ghostIndex << 
"  is invalid\n";
 
  280            throw OpenMDException(oss.str());
 
  283      } 
else if (bendAtoms.size() == 3 && bendStamp->haveGhostVectorSource()) {
 
  284        oss << 
"Error in Fragment " << getName()
 
  285            << 
": normal bend should not have ghostVectorSouce\n";
 
  286        throw OpenMDException(oss.str());
 
  290    for (std::size_t i = 0; i < getNBends(); ++i) {
 
  291      BendStamp* bendStamp       = getBendStamp(i);
 
  292      std::vector<int> bendAtoms = bendStamp->getMembers();
 
  293      std::vector<int> rigidSet(getNRigidBodies(), 0);
 
  294      std::vector<int>::iterator j;
 
  295      for (j = bendAtoms.begin(); j != bendAtoms.end(); ++j) {
 
  296        int rigidbodyIndex = atom2Rigidbody[*j];
 
  297        if (rigidbodyIndex >= 0) {
 
  298          ++rigidSet[rigidbodyIndex];
 
  299          if (rigidSet[rigidbodyIndex] > 2) {
 
  300            oss << 
"Error in Fragment " << getName() << 
": bend" 
  301                << containerToString(bendAtoms)
 
  302                << 
"has three atoms on the same rigid body\n";
 
  303            throw OpenMDException(oss.str());
 
  309    std::set<std::tuple<int, int, int>> allBends;
 
  310    std::set<std::tuple<int, int, int>>::iterator iter;
 
  311    for (std::size_t i = 0; i < getNBends(); ++i) {
 
  312      BendStamp* bendStamp  = getBendStamp(i);
 
  313      std::vector<int> bend = bendStamp->getMembers();
 
  314      if (bend.size() == 2) {
 
  328        int ghostIndex = bendStamp->getGhostVectorSource();
 
  329        std::vector<int>::iterator j =
 
  330            std::find(bend.begin(), bend.end(), ghostIndex);
 
  331        if (j != bend.end()) { bend.insert(j, ghostIndex); }
 
  334      std::tuple<int, int, int> bendTuple {bend[0], bend[1], bend[2]};
 
  335      auto& [first, second, third] = bendTuple;
 
  339      if (first > third) { std::swap(first, third); }
 
  341      iter = allBends.find(bendTuple);
 
  342      if (iter != allBends.end()) {
 
  343        oss << 
"Error in Fragment " << getName() << 
": " 
  344            << 
"Bend" << containerToString(bend) << 
" appears multiple times\n";
 
  345        throw OpenMDException(oss.str());
 
  347        allBends.insert(bendTuple);
 
  352  void FragmentStamp::checkTorsions() {
 
  353    std::ostringstream oss;
 
  354    for (std::size_t i = 0; i < getNTorsions(); ++i) {
 
  355      TorsionStamp* torsionStamp    = getTorsionStamp(i);
 
  356      std::vector<int> torsionAtoms = torsionStamp->getMembers();
 
  357      std::vector<int>::iterator j  = std::find_if(
 
  358          torsionAtoms.begin(), torsionAtoms.end(),
 
  359          std::bind(std::greater<int>(), placeholders::_1, getNAtoms() - 1));
 
  360      std::vector<int>::iterator k =
 
  361          std::find_if(torsionAtoms.begin(), torsionAtoms.end(),
 
  362                       std::bind(std::less<int>(), placeholders::_1, 0));
 
  364      if (j != torsionAtoms.end() || k != torsionAtoms.end()) {
 
  365        oss << 
"Error in Fragment " << getName() << 
": atoms of torsion" 
  366            << containerToString(torsionAtoms) << 
" have invalid indices\n";
 
  367        throw OpenMDException(oss.str());
 
  369      if (hasDuplicateElement(torsionAtoms)) {
 
  370        oss << 
"Error in Fragment " << getName() << 
" : atoms of torsion" 
  371            << containerToString(torsionAtoms) << 
" have duplicated indices\n";
 
  372        throw OpenMDException(oss.str());
 
  376    for (std::size_t i = 0; i < getNTorsions(); ++i) {
 
  377      TorsionStamp* torsionStamp    = getTorsionStamp(i);
 
  378      std::vector<int> torsionAtoms = torsionStamp->getMembers();
 
  379      std::vector<int> rigidSet(getNRigidBodies(), 0);
 
  380      std::vector<int>::iterator j;
 
  381      for (j = torsionAtoms.begin(); j != torsionAtoms.end(); ++j) {
 
  382        int rigidbodyIndex = atom2Rigidbody[*j];
 
  383        if (rigidbodyIndex >= 0) {
 
  384          ++rigidSet[rigidbodyIndex];
 
  385          if (rigidSet[rigidbodyIndex] > 3) {
 
  386            oss << 
"Error in Fragment " << getName() << 
": torsion" 
  387                << containerToString(torsionAtoms)
 
  388                << 
"has four atoms on the same rigid body\n";
 
  389            throw OpenMDException(oss.str());
 
  395    std::set<std::tuple<int, int, int, int>> allTorsions;
 
  396    std::set<std::tuple<int, int, int, int>>::iterator iter;
 
  397    for (std::size_t i = 0; i < getNTorsions(); ++i) {
 
  398      TorsionStamp* torsionStamp = getTorsionStamp(i);
 
  399      std::vector<int> torsion   = torsionStamp->getMembers();
 
  400      if (torsion.size() == 3) {
 
  401        int ghostIndex = torsionStamp->getGhostVectorSource();
 
  402        std::vector<int>::iterator j =
 
  403            std::find(torsion.begin(), torsion.end(), ghostIndex);
 
  404        if (j != torsion.end()) { torsion.insert(j, ghostIndex); }
 
  407      std::tuple<int, int, int, int> torsionTuple(torsion[0], torsion[1],
 
  408                                                  torsion[2], torsion[3]);
 
  409      auto& [first, second, third, fourth] = torsionTuple;
 
  411      if (first > fourth) {
 
  412        std::swap(first, fourth);
 
  413        std::swap(second, third);
 
  416      iter = allTorsions.find(torsionTuple);
 
  417      if (iter == allTorsions.end()) {
 
  418        allTorsions.insert(torsionTuple);
 
  420        oss << 
"Error in Fragment " << getName() << 
": " 
  421            << 
"Torsion" << containerToString(torsion)
 
  422            << 
" appears multiple times\n";
 
  423        throw OpenMDException(oss.str());
 
  428  void FragmentStamp::checkInversions() {
 
  429    std::ostringstream oss;
 
  434    for (std::size_t i = 0; i < getNInversions(); ++i) {
 
  435      InversionStamp* inversionStamp = getInversionStamp(i);
 
  436      int center                     = inversionStamp->getCenter();
 
  437      std::vector<int> satellites;
 
  442      if (inversionStamp->getNSatellites() != 3) {
 
  443        for (std::size_t j = 0; j < getNBonds(); ++j) {
 
  444          BondStamp* bondStamp = getBondStamp(j);
 
  445          int a                = bondStamp->getA();
 
  446          int b                = bondStamp->getB();
 
  448          if (a == center) { satellites.push_back(b); }
 
  449          if (b == center) { satellites.push_back(a); }
 
  452        if (satellites.size() == 3) {
 
  453          std::sort(satellites.begin(), satellites.end());
 
  454          inversionStamp->setSatellites(satellites);
 
  456          oss << 
"Error in Fragment " << getName() << 
": found wrong number" 
  457              << 
" of bonds for inversion center " << center;
 
  458          throw OpenMDException(oss.str());
 
  465    for (std::size_t i = 0; i < getNInversions(); ++i) {
 
  466      InversionStamp* inversionStamp = getInversionStamp(i);
 
  468      std::vector<int> inversionAtoms = inversionStamp->getSatellites();
 
  470      inversionAtoms.insert(inversionAtoms.begin(),
 
  471                            inversionStamp->getCenter());
 
  473      std::vector<int>::iterator j = std::find_if(
 
  474          inversionAtoms.begin(), inversionAtoms.end(),
 
  475          std::bind(std::greater<int>(), placeholders::_1, getNAtoms() - 1));
 
  476      std::vector<int>::iterator k =
 
  477          std::find_if(inversionAtoms.begin(), inversionAtoms.end(),
 
  478                       std::bind(std::less<int>(), placeholders::_1, 0));
 
  480      if (j != inversionAtoms.end() || k != inversionAtoms.end()) {
 
  481        oss << 
"Error in Fragment " << getName() << 
": atoms of inversion" 
  482            << containerToString(inversionAtoms) << 
" have invalid indices\n";
 
  483        throw OpenMDException(oss.str());
 
  486      if (hasDuplicateElement(inversionAtoms)) {
 
  487        oss << 
"Error in Fragment " << getName() << 
" : atoms of inversion" 
  488            << containerToString(inversionAtoms)
 
  489            << 
" have duplicated indices\n";
 
  490        throw OpenMDException(oss.str());
 
  494    for (std::size_t i = 0; i < getNInversions(); ++i) {
 
  495      InversionStamp* inversionStamp  = getInversionStamp(i);
 
  496      std::vector<int> inversionAtoms = inversionStamp->getSatellites();
 
  497      inversionAtoms.push_back(inversionStamp->getCenter());
 
  498      std::vector<int> rigidSet(getNRigidBodies(), 0);
 
  499      std::vector<int>::iterator j;
 
  500      for (j = inversionAtoms.begin(); j != inversionAtoms.end(); ++j) {
 
  501        int rigidbodyIndex = atom2Rigidbody[*j];
 
  502        if (rigidbodyIndex >= 0) {
 
  503          ++rigidSet[rigidbodyIndex];
 
  504          if (rigidSet[rigidbodyIndex] > 3) {
 
  505            oss << 
"Error in Fragment " << getName()
 
  506                << 
": inversion centered on atom " 
  507                << inversionStamp->getCenter()
 
  508                << 
" has four atoms that belong to same rigidbody " 
  509                << rigidbodyIndex << 
"\n";
 
  510            throw OpenMDException(oss.str());
 
  516    std::set<std::tuple<int, int, int, int>> allInversions;
 
  517    std::set<std::tuple<int, int, int, int>>::iterator iter;
 
  518    for (std::size_t i = 0; i < getNInversions(); ++i) {
 
  519      InversionStamp* inversionStamp = getInversionStamp(i);
 
  520      int cent                       = inversionStamp->getCenter();
 
  521      std::vector<int> inversion     = inversionStamp->getSatellites();
 
  523      std::tuple<int, int, int, int> inversionTuple(cent, inversion[0],
 
  524                                                    inversion[1], inversion[2]);
 
  525      auto& [first, second, third, fourth] = inversionTuple;
 
  532      if (third > fourth) std::swap(third, fourth);
 
  533      if (second > third) std::swap(second, third);
 
  534      if (third > fourth) std::swap(third, fourth);
 
  536      iter = allInversions.find(inversionTuple);
 
  537      if (iter == allInversions.end()) {
 
  538        allInversions.insert(inversionTuple);
 
  540        oss << 
"Error in Fragment " << getName() << 
": " 
  541            << 
"Inversion" << containerToString(inversion)
 
  542            << 
" appears multiple times\n";
 
  543        throw OpenMDException(oss.str());
 
  548  void FragmentStamp::checkRigidBodies() {
 
  549    std::ostringstream oss;
 
  550    std::vector<RigidBodyStamp*>::iterator ri =
 
  551        std::find(rigidBodyStamps_.begin(), rigidBodyStamps_.end(),
 
  552                  static_cast<RigidBodyStamp*
>(NULL));
 
  553    if (ri != rigidBodyStamps_.end()) {
 
  554      oss << 
"Error in Fragment " << getName() << 
":rigidBody[" 
  555          << ri - rigidBodyStamps_.begin() << 
"] is missing\n";
 
  556      throw OpenMDException(oss.str());
 
  559    for (std::size_t i = 0; i < getNRigidBodies(); ++i) {
 
  560      RigidBodyStamp* rbStamp      = getRigidBodyStamp(i);
 
  561      std::vector<int> rigidAtoms  = rbStamp->getMembers();
 
  562      std::vector<int>::iterator j = std::find_if(
 
  563          rigidAtoms.begin(), rigidAtoms.end(),
 
  564          std::bind(std::greater<int>(), placeholders::_1, getNAtoms() - 1));
 
  565      if (j != rigidAtoms.end()) {
 
  566        oss << 
"Error in Fragment " << getName();
 
  567        throw OpenMDException(oss.str());
 
  572  void FragmentStamp::checkCutoffGroups() {
 
  573    std::vector<AtomStamp*>::iterator ai;
 
  574    std::vector<int>::iterator fai;
 
  577    for (ai = atomStamps_.begin(); ai != atomStamps_.end(); ++ai) {
 
  578      freeAtoms_.push_back((*ai)->getIndex());
 
  581    for (std::size_t i = 0; i < getNCutoffGroups(); ++i) {
 
  582      CutoffGroupStamp* cutoffGroupStamp = getCutoffGroupStamp(i);
 
  583      std::vector<int> cutoffGroupAtoms  = cutoffGroupStamp->getMembers();
 
  584      std::vector<int>::iterator j       = std::find_if(
 
  585          cutoffGroupAtoms.begin(), cutoffGroupAtoms.end(),
 
  586          std::bind(std::greater<int>(), placeholders::_1, getNAtoms() - 1));
 
  587      if (j != cutoffGroupAtoms.end()) {
 
  588        std::ostringstream oss;
 
  589        oss << 
"Error in Fragment " << getName() << 
": cutoffGroup" 
  590            << 
" is out of range\n";
 
  591        throw OpenMDException(oss.str());
 
  594      for (fai = cutoffGroupAtoms.begin(); fai != cutoffGroupAtoms.end();
 
  598            std::remove(freeAtoms_.begin(), freeAtoms_.end(), (*fai)),
 
  604  void FragmentStamp::checkConstraints() {
 
  605    std::ostringstream oss;
 
  607    int natoms = getNAtoms();
 
  608    for (std::size_t i = 0; i < getNConstraints(); ++i) {
 
  609      ConstraintStamp* constraintStamp = getConstraintStamp(i);
 
  610      if (constraintStamp->getA() > natoms - 1 || constraintStamp->getA() < 0 ||
 
  611          constraintStamp->getB() > natoms - 1 || constraintStamp->getB() < 0 ||
 
  612          constraintStamp->getA() == constraintStamp->getB()) {
 
  613        oss << 
"Error in Fragment " << getName() << 
": constraint(" 
  614            << constraintStamp->getA() << 
", " << constraintStamp->getB()
 
  616        throw OpenMDException(oss.str());
 
  621    std::set<std::pair<int, int>> allConstraints;
 
  622    for (std::size_t i = 0; i < getNConstraints(); ++i) {
 
  623      ConstraintStamp* constraintStamp = getConstraintStamp(i);
 
  624      std::pair<int, int> constraintPair(constraintStamp->getA(),
 
  625                                         constraintStamp->getB());
 
  628      if (constraintPair.first > constraintPair.second) {
 
  629        std::swap(constraintPair.first, constraintPair.second);
 
  632      std::set<std::pair<int, int>>::iterator iter =
 
  633          allConstraints.find(constraintPair);
 
  634      if (iter != allConstraints.end()) {
 
  635        oss << 
"Error in Fragment " << getName() << 
": " 
  636            << 
"constraint(" << iter->first << 
", " << iter->second
 
  637            << 
") appears multiple times\n";
 
  638        throw OpenMDException(oss.str());
 
  640        allConstraints.insert(constraintPair);
 
  646    for (std::size_t i = 0; i < getNConstraints(); ++i) {
 
  647      ConstraintStamp* constraintStamp = getConstraintStamp(i);
 
  648      if (atom2Rigidbody[constraintStamp->getA()] ==
 
  649          atom2Rigidbody[constraintStamp->getB()]) {
 
  650        oss << 
"Error in Fragment " << getName() << 
": " 
  651            << 
"constraint(" << constraintStamp->getA() << 
", " 
  652            << constraintStamp->getB() << 
") belong to same rigidbody " 
  653            << atom2Rigidbody[constraintStamp->getA()] << 
"\n";
 
  654        throw OpenMDException(oss.str());
 
  659  void FragmentStamp::checkNodes() {
 
  660    std::ostringstream oss;
 
  661    std::vector<NodesStamp*>::iterator ni =
 
  662        std::find(nodesStamps_.begin(), nodesStamps_.end(),
 
  663                  static_cast<NodesStamp*
>(NULL));
 
  664    if (ni != nodesStamps_.end()) {
 
  665      oss << 
"Error in Molecule " << getName() << 
":nodes[" 
  666          << ni - nodesStamps_.begin() << 
"] is missing\n";
 
  667      throw OpenMDException(oss.str());
 
  670    for (std::size_t i = 0; i < getNNodes(); ++i) {
 
  671      NodesStamp* nStamp           = getNodesStamp(i);
 
  672      std::vector<int> nodeAtoms   = nStamp->getMembers();
 
  673      std::vector<int>::iterator j = std::find_if(
 
  674          nodeAtoms.begin(), nodeAtoms.end(),
 
  675          std::bind(std::greater<int>(), placeholders::_1, getNAtoms() - 1));
 
  676      if (j != nodeAtoms.end()) {
 
  677        oss << 
"Error in Fragment " << getName();
 
  678        throw OpenMDException(oss.str());
 
  683  void FragmentStamp::fillBondInfo() {
 
  684    for (std::size_t i = 0; i < getNBonds(); ++i) {
 
  685      BondStamp* bondStamp = getBondStamp(i);
 
  686      int a                = bondStamp->getA();
 
  687      int b                = bondStamp->getB();
 
  688      AtomStamp* atomA     = getAtomStamp(a);
 
  689      AtomStamp* atomB     = getAtomStamp(b);
 
  691      atomA->addBondedAtom(b);
 
  693      atomB->addBondedAtom(a);
 
  700  bool FragmentStamp::isBondInSameRigidBody(BondStamp* bond) {
 
  706    if (!isAtomInRigidBody(bond->getA(), rbA, consAtomA)) 
return false;
 
  708    if (!isAtomInRigidBody(bond->getB(), rbB, consAtomB)) 
return false;
 
  719  bool FragmentStamp::isAtomInRigidBody(
int atomIndex) {
 
  720    return atom2Rigidbody[atomIndex] >= 0;
 
  730  bool FragmentStamp::isAtomInRigidBody(
int atomIndex, 
int& whichRigidBody,
 
  731                                        int& consAtomIndex) {
 
  735    if (atom2Rigidbody[atomIndex] >= 0) {
 
  736      whichRigidBody          = atom2Rigidbody[atomIndex];
 
  737      RigidBodyStamp* rbStamp = getRigidBodyStamp(whichRigidBody);
 
  738      int numAtom             = rbStamp->getNMembers();
 
  739      for (
int j = 0; j < numAtom; j++) {
 
  740        if (rbStamp->getMemberAt(j) == atomIndex) {
 
  755  std::vector<std::pair<int, int>> FragmentStamp::getJointAtoms(
int rb1,
 
  757    RigidBodyStamp* rbStamp1;
 
  758    RigidBodyStamp* rbStamp2;
 
  763    std::vector<std::pair<int, int>> jointAtomIndexPair;
 
  765    rbStamp1   = this->getRigidBodyStamp(rb1);
 
  766    natomInRb1 = rbStamp1->getNMembers();
 
  768    rbStamp2   = this->getRigidBodyStamp(rb2);
 
  769    natomInRb2 = rbStamp2->getNMembers();
 
  771    for (
int i = 0; i < natomInRb1; i++) {
 
  772      atomIndex1 = rbStamp1->getMemberAt(i);
 
  774      for (
int j = 0; j < natomInRb2; j++) {
 
  775        atomIndex2 = rbStamp2->getMemberAt(j);
 
  777        if (atomIndex1 == atomIndex2) {
 
  778          jointAtomIndexPair.push_back(std::make_pair(i, j));
 
  784    return jointAtomIndexPair;
 
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.