TEST_F(MoleculeTest, removeBond)
{
  Molecule molecule;
  Atom a = molecule.addAtom(1);
  Atom b = molecule.addAtom(1);
  Bond bondAB = molecule.addBond(a, b);
  Atom c = molecule.addAtom(1);
  molecule.addBond(b, c, 2);

  EXPECT_EQ(3, molecule.atomCount());
  EXPECT_EQ(2, molecule.bondCount());
  EXPECT_TRUE(molecule.bond(a, b).isValid());
  EXPECT_TRUE(molecule.bond(b, c).isValid());

  molecule.removeBond(bondAB);

  EXPECT_EQ(3, molecule.atomCount());
  EXPECT_EQ(1, molecule.bondCount());
  EXPECT_FALSE(molecule.bond(a, b).isValid());
  EXPECT_TRUE(molecule.bond(b, c).isValid());

  molecule.clearBonds();

  EXPECT_EQ(0, molecule.bondCount());
}
TEST_F(MoleculeTest, removeAtom)
{
  Molecule molecule;
  Atom atom0 = molecule.addAtom(6);
  Atom atom1 = molecule.addAtom(1);
  Atom atom2 = molecule.addAtom(1);
  Atom atom3 = molecule.addAtom(1);
  Atom atom4 = molecule.addAtom(1);
  molecule.addBond(atom0, atom1, 1);
  molecule.addBond(atom0, atom2, 1);
  molecule.addBond(atom0, atom3, 1);
  molecule.addBond(atom0, atom4, 1);

  EXPECT_EQ(5, molecule.atomCount());
  EXPECT_EQ(4, molecule.bondCount());

  molecule.removeAtom(atom0);

  EXPECT_EQ(4, molecule.atomCount());
  EXPECT_EQ(0, molecule.bondCount());

  molecule.clearAtoms();

  EXPECT_EQ(0, molecule.atomCount());
}
Example #3
0
bool Cube::setLimits(const Molecule &mol, double spacing_, double padding)
{
  Index numAtoms = mol.atomCount();
  Vector3 min_, max_;
  if (numAtoms) {
    Vector3 curPos = min_ = max_ = mol.atomPositions3d()[0];
    for (Index i = 1; i < numAtoms; ++i) {
      curPos = mol.atomPositions3d()[i];
      if (curPos.x() < min_.x())
        min_.x() = curPos.x();
      if (curPos.x() > max_.x())
        max_.x() = curPos.x();
      if (curPos.y() < min_.y())
        min_.y() = curPos.y();
      if (curPos.y() > max_.y())
        max_.y() = curPos.y();
      if (curPos.z() < min_.z())
        min_.z() = curPos.z();
      if (curPos.z() > max_.z())
        max_.z() = curPos.z();
    }
  }
  else {
    min_ = max_ = Vector3::Zero();
  }

  // Now to take care of the padding term
  min_ += Vector3(-padding,-padding,-padding);
  max_ += Vector3( padding, padding, padding);

  return setLimits(min_, max_, spacing_);
}
TEST_F(MoleculeTest, addAtom)
{
  Molecule molecule;
  EXPECT_EQ(molecule.atomCount(), static_cast<Index>(0));

  Avogadro::Core::Atom atom = molecule.addAtom(6);
  EXPECT_EQ(atom.isValid(), true);
  EXPECT_EQ(molecule.atomCount(), static_cast<Index>(1));
  EXPECT_EQ(atom.index(), 0);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(6));

  Avogadro::Core::Atom atom2 = molecule.addAtom(1);
  EXPECT_EQ(atom2.isValid(), true);
  EXPECT_EQ(molecule.atomCount(), static_cast<Index>(2));
  EXPECT_EQ(atom2.index(), 1);
  EXPECT_EQ(atom2.atomicNumber(), static_cast<unsigned char>(1));
}
void BallAndStick::process(const Molecule &molecule,
                           Rendering::GroupNode &node)
{
  // Add a sphere node to contain all of the spheres.
  GeometryNode *geometry = new GeometryNode;
  node.addChild(geometry);
  SphereGeometry *spheres = new SphereGeometry;
  spheres->identifier().molecule = &molecule;
  spheres->identifier().type = Rendering::AtomType;
  geometry->addDrawable(spheres);

  for (Index i = 0; i < molecule.atomCount(); ++i) {
    Core::Atom atom = molecule.atom(i);
    unsigned char atomicNumber = atom.atomicNumber();
    const unsigned char *c = Elements::color(atomicNumber);
    Vector3ub color(c[0], c[1], c[2]);
    spheres->addSphere(atom.position3d().cast<float>(), color,
                       static_cast<float>(Elements::radiusVDW(atomicNumber))
                       * 0.3f);
  }

  float bondRadius = 0.1f;
  CylinderGeometry *cylinders = new CylinderGeometry;
  cylinders->identifier().molecule = &molecule;
  cylinders->identifier().type = Rendering::BondType;
  geometry->addDrawable(cylinders);
  for (Index i = 0; i < molecule.bondCount(); ++i) {
    Core::Bond bond = molecule.bond(i);
    Vector3f pos1 = bond.atom1().position3d().cast<float>();
    Vector3f pos2 = bond.atom2().position3d().cast<float>();
    Vector3ub color1(Elements::color(bond.atom1().atomicNumber()));
    Vector3ub color2(Elements::color(bond.atom2().atomicNumber()));
    Vector3f bondVector = pos2 - pos1;
    float bondLength = bondVector.norm();
    bondVector /= bondLength;
    switch (bond.order()) {
    case 3: {
      Vector3f delta = bondVector.unitOrthogonal() * (2.0f * bondRadius);
      cylinders->addCylinder(pos1 + delta, bondVector, bondLength, bondRadius,
                             color1, color2, i);
      cylinders->addCylinder(pos1 - delta, bondVector, bondLength, bondRadius,
                             color1, color2, i);
    }
    default:
    case 1:
      cylinders->addCylinder(pos1, bondVector, bondLength, bondRadius,
                             color1, color2, i);
      break;
    case 2: {
      Vector3f delta = bondVector.unitOrthogonal() * bondRadius;
      cylinders->addCylinder(pos1 + delta, bondVector, bondLength, bondRadius,
                             color1, color2, i);
      cylinders->addCylinder(pos1 - delta, bondVector, bondLength, bondRadius,
                             color1, color2, i);
    }
    }
  }
}
void HydrogenTools::removeAllHydrogens(Molecule &molecule)
{
  const Array<unsigned char> atomicNums(molecule.atomicNumbers());
  size_t atomIndex = molecule.atomCount() - 1;
  for (Array<unsigned char>::const_reverse_iterator
       it = atomicNums.rbegin(), itEnd = atomicNums.rend(); it != itEnd;
       ++it, --atomIndex) {
    if (*it == 1)
      molecule.removeAtom(atomIndex);
  }
}
void HydrogenTools::adjustHydrogens(Molecule &molecule, Adjustment adjustment)
{
  // This vector stores indices of hydrogens that need to be removed. Additions
  // are made first, followed by removals to keep indexing sane.
  std::vector<size_t> badHIndices;

  // Temporary container for calls to generateNewHydrogenPositions.
  std::vector<Vector3> newHPos;

  // Convert the adjustment option to a couple of booleans
  bool doAdd(adjustment == Add || adjustment == AddAndRemove);
  bool doRemove(adjustment == Remove || adjustment == AddAndRemove);

  // Limit to only the original atoms:
  const size_t numAtoms = molecule.atomCount();

  // Iterate through all atoms in the molecule, adding hydrogens as needed
  // and building up a list of hydrogens that should be removed.
  for (size_t atomIndex = 0; atomIndex < numAtoms; ++atomIndex) {
    const Atom atom(molecule.atom(atomIndex));
    int hDiff = valencyAdjustment(atom);
    // Add hydrogens:
    if (doAdd && hDiff > 0) {
      newHPos.clear();
      generateNewHydrogenPositions(atom, hDiff, newHPos);
      for (std::vector<Vector3>::const_iterator it = newHPos.begin(),
           itEnd = newHPos.end(); it != itEnd; ++it) {
        Atom newH(molecule.addAtom(1));
        newH.setPosition3d(*it);
        molecule.addBond(atom, newH, 1);
      }
    }
    // Add bad hydrogens to our list of hydrogens to remove:
    else if (doRemove && hDiff < 0) {
      extraHydrogenIndices(atom, -hDiff, badHIndices);
    }
  }

  // Remove dead hydrogens now. Remove them in reverse-index order to keep
  // indexing sane.
  if (doRemove && !badHIndices.empty()) {
    std::sort(badHIndices.begin(), badHIndices.end());
    std::vector<size_t>::iterator newEnd(std::unique(badHIndices.begin(),
                                                     badHIndices.end()));
    badHIndices.resize(std::distance(badHIndices.begin(), newEnd));
    for (std::vector<size_t>::const_reverse_iterator it = badHIndices.rbegin(),
         itEnd = badHIndices.rend(); it != itEnd; ++it) {
      molecule.removeAtom(*it);
    }
  }
}
TEST(HydrogenToolsTest, adjustHydrogens_C2H4O)
{
  Molecule mol;
  Atom C1 = mol.addAtom(6);
  Atom C2 = mol.addAtom(6);
  Atom O1 = mol.addAtom(8);
  mol.addBond(C1, C2, 1);
  mol.addBond(C2, O1, 2);

  HydrogenTools::adjustHydrogens(mol);
  EXPECT_EQ(7, mol.atomCount());
  EXPECT_EQ(6, mol.bondCount());
  EXPECT_EQ(std::string("C2H4O"), mol.formula());
}
TEST(HydrogenToolsTest, adjustHydrogens_C3H8)
{
  Molecule mol;
  Atom C1 = mol.addAtom(6);
  Atom C2 = mol.addAtom(6);
  Atom C3 = mol.addAtom(6);
  mol.addBond(C1, C2, 1);
  mol.addBond(C2, C3, 1);

  HydrogenTools::adjustHydrogens(mol);
  EXPECT_EQ(11, mol.atomCount());
  EXPECT_EQ(10, mol.bondCount());
  EXPECT_EQ(std::string("C3H8"), mol.formula());
}
Example #10
0
TEST(CjsonTest, crystal)
{
  CjsonFormat cjson;
  Molecule molecule;
  bool success = cjson.readFile(std::string(AVOGADRO_DATA) +
                                "/data/rutile.cjson", molecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");
  EXPECT_EQ(molecule.data("name").toString(), "TiO2 rutile");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(6));
  EXPECT_EQ(molecule.bondCount(), static_cast<size_t>(0));

  const UnitCell *unitCell = molecule.unitCell();
  ASSERT_NE(unitCell, (UnitCell*)NULL);
  EXPECT_TRUE(std::fabs((float)unitCell->a() - 2.95812f) < 1e-5f);
  EXPECT_TRUE(std::fabs((float)unitCell->b() - 4.59373f) < 1e-5f);
  EXPECT_TRUE(std::fabs((float)unitCell->c() - 4.59373f) < 1e-5f);
  EXPECT_TRUE(std::fabs((float)unitCell->alpha() - (.5f * PI_F)) < 1e-5f);
  EXPECT_TRUE(std::fabs((float)unitCell->beta()  - (.5f * PI_F)) < 1e-5f);
  EXPECT_TRUE(std::fabs((float)unitCell->gamma() - (.5f * PI_F)) < 1e-5f);

  Atom atom = molecule.atom(5);
  EXPECT_EQ(atom.atomicNumber(), 8);
  EXPECT_TRUE(std::fabs((float)atom.position3d().x() - 1.479060f) < 1e-5f);
  EXPECT_TRUE(std::fabs((float)atom.position3d().y() - 3.699331f) < 1e-5f);
  EXPECT_TRUE(std::fabs((float)atom.position3d().z() - 0.894399f) < 1e-5f);

  std::string cjsonStr;
  cjson.writeString(cjsonStr, molecule);
  Molecule otherMolecule;
  cjson.readString(cjsonStr, otherMolecule);

  const UnitCell *otherUnitCell = otherMolecule.unitCell();
  ASSERT_NE(otherUnitCell, (UnitCell*)NULL);
  EXPECT_FLOAT_EQ((float)otherUnitCell->a(),     (float)unitCell->a());
  EXPECT_FLOAT_EQ((float)otherUnitCell->b(),     (float)unitCell->b());
  EXPECT_FLOAT_EQ((float)otherUnitCell->c(),     (float)unitCell->c());
  EXPECT_FLOAT_EQ((float)otherUnitCell->alpha(), (float)unitCell->alpha());
  EXPECT_FLOAT_EQ((float)otherUnitCell->beta(),  (float)unitCell->beta());
  EXPECT_FLOAT_EQ((float)otherUnitCell->gamma(), (float)unitCell->gamma());

  Atom otherAtom = otherMolecule.atom(5);
  EXPECT_EQ(otherAtom.atomicNumber(), atom.atomicNumber());
  EXPECT_FLOAT_EQ((float)otherAtom.position3d().x(),
                  (float)atom.position3d().x());
  EXPECT_FLOAT_EQ((float)otherAtom.position3d().y(),
                  (float)atom.position3d().y());
  EXPECT_FLOAT_EQ((float)otherAtom.position3d().z(),
                  (float)atom.position3d().z());
}
Example #11
0
TEST(RWMoleculeTest, MoleculeToRWMolecule)
{
  Molecule mol;
  typedef Molecule::AtomType Atom;
  typedef Molecule::BondType Bond;
  Atom a0 = mol.addAtom(1);
  Atom a1 = mol.addAtom(6);
  Atom a2 = mol.addAtom(9);
  Bond b0 = mol.addBond(a0, a2);
  a1.setPosition3d(Vector3(0, 6, 9));
  b0.setOrder(3);

  RWMolecule rwmol(mol, 0);
  EXPECT_EQ(rwmol.atomCount(), mol.atomCount());
  EXPECT_EQ(rwmol.bondCount(), mol.bondCount());
  EXPECT_EQ(rwmol.atom(2).atomicNumber(), mol.atom(2).atomicNumber());
  EXPECT_EQ(rwmol.bond(0).order(), mol.bond(0).order());
}
Example #12
0
TEST(CjsonTest, bonds)
{
  CjsonFormat cjson;
  Molecule molecule;
  bool success = cjson.readFile(std::string(AVOGADRO_DATA) +
                                "/data/ethane.cjson", molecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  EXPECT_EQ(molecule.bondCount(), static_cast<size_t>(7));

  Bond bond = molecule.bond(0);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(0));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(1));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
  bond = molecule.bond(6);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(4));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(7));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
}
Example #13
0
TEST(HydrogenToolsTest, removeAllHydrogens)
{
  Molecule mol;
  mol.addAtom(1);
  HydrogenTools::removeAllHydrogens(mol);
  EXPECT_EQ(mol.atomCount(), 0);

  Atom C1 = mol.addAtom(6);
  Atom C2 = mol.addAtom(6);
  Atom C3 = mol.addAtom(6);

  mol.addBond(C1, C2, 1);
  mol.addBond(C2, C3, 1);

  Atom H = mol.addAtom(1);
  mol.addBond(C1, H);
  H = mol.addAtom(1);
  mol.addBond(C1, H);
  H = mol.addAtom(1);
  mol.addBond(C1, H);

  H = mol.addAtom(1);
  mol.addBond(C2, H);
  H = mol.addAtom(1);
  mol.addBond(C2, H);

  H = mol.addAtom(1);
  mol.addBond(C3, H);
  H = mol.addAtom(1);
  mol.addBond(C3, H);
  H = mol.addAtom(1);
  mol.addBond(C3, H);

  HydrogenTools::removeAllHydrogens(mol);
  EXPECT_EQ(std::string("C3"), mol.formula());
}
Example #14
0
TEST(CjsonTest, atoms)
{
  CjsonFormat cjson;
  Molecule molecule;
  bool success = cjson.readFile(std::string(AVOGADRO_DATA) +
                                "/data/ethane.cjson", molecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  Atom atom = molecule.atom(0);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  atom = molecule.atom(1);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(6));
  EXPECT_EQ(atom.position3d().x(),  0.751621);
  EXPECT_EQ(atom.position3d().y(), -0.022441);
  EXPECT_EQ(atom.position3d().z(), -0.020839);

  atom = molecule.atom(7);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  EXPECT_EQ(atom.position3d().x(), -1.184988);
  EXPECT_EQ(atom.position3d().y(),  0.004424);
  EXPECT_EQ(atom.position3d().z(), -0.987522);
}
TEST(UnitCellTest, fractionalCoordinates)
{
  Molecule mol = createCrystal(static_cast<Real>(3.0),
                               static_cast<Real>(4.0),
                               static_cast<Real>(5.0),
                               static_cast<Real>(90.0),
                               static_cast<Real>(120.0),
                               static_cast<Real>(77.0));
  mol.addAtom(1).setPosition3d(Vector3(static_cast<Real>(0),
                                       static_cast<Real>(0),
                                       static_cast<Real>(0)));
  mol.addAtom(1).setPosition3d(Vector3(static_cast<Real>(0.7),
                                       static_cast<Real>(2.23733),
                                       static_cast<Real>(2.14574)));
  mol.addAtom(1).setPosition3d(Vector3(static_cast<Real>(2.07490),
                                       static_cast<Real>(2.09303),
                                       static_cast<Real>(1.07287)));
  mol.addAtom(1).setPosition3d(Vector3(static_cast<Real>(3),
                                       static_cast<Real>(0),
                                       static_cast<Real>(0)));
  mol.addAtom(1).setPosition3d(Vector3(static_cast<Real>(0.89980),
                                       static_cast<Real>(3.89748),
                                       static_cast<Real>(0)));
  mol.addAtom(1).setPosition3d(Vector3(static_cast<Real>(-2.5),
                                       static_cast<Real>(0.57717),
                                       static_cast<Real>(4.29149)));
  Array<Vector3> ccoords_ref = mol.atomPositions3d();

  Array<Vector3> fcoords;
  EXPECT_TRUE(CrystalTools::fractionalCoordinates(mol, fcoords));
  EXPECT_EQ(mol.atomCount(), fcoords.size());
  EXPECT_TRUE(std::fabs(fcoords[0][0] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[0][1] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[0][2] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[1][0] - static_cast<Real>(0.5)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[1][1] - static_cast<Real>(0.5)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[1][2] - static_cast<Real>(0.5)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[2][0] - static_cast<Real>(0.75)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[2][1] - static_cast<Real>(0.5)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[2][2] - static_cast<Real>(0.25)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[3][0] - static_cast<Real>(1)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[3][1] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[3][2] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[4][0] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[4][1] - static_cast<Real>(1)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[4][2] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[5][0] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[5][1] - static_cast<Real>(0)) < 1e-4);
  EXPECT_TRUE(std::fabs(fcoords[5][2] - static_cast<Real>(1)) < 1e-4);

  mol.atomPositions3d().clear();
  EXPECT_TRUE(CrystalTools::setFractionalCoordinates(mol, fcoords));
  Array<Vector3> ccoords = mol.atomPositions3d();
  for (int i = 0; i < 6; ++i) {
    for (int j = 0; j < 3; ++j) {
      EXPECT_FLOAT_EQ(static_cast<float>(ccoords_ref[i][j]),
                      static_cast<float>(ccoords[i][j]))
          << " (i=" << i << "j=" << j << ")";
    }
  }
}