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()); }
TEST(HydrogenToolsTest, valencyAdjustment_O) { Molecule mol; Atom O = mol.addAtom(8); int expectedAdjustment = 2; for (int i = 0; i < 8; ++i, --expectedAdjustment) { EXPECT_EQ(expectedAdjustment, HydrogenTools::valencyAdjustment(O)); mol.addBond(mol.addAtom(1), O, 1); } }
TEST(HydrogenToolsTest, valencyAdjustment_C) { Molecule mol; Atom C = mol.addAtom(6); int expectedAdjustment = 4; for (int i = 0; i < 8; ++i, --expectedAdjustment) { EXPECT_EQ(expectedAdjustment, HydrogenTools::valencyAdjustment(C)); mol.addBond(mol.addAtom(1), C, 1); } }
TEST(HydrogenToolsTest, valencyAdjustment_N) { Molecule mol; Atom N = mol.addAtom(7); int expectedAdjustment = 3; for (int i = 0; i < 8; ++i, --expectedAdjustment) { if (i == 4) // neutral N can have 3 or 5 bonds in our valence model. expectedAdjustment += 2; EXPECT_EQ(expectedAdjustment, HydrogenTools::valencyAdjustment(N)); mol.addBond(mol.addAtom(1), N, 1); } }
TEST(RingPerceiverTest, ethanol) { Molecule molecule; molecule.addAtom(6); molecule.addAtom(6); molecule.addAtom(8); molecule.addBond(molecule.atom(0), molecule.atom(1), 1); molecule.addBond(molecule.atom(1), molecule.atom(2), 1); RingPerceiver perceiver(&molecule); std::vector<std::vector<size_t>> rings = perceiver.rings(); EXPECT_EQ(rings.size(), static_cast<size_t>(0)); }
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(UnitCellTest, wrapAtomsToUnitCell) { 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)); for (int i = 0; i < 10; ++i) mol.addAtom(1).setPosition3d(Vector3::Zero()); Array<Vector3> fcoords; for (int i = 0; i < 10; ++i) { fcoords.push_back(Vector3(static_cast<Real>(i + i / 10.), static_cast<Real>(i + 2 * i / 10.), static_cast<Real>(i + 3 * i / 10.))); } EXPECT_TRUE(CrystalTools::setFractionalCoordinates(mol, fcoords)); EXPECT_TRUE(CrystalTools::wrapAtomsToUnitCell(mol)); fcoords.clear(); EXPECT_TRUE(CrystalTools::fractionalCoordinates(mol, fcoords)); for (std::vector<Vector3>::const_iterator it = fcoords.begin(), itEnd = fcoords.end(); it != itEnd; ++it) { EXPECT_GE(it->x(), static_cast<Real>(0.0)); EXPECT_LE(it->x(), static_cast<Real>(1.0)); EXPECT_GE(it->y(), static_cast<Real>(0.0)); EXPECT_LE(it->y(), static_cast<Real>(1.0)); EXPECT_GE(it->z(), static_cast<Real>(0.0)); EXPECT_LE(it->z(), static_cast<Real>(1.0)); } }
void FileParser::readORCA() { std::string tempString; QRegExp rx("", Qt::CaseInsensitive, QRegExp::RegExp2); while (1) { Molecule *molecule = new Molecule(); // GOAL TO MATCH - // --------------------------------- // CARTESIAN COORDINATES (ANGSTROEM) // --------------------------------- // N 1.641610 -0.243155 1.175097 // C 2.719261 -0.702755 0.549942 // C 2.620982 -0.629038 -0.867321 // H 3.602940 -1.075919 1.062705 // N 1.452945 -0.127890 -1.286957 // H 3.405318 -0.967835 -1.537305 // N -1.204954 0.202179 1.259883 getline(infile, tempString); while (tempString.find("CARTESIAN COORDINATES (ANGSTROEM)") == string::npos && infile.eof() == false) { getline(infile, tempString); } if (infile.eof()) { break; } #ifdef QT_DEBUG std::cout << "readORCA: 'CARTESIAN COORDINATES (ANGSTROEM)' found.\n"; #endif // Geometry is reported in Angstroms myUnits = Angstrom; // Read in atom information rx.setPattern("(?:\\s*)(\\w+)(?:\\s+)(-?\\d+\\.\\d+)(?:\\s+)(-?\\d+\\.\\d+)(?:\\s+)(-?\\d+" "\\.\\d+)(?:\\s*)"); while (1) { getline(infile, tempString); if (rx.exactMatch(tempString.c_str()) == true) { AtomEntry *atom = new AtomEntry; atom->Label = rx.cap(1); atom->x = rx.cap(2).toDouble(); atom->y = rx.cap(3).toDouble(); atom->z = rx.cap(4).toDouble(); molecule->addAtom(atom); #ifdef QT_DEBUG std::cout << std::setw(5) << atom->Label.toStdString() << " " << std::setw(16) << std::setprecision(10) << atom->x << " " << std::setw(16) << std::setprecision(10) << atom->y << " " << std::setw(16) << std::setprecision(10) << atom->z << std::endl; #endif } else if (tempString.size() == 0) { myMoleculeList.push_back(molecule); break; } } } }
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)); }
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_F(MoleculeTest, perceiveBondsSimple) { Molecule molecule; Atom o1 = molecule.addAtom(8); Atom h2 = molecule.addAtom(1); Atom h3 = molecule.addAtom(1); o1.setPosition3d(Vector3(0, 0, 0)); h2.setPosition3d(Vector3(0.6, -0.5, 0)); h3.setPosition3d(Vector3(-0.6, -0.5, 0)); EXPECT_EQ(molecule.bondCount(), 0); molecule.perceiveBondsSimple(); EXPECT_EQ(molecule.bondCount(), 2); EXPECT_TRUE(molecule.bond(o1, h2).isValid()); EXPECT_TRUE(molecule.bond(o1, h3).isValid()); EXPECT_FALSE(molecule.bond(h2, h3).isValid()); }
TEST_F(MoleculeTest, findBond) { Molecule molecule; Atom a1 = molecule.addAtom(5); Atom a2 = molecule.addAtom(6); Bond b = molecule.addBond(a1, a2, 1); EXPECT_EQ(molecule.bond(a1, a2).index(), b.index()); EXPECT_EQ(molecule.bond(a2, a1).index(), b.index()); Array<Bond> bonds = molecule.bonds(a1); EXPECT_EQ(bonds.size(), 1); Atom a3 = molecule.addAtom(7); molecule.addBond(a1, a3, 1); EXPECT_EQ(molecule.bonds(a1).size(), 2); EXPECT_EQ(molecule.bonds(a3).size(), 1); }
TEST_F(MoleculeTest, addBond) { Molecule molecule; EXPECT_EQ(molecule.bondCount(), static_cast<Index>(0)); Atom a = molecule.addAtom(1); Atom b = molecule.addAtom(1); Bond bondAB = molecule.addBond(a, b); EXPECT_TRUE(bondAB.isValid()); EXPECT_EQ(bondAB.molecule(), &molecule); EXPECT_EQ(molecule.bondCount(), static_cast<Index>(1)); EXPECT_EQ(bondAB.index(), static_cast<Index>(0)); EXPECT_EQ(bondAB.atom1().index(), a.index()); EXPECT_EQ(bondAB.atom2().index(), b.index()); EXPECT_EQ(bondAB.order(), static_cast<unsigned char>(1)); Atom c = molecule.addAtom(1); Bond bondBC = molecule.addBond(b, c, 2); EXPECT_TRUE(bondBC.isValid()); EXPECT_EQ(molecule.bondCount(), static_cast<Index>(2)); EXPECT_EQ(bondBC.index(), static_cast<Index>(1)); EXPECT_EQ(bondBC.order(), static_cast<unsigned char>(2)); // try to lookup nonexistant bond Bond bond = molecule.bond(a, c); EXPECT_FALSE(bond.isValid()); // try to lookup bond between a and b bond = molecule.bond(a, b); EXPECT_TRUE(bond.isValid()); EXPECT_EQ(bond.molecule(), &molecule); EXPECT_EQ(bond.atom1().index(), a.index()); EXPECT_EQ(bond.atom2().index(), b.index()); // try to lookup bond between b and c by index bond = molecule.bond(1); EXPECT_TRUE(bond.isValid()); EXPECT_EQ(bond.molecule(), &molecule); EXPECT_EQ(bond.atom1().index(), b.index()); EXPECT_EQ(bond.atom2().index(), c.index()); }
TEST(RingPerceiverTest, benzene) { Molecule molecule; molecule.addAtom(6); molecule.addAtom(6); molecule.addAtom(6); molecule.addAtom(6); molecule.addAtom(6); molecule.addAtom(6); molecule.addBond(molecule.atom(0), molecule.atom(1), 1); molecule.addBond(molecule.atom(1), molecule.atom(2), 2); molecule.addBond(molecule.atom(2), molecule.atom(3), 1); molecule.addBond(molecule.atom(3), molecule.atom(4), 2); molecule.addBond(molecule.atom(4), molecule.atom(5), 1); molecule.addBond(molecule.atom(5), molecule.atom(0), 2); RingPerceiver perceiver(&molecule); std::vector<std::vector<size_t>> rings = perceiver.rings(); EXPECT_EQ(rings.size(), static_cast<size_t>(1)); EXPECT_EQ(rings[0].size(), static_cast<size_t>(6)); }
bool GaussianOutputFile::readInputOrientationGeometries(vector<Molecule>& molecules) { Atom atom; Molecule mol; string line; bool ok; ok = false; int i; i = 0; while(isStringInFile("Input orientation")) { // if(isStringInFile("Input orientation")) // { /* * Jumping four lines that contains the orientation header * */ for(size_t i = 0; i < 4; i++) line = readLine(); /* * Reading the atoms * */ line = readLine(); while(line.find("-------") == string::npos) { atom.clear(); atom.setName(line.substr(13,16)); atom.setX(atof(line.substr(33,46).c_str())); atom.setY(atof(line.substr(47,59).c_str())); atom.setZ(atof(line.substr(60,70).c_str())); mol.addAtom(atom); line = readLine(); } molecules.push_back(mol); mol.clear(); ok = true; // } } if(ok) return true; else return false; }
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); } } }
void MoleculeTest::removeAtom() { // Should now to two atoms in the Molecule with ids 0 and 1. Atom *a = m_molecule->atom(1); m_molecule->removeAtom(a); QVERIFY(m_molecule->numAtoms() == 1); m_molecule->removeAtom(0ul); QVERIFY(m_molecule->numAtoms() == 0); // Check behavior of removing an atom that is owned by a different // molecule. Should not crash. Molecule mol; a = mol.addAtom(); m_molecule->removeAtom(a); }
bool AbbreviationExpander::tryCarbonChain (TokenChain &tokens, size_t &offset, Molecule &m, AttPoint &attach_to) { if (attach_to.order != 1) return false; Token &cur = tokens[offset]; if (cur.type != Token::Element) return false; if (cur.multiplier == 1 || cur.index != ELEM_C || offset + 1 == tokens.size()) return false; Token &next = tokens[offset + 1]; // Check CnH(2n+1), CnH2n pattern if (next.multiplier > 1 && next.index == ELEM_H) { bool tail; if (next.multiplier == cur.multiplier * 2) { // Intermediate carbon chain tail = false; } else if (next.multiplier == cur.multiplier * 2 + 1) { // Terminator carbon chain tail = true; } else return false; for (int i = 0; i < cur.multiplier; i++) { int idx = m.addAtom(ELEM_C); attachBond(m, attach_to, idx); attach_to = AttPoint(idx, 1); } if (tail) attach_to = AttPoint(-1, 0); offset += 2; return true; } return false; }
TEST(HydrogenToolsTest, adjustHydrogens_adjustments) { for (int i = 0; i < 3; ++i) { HydrogenTools::Adjustment adjustment; std::string expectedFormula; switch (i) { case 0: adjustment = HydrogenTools::Add; expectedFormula = "C2H14"; break; case 1: adjustment = HydrogenTools::Remove; expectedFormula = "C2H5"; break; case 2: adjustment = HydrogenTools::AddAndRemove; expectedFormula = "C2H8"; break; } Molecule mol; Atom C1 = mol.addAtom(6); // Overbond this atom mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); mol.addBond(C1, mol.addAtom(1)); Atom C2 = mol.addAtom(6); // Underbond this atom mol.addBond(C2, mol.addAtom(1)); EXPECT_EQ(std::string("C2H11"), mol.formula()); HydrogenTools::adjustHydrogens(mol, adjustment); EXPECT_EQ(expectedFormula, mol.formula()); } }
bool GaussianOutputFile::readFirstInputOrientationGeometry(Molecule& mol) { Atom atom; string line; if(!rewind()) return false; if(isStringInFile("Input orientation")) { /* * Jumping four lines that contains the orientation header * */ for(size_t i = 0; i < 4; i++) line = readLine(); /* * Reading the atoms * */ line = readLine(); while(line.find("-------") == string::npos) { atom.clear(); atom.setName(line.substr(13,16)); atom.setX(atof(line.substr(33,46).c_str())); atom.setY(atof(line.substr(47,59).c_str())); atom.setZ(atof(line.substr(60,70).c_str())); mol.addAtom(atom); line = readLine(); } } else return false; return true; }
void MoleculeLayoutGraphSmart::saveDebug () { int i; Molecule mol; QS_DEF(Array<int>, mapping); mapping.clear_resize(vertexEnd()); for (i = vertexBegin(); i < vertexEnd(); i = vertexNext(i)) { if (getVertexType(i) == ELEMENT_NOT_DRAWN) continue; mapping[i] = mol.addAtom(ELEM_C); mol.setAtomXyz(mapping[i], getPos(i).x, getPos(i).y, 0); } for (i = edgeBegin(); i < edgeEnd(); i = edgeNext(i)) { if (getEdgeType(i) == ELEMENT_NOT_DRAWN) continue; const Edge &edge = getEdge(i); mol.addBond(mapping[edge.beg], mapping[edge.end], BOND_SINGLE); } static int id = 0; char out_name[100]; sprintf_s(out_name, "D:\\mf\\draw\\trace_my\\%03d.mol", id); FileOutput fo(out_name); MolfileSaver ms(fo); ms.saveMolecule(mol); id++; }
void CmfLoader::loadMolecule (Molecule &mol) { int code; mol.clear(); QS_DEF(Array<int>, cycle_numbers); QS_DEF(Array<int>, atom_stack); _atoms.clear(); _bonds.clear(); _pseudo_labels.clear(); _attachments.clear(); cycle_numbers.clear(); atom_stack.clear(); bool first_atom = true; if (!_getNextCode(code)) return; bool has_ext_part = false; /* Main loop */ do { _BondDesc *bond = 0; if (code > CMF_ALPHABET_SIZE) throw Error("unexpected code"); if (code == CMF_TERMINATOR) break; if (code == CMF_EXT) { has_ext_part = true; // Ext part has to be read till CMF_TERMINATOR break; } if (!first_atom) { int number; while (_readCycleNumber(code, number)) { while (cycle_numbers.size() <= number) cycle_numbers.push(-1); if (cycle_numbers[number] >= 0) throw Error("cycle #%d already in use", number); cycle_numbers[number] = atom_stack.top(); if (!_getNextCode(code)) break; } } if (code == CMF_SEPARATOR) { atom_stack.pop(); first_atom = true; if (!_getNextCode(code)) break; continue; } if (code == CMF_OPEN_BRACKET) { atom_stack.push(atom_stack.top()); if (!_getNextCode(code)) break; continue; } if (code == CMF_CLOSE_BRACKET) { atom_stack.pop(); if (!_getNextCode(code)) break; continue; } if (!first_atom) { bond = &_bonds.push(); bond->beg = atom_stack.top(); } if (bond != 0) { _readBond(code, *bond); int number; if (_readCycleNumber(code, number)) { if (cycle_numbers[number] < 0) throw Error("bad cycle number after bond symbol"); bond->end = cycle_numbers[number]; cycle_numbers[number] = -1; if (!_getNextCode(code)) break; continue; } } _AtomDesc &atom = _atoms.push(); if (!first_atom) atom_stack.pop(); atom_stack.push(_atoms.size() - 1); first_atom = false; if (bond != 0) bond->end = _atoms.size() - 1; memset(&atom, 0, sizeof(_AtomDesc)); atom.hydrogens = -1; atom.valence = -1; atom.pseudo_atom_idx = -1; atom.rsite = false; if (code > 0 && (code < ELEM_MAX || code == CMF_PSEUDOATOM || code == CMF_RSITE || code == CMF_RSITE_EXT)) { if (!_readAtom(code, atom, _atoms.size() - 1)) break; continue; } if (!_getNextCode(code)) break; } while (true); // if have internal decoder, finish it /* if (_decoder_obj.get() != 0) _decoder_obj->finish(); */ /* Reading finished, filling molecule */ int i; for (i = 0; i < _atoms.size(); i++) { mol.addAtom(_atoms[i].label); if (_atoms[i].pseudo_atom_idx >= 0) mol.setPseudoAtom(i, _pseudo_labels.at(_atoms[i].pseudo_atom_idx)); if (_atoms[i].rsite_bits > 0) mol.setRSiteBits(i, _atoms[i].rsite_bits); mol.setAtomCharge(i, _atoms[i].charge); mol.setAtomIsotope(i, _atoms[i].isotope); if (_atoms[i].hydrogens >= 0) mol.setImplicitH(i, _atoms[i].hydrogens); mol.setAtomRadical(i, _atoms[i].radical); if (_atoms[i].highlighted) mol.highlightAtom(i); } for (i = 0; i < _bonds.size(); i++) { int type = _bonds[i].type; int beg = _bonds[i].beg; int end = _bonds[i].end; int tmp; if (_bonds[i].swap) __swap(beg, end, tmp); int idx = mol.addBond_Silent(beg, end, type); if (_bonds[i].in_ring) mol.setEdgeTopology(idx, TOPOLOGY_RING); else mol.setEdgeTopology(idx, TOPOLOGY_CHAIN); if (_bonds[i].direction != 0) mol.setBondDirection(idx, _bonds[i].direction); if (_bonds[i].highlighted) mol.highlightBond(idx); } for (i = 0; i < _attachments.size(); i++) mol.addAttachmentPoint(_attachments[i].index, _attachments[i].atom); mol.validateEdgeTopologies(); if (has_ext_part) _readExtSection(mol); if (atom_flags != 0) { atom_flags->clear(); for (i = 0; i < _atoms.size(); i++) atom_flags->push(_atoms[i].flags); } if (bond_flags != 0) { bond_flags->clear(); for (i = 0; i < _bonds.size(); i++) bond_flags->push(_bonds[i].flags); } if (!skip_cistrans) { for (i = 0; i < _bonds.size(); i++) { if (_bonds[i].cis_trans != 0) { int parity = _bonds[i].cis_trans; if (parity > 0) mol.cis_trans.setParity(i, _bonds[i].cis_trans); else mol.cis_trans.ignore(i); mol.cis_trans.restoreSubstituents(i); } } } if (!skip_valence) { for (i = 0; i < _atoms.size(); i++) { if (_atoms[i].valence >= 0) mol.setValence(i, _atoms[i].valence); } } if (!skip_stereocenters) { for (i = 0; i < _atoms.size(); i++) { if (_atoms[i].stereo_type != 0) mol.stereocenters.add(i, _atoms[i].stereo_type, _atoms[i].stereo_group, _atoms[i].stereo_invert_pyramid); } } for (i = 0; i < _atoms.size(); i++) { if (_atoms[i].allene_stereo_parity != 0) { int left, right, subst[4]; bool pure_h[4]; int parity = _atoms[i].allene_stereo_parity; int tmp; if (!MoleculeAlleneStereo::possibleCenter(mol, i, left, right, subst, pure_h)) throw Error("invalid molecule allene stereo marker"); if (subst[1] != -1 && subst[1] < subst[0]) __swap(subst[1], subst[0], tmp); if (subst[3] != -1 && subst[3] < subst[2]) __swap(subst[3], subst[2], tmp); if (pure_h[0]) { __swap(subst[1], subst[0], tmp); parity = 3 - parity; } if (pure_h[2]) { __swap(subst[2], subst[3], tmp); parity = 3 - parity; } mol.allene_stereo.add(i, left, right, subst, parity); } } // for loadXyz() _mol = &mol; // Check if atom mapping was used if (has_mapping) { // Compute inv_atom_mapping_to_restore inv_atom_mapping_to_restore.clear_resize(atom_mapping_to_restore.size()); for (int i = 0; i < atom_mapping_to_restore.size(); i++) inv_atom_mapping_to_restore[atom_mapping_to_restore[i]] = i; // Compute inv_bond_mapping_to_restore inv_bond_mapping_to_restore.clear_resize(bond_mapping_to_restore.size()); for (int i = 0; i < bond_mapping_to_restore.size(); i++) inv_bond_mapping_to_restore[bond_mapping_to_restore[i]] = i; QS_DEF(Molecule, tmp); tmp.makeEdgeSubmolecule(mol, atom_mapping_to_restore, bond_mapping_to_restore, NULL); mol.clone(tmp, NULL, NULL); } }
void FileParser::readQchem31() { std::string tempString; QRegExp rx("", Qt::CaseInsensitive, QRegExp::RegExp2); while (1) { Molecule *molecule = new Molecule(); // GOAL TO MATCH - // Optimization Cycle: 1 // // Coordinates (Angstroms) // ATOM X Y Z // 1 H 6.264255 -1.214463 0.001562 // 2 N 0.992577 0.405079 -0.000713 // 3 C 3.640581 0.699759 -0.000285 // 4 H 5.692879 1.292403 -0.000233 // 5 N 1.103169 -1.927005 0.000687 // 6 C -3.986741 -0.820146 0.000147 // 7 C -4.603474 0.385503 0.001374 // 8 N 4.158387 -1.540250 0.001279 // 9 C 5.256835 -0.819403 0.001066 // 10 H -5.684216 0.487120 0.002358 // 11 N 2.932990 1.843103 -0.001138 // 12 H -4.383326 2.467645 0.002362 // 13 H 0.959209 2.465806 -0.001902 // 14 H 1.658401 -2.773307 0.001857 // 15 C 1.728674 -0.733977 0.000168 // 16 N 5.011372 0.541687 0.000124 // 17 H -4.452049 -2.729414 0.878462 // 18 C 3.136252 -0.602051 0.000394 // 19 H -0.845397 0.417252 -0.001289 // 20 H -4.453040 -2.728702 -0.879157 // 21 H -5.802705 -1.976283 0.000726 // 22 C -4.719039 -2.131115 0.000042 // 23 C 1.619390 1.601695 -0.001312 // 24 H 0.079495 -1.982939 0.000872 // 25 N -3.902148 1.574898 0.001480 // 26 C -2.511246 1.648434 0.000286 // 27 O -1.910441 2.717732 0.000430 // 28 N -1.895228 0.410754 -0.001007 // 29 C -2.522920 -0.833703 -0.001123 // 30 O -1.848461 -1.874351 -0.002325 getline(infile, tempString); while (tempString.find("Optimization Cycle:") == string::npos && infile.eof() == false) { getline(infile, tempString); } if (infile.eof()) { break; } #ifdef QT_DEBUG std::cout << "readQchem31: 'Optimization Cycle:' found.\n"; #endif getline(infile, tempString); getline(infile, tempString); getline(infile, tempString); // qchem31 is reported in Angstroms myUnits = Angstrom; // Read in atom information rx.setPattern("(?:\\s*)(?:\\d+)(?:\\s+)(\\w+)(?:\\s+)(-?\\d+\\.\\d+)(?:\\s+)(-?\\d+\\.\\d+)" "(?:\\s+)(-?\\d+\\.\\d+)"); while (1) { getline(infile, tempString); if (rx.exactMatch(tempString.c_str()) == true) { AtomEntry *atom = new AtomEntry; atom->Label = rx.cap(1); atom->x = rx.cap(2).toDouble(); atom->y = rx.cap(3).toDouble(); atom->z = rx.cap(4).toDouble(); molecule->addAtom(atom); #ifdef QT_DEBUG std::cout << std::setw(5) << atom->Label.toStdString() << " " << std::setw(16) << std::setprecision(10) << atom->x << " " << std::setw(16) << std::setprecision(10) << atom->y << " " << std::setw(16) << std::setprecision(10) << atom->z << std::endl; #endif } else { myMoleculeList.push_back(molecule); break; } } } }
TEST(InputGeneratorWidgetTest, exercise) { // Fake a QApplication -- needed to instantiate widgets. int argc = 1; char argName[] = "FakeApp.exe"; char *argv[2] = {argName, NULL}; QApplication app(argc, argv); Q_UNUSED(app); // Setup the widget InputGeneratorWidget widget; QString scriptFilePath(AVOGADRO_DATA "/tests/avogadro/scripts/inputgeneratortest.py"); widget.setInputGeneratorScript(scriptFilePath); Molecule mol; mol.addAtom(6).setPosition3d(Avogadro::Vector3(1, 1, 1)); mol.addAtom(1).setPosition3d(Avogadro::Vector3(2, 3, 4)); mol.addAtom(8).setPosition3d(Avogadro::Vector3(-2, 3, -4)); widget.setMolecule(&mol); // Check that the generator is configured properly. EXPECT_EQ(widget.inputGenerator().displayName().toStdString(), std::string("Input Generator Test")); // Verify that appropriate widgets are produced for each parameter type: EXPECT_TRUE(widget.findChild<QComboBox*>("Test StringList") != NULL); EXPECT_TRUE(widget.findChild<QLineEdit*>("Test String") != NULL); EXPECT_TRUE(widget.findChild<QSpinBox*>("Test Integer") != NULL); EXPECT_TRUE(widget.findChild<QCheckBox*>("Test Boolean") != NULL); EXPECT_TRUE(widget.findChild<FileBrowseWidget*>("Test FilePath") != NULL); // Set a test filepath FileBrowseWidget *testFilePathWidget( widget.findChild<FileBrowseWidget*>("Test FilePath")); QString testFilePath(AVOGADRO_DATA "/data/ethane.cml"); testFilePathWidget->setFileName(testFilePath); // Show the widget so that events are processed widget.show(); // Clear out the event queue so that the text edits are updated: flushEvents(); // Check the contents of the filepath file: QTextEdit *filePathEdit = widget.findChild<QTextEdit*>("job.testFilePath"); QFile testFile(testFilePath); EXPECT_TRUE(testFile.open(QFile::ReadOnly | QFile::Text)); QByteArray refData(testFile.readAll()); EXPECT_EQ(std::string(refData.constData()), filePathEdit->document()->toPlainText().toStdString()); // Check the coords: QTextEdit *coordsEdit = widget.findChild<QTextEdit*>("job.coords"); QString coords(coordsEdit->document()->toPlainText()); EXPECT_TRUE(coords.contains( "C 1.000000 0 1.000000 1 1.000000 1 Carbon")); EXPECT_TRUE(coords.contains( "H 2.000000 0 3.000000 1 4.000000 1 Hydrogen")); EXPECT_TRUE(coords.contains( "O -2.000000 0 3.000000 1 -4.000000 1 Oxygen")); // Test the default reset -- trigger a reset, then verify that testFilePath // is cleared (we set it earlier) QPushButton *defaultsButton(widget.findChild<QPushButton*>("defaultsButton")); defaultsButton->click(); flushEvents(); EXPECT_TRUE(testFilePathWidget->fileName().isEmpty()); EXPECT_EQ(filePathEdit->document()->toPlainText().toStdString(), std::string("Reference file '' does not exist.")); // Test the autogenerated title: QLineEdit *titleEdit = widget.findChild<QLineEdit*>("Title"); EXPECT_EQ(titleEdit->placeholderText().toStdString(), std::string("CHO | Equilibrium Geometry | B3LYP/6-31G(d)")); }
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 << ")"; } } }
bool AbbreviationExpander::tryExpandToken (TokenChain &tokens, size_t &offset, Molecule &m, AttPoint &attach_to) { Token &cur = tokens[offset]; if (cur.multiplier != 1) return false; Array<int> connection_points; if (cur.type == Token::Element) { if (cur.index == ELEM_H) { offset++; attach_to = AttPoint(-1, 0); return true; } int added = m.addAtom(cur.index); // Get the number of bonds to connect int valence, hyd; int conn = attach_to.order; if (offset + 1 < tokens.size()) { Token &next = tokens[offset + 1]; conn += next.multiplier; } if (!Element::calcValence(cur.index, 0, 0, conn, valence, hyd, false)) { // Ignore next atom // Appear in the OH3C case when H3 is belong to C conn = attach_to.order; if (!Element::calcValence(cur.index, 0, 0, conn, valence, hyd, false)) return false; } for (int i = 0; i < hyd + conn; i++) connection_points.push(added); } else if (cur.type == Token::Pattern) { // Add pattern BufferScanner scanner(abbreviations[cur.index]->expansion.c_str()); SmilesLoader loader(scanner); Molecule abbr; loader.loadMolecule(abbr); Array<int> mapping; Array<int> rsites; m.mergeWithMolecule(abbr, &mapping); for (int v = abbr.vertexBegin(); v != abbr.vertexEnd(); v = abbr.vertexNext(v)) { int mapped = mapping[v]; if (m.isRSite(mapped)) { dword bits = m.getRSiteBits(mapped); int id1 = bitGetOneHOIndex(bits); int id2 = bitGetOneHOIndex(bits); if (id1 != id2) throw Exception("Invalid abbreviations specification: %s", abbreviations[cur.index]->expansion.c_str()); if (id1 != 0) id1--; // R == R1 const Vertex &vertex = m.getVertex(mapped); int nei = vertex.neiBegin(); connection_points.expandFill(id1 + 1, -1); connection_points[id1] = vertex.neiVertex(nei); // Point connected to the RSite rsites.push(mapped); } } m.removeAtoms(rsites); } else return false; bool rollback = false; int atom_bound = m.vertexCount(); size_t offset2 = offset + 1; attachBond(m, attach_to, connection_points[0]); int i = attach_to.order; while (i < connection_points.size() - 1 && !rollback) { if (offset2 >= tokens.size()) { // If we are at the end then there can be an implicit double bond // Example: -CH2CH= // When we read C H there are no more tokens break; } Token &next = tokens[offset2]; for (int j = 0; j < next.multiplier; j++) { if (i >= connection_points.size()) { rollback = true; break; } if (next.type == Token::Branch) { AttPoint point(connection_points[i], 1); if (!expandParsedTokensWithRev(next.branch, m, point) || point.index != -1) { rollback = true; break; } } else { TokenChain chain; chain.push_back(next); chain[0].multiplier = 1; size_t local_offset = 0; AttPoint point(connection_points[i], 1); if (!tryExpandToken(chain, local_offset, m, point) || point.index != -1) { rollback = true; break; } } i++; } offset2++; } if (i > connection_points.size()) rollback = true; if (!rollback) { if (i == connection_points.size()) { // This is terminal attach_to = AttPoint(-1, 0); } else if (i == connection_points.size() - 1) attach_to = AttPoint(connection_points[i], 1); // Last attachment point else { // Number of tokens are incomlete means that there are double bonds after attach_to = AttPoint(connection_points[i], connection_points.size() - i); } } if (rollback) { // Rollback Array<int> new_atoms; for (int v = m.vertexBegin(); v != m.vertexEnd(); v = m.vertexNext(v)) if (v >= atom_bound) new_atoms.push(v); m.removeAtoms(new_atoms); return false; } offset = offset2; return true; }
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()); }
void IndigoInchi::parseInchiOutput (const inchi_OutputStruct &inchi_output, Molecule &mol) { mol.clear(); Array<int> atom_indices; atom_indices.clear(); // Add atoms for (AT_NUM i = 0; i < inchi_output.num_atoms; i ++) { const inchi_Atom &inchi_atom = inchi_output.atom[i]; int idx = mol.addAtom(Element::fromString(inchi_atom.elname)); atom_indices.push(idx); } // Add bonds for (AT_NUM i = 0; i < inchi_output.num_atoms; i ++) { const inchi_Atom &inchi_atom = inchi_output.atom[i]; for (AT_NUM bi = 0; bi < inchi_atom.num_bonds; bi++) { AT_NUM nei = inchi_atom.neighbor[bi]; if (i > nei) // Add bond only once continue; int bond_order = inchi_atom.bond_type[bi]; if (bond_order == INCHI_BOND_TYPE_NONE) throw Molecule::Error("Indigo-InChI: NONE-typed bonds are not supported"); if (bond_order >= INCHI_BOND_TYPE_ALTERN) throw Molecule::Error("Indigo-InChI: ALTERN-typed bonds are not supported"); int bond = mol.addBond(atom_indices[i], atom_indices[nei], bond_order); } } // Add Hydrogen isotope atoms at the end to preserver // the same atom ordering for (AT_NUM i = 0; i < inchi_output.num_atoms; i ++) { const inchi_Atom &inchi_atom = inchi_output.atom[i]; int root_atom = atom_indices[i]; for (int iso = 1; iso <= NUM_H_ISOTOPES; iso++) { int count = inchi_atom.num_iso_H[iso]; while (count-- > 0) { int h = mol.addAtom(ELEM_H); mol.setAtomIsotope(h, iso); mol.addBond(root_atom, h, BOND_SINGLE); } } } // Set atom charges, radicals and etc. for (int i = 0; i < inchi_output.num_atoms; i++) { const inchi_Atom &inchi_atom = inchi_output.atom[i]; int idx = atom_indices[i]; mol.setAtomCharge(idx, inchi_atom.charge); if (inchi_atom.isotopic_mass) mol.setAtomIsotope(idx, inchi_atom.isotopic_mass); if (inchi_atom.radical) mol.setAtomRadical(idx, inchi_atom.radical); mol.setImplicitH(idx, inchi_atom.num_iso_H[0]); } neutralizeV5Nitrogen(mol); // Process stereoconfiguration for (int i = 0; i < inchi_output.num_stereo0D; i++) { inchi_Stereo0D &stereo0D = inchi_output.stereo0D[i]; if (stereo0D.type == INCHI_StereoType_DoubleBond) { if (stereo0D.parity != INCHI_PARITY_ODD && stereo0D.parity != INCHI_PARITY_EVEN) continue; int bond = mol.findEdgeIndex(stereo0D.neighbor[1], stereo0D.neighbor[2]); bool valid = mol.cis_trans.registerBondAndSubstituents(bond); if (!valid) throw IndigoError("Indigo-InChI: Unsupported cis-trans configuration for " "bond %d (atoms %d-%d-%d-%d)", bond, stereo0D.neighbor[0], stereo0D.neighbor[1], stereo0D.neighbor[2], stereo0D.neighbor[3]); int vb, ve; const Edge &edge = mol.getEdge(bond); if (edge.beg == stereo0D.neighbor[1]) { vb = stereo0D.neighbor[0]; ve = stereo0D.neighbor[3]; } else if (edge.beg == stereo0D.neighbor[2]) { vb = stereo0D.neighbor[3]; ve = stereo0D.neighbor[0]; } else throw IndigoError("Indigo-InChI: Internal error: cannot find cis-trans bond indices"); const int *subst = mol.cis_trans.getSubstituents(bond); bool same_side; if (subst[0] == vb) same_side = (subst[2] == ve); else if (subst[1] == vb) same_side = (subst[3] == ve); else throw IndigoError("Indigo-InChI: Internal error: cannot find cis-trans bond indices (#2)"); if (stereo0D.parity == INCHI_PARITY_EVEN) same_side = !same_side; mol.cis_trans.setParity(bond, same_side ? MoleculeCisTrans::CIS : MoleculeCisTrans::TRANS); } else if (stereo0D.type == INCHI_StereoType_Tetrahedral) { if (stereo0D.parity != INCHI_PARITY_ODD && stereo0D.parity != INCHI_PARITY_EVEN) continue; int pyramid[4]; if (stereo0D.central_atom == stereo0D.neighbor[0]) { pyramid[1] = stereo0D.neighbor[1]; pyramid[0] = stereo0D.neighbor[2]; pyramid[2] = stereo0D.neighbor[3]; pyramid[3] = -1; } else { pyramid[0] = stereo0D.neighbor[0]; pyramid[1] = stereo0D.neighbor[1]; pyramid[2] = stereo0D.neighbor[2]; pyramid[3] = stereo0D.neighbor[3]; } if (stereo0D.parity == INCHI_PARITY_ODD) std::swap(pyramid[0], pyramid[1]); mol.stereocenters.add(stereo0D.central_atom, MoleculeStereocenters::ATOM_ABS, 0, pyramid); } } }