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()); }
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()); }
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()); }
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()); }
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)); }
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()); }
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 << ")"; } } }