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(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()); }
/* * Allocate arrays. */ void G1MSD::setup() { // Get number of molecules of this species in the System. nMolecule_ = system().nMolecule(speciesId_); int nratoms; nratoms = nMolecule_*nAtom_; // Allocate arrays of position Vectors and shifts truePositions_.allocate(nratoms); oldPositions_.allocate(nratoms); shifts_.allocate(nratoms); // Initialize the AutoCorrArray object accumulator_.setParam(nratoms, capacity_); // Store initial positions, and set initial shift vectors. Vector r; IntVector zero(0); Molecule* moleculePtr; int iatom = 0; for (int i = 0; i < nMolecule_; ++i) { moleculePtr = &system().molecule(speciesId_, i); for (int j = 0 ; j < nAtom_; j++) { r = moleculePtr->atom(j).position(); system().boundary().shift(r); oldPositions_[iatom] = r; shifts_[iatom] = zero; iatom++; } } }
/* * Initialize all Angle objects for Molecules of one Species. * * This functions assigns pointers to Atoms and angle types ids within a * contiguous block of Angle objects, and sets a pointer in each Molecule * to the first Angle in the associated block. */ void Simulation::initializeSpeciesAngles(int iSpecies) { if (nAngleType_ <= 0) { UTIL_THROW("nAngleType must be positive"); } Species* speciesPtr = 0; Molecule *moleculePtr = 0; Angle *anglePtr = 0; Atom *firstAtomPtr, *atom0Ptr, *atom1Ptr, *atom2Ptr; int iMol, iAngle, atom0Id, atom1Id, atom2Id, type; int capacity, nAngle; speciesPtr = &species(iSpecies); capacity = speciesPtr->capacity(); nAngle = speciesPtr->nAngle(); // Initialize pointers before loop moleculePtr = &molecules_[firstMoleculeIds_[iSpecies]]; anglePtr = &angles_[firstAngleIds_[iSpecies]]; // Loop over molecules in Species for (iMol = 0; iMol < capacity; ++iMol) { firstAtomPtr = &(moleculePtr->atom(0)); moleculePtr->setFirstAngle(*anglePtr); moleculePtr->setNAngle(nAngle); if (nAngle > 0) { // Create angles for a molecule for (iAngle = 0; iAngle < nAngle; ++iAngle) { // Get pointers to atoms spanning the angle and angle type atom0Id = speciesPtr->speciesAngle(iAngle).atomId(0); atom1Id = speciesPtr->speciesAngle(iAngle).atomId(1); atom2Id = speciesPtr->speciesAngle(iAngle).atomId(2); type = speciesPtr->speciesAngle(iAngle).typeId(); atom0Ptr = firstAtomPtr + atom0Id; atom1Ptr = firstAtomPtr + atom1Id; atom2Ptr = firstAtomPtr + atom2Id; // Set fields of the Angle object anglePtr->setAtom(0, *atom0Ptr); anglePtr->setAtom(1, *atom1Ptr); anglePtr->setAtom(2, *atom2Ptr); anglePtr->setTypeId(type); ++anglePtr; } } ++moleculePtr; } }
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); } } } }
static PyObject *setbonds(PyObject *self, PyObject *args) { int molid; PyObject *atomlist, *bondlist; if (!PyArg_ParseTuple(args, (char *)"iO!O!:setbonds", &molid, &PyTuple_Type, &atomlist, &PyList_Type, &bondlist)) return NULL; // bad args Molecule *mol = get_vmdapp()->moleculeList->mol_from_id(molid); if (!mol) { PyErr_SetString(PyExc_ValueError, "molecule no longer exists"); return NULL; } int num_atoms = mol->nAtoms; int num_selected = PyTuple_Size(atomlist); if (PyList_Size(bondlist) != num_selected) { PyErr_SetString(PyExc_ValueError, (char *)"setbonds: atomlist and bondlist must have the same size"); return NULL; } mol->force_recalc(DrawMolItem::MOL_REGEN); // many reps ignore bonds for (int i=0; i<num_selected; i++) { int id = PyInt_AsLong(PyTuple_GET_ITEM(atomlist, i)); if (PyErr_Occurred()) { return NULL; } if (id < 0 || id >= num_atoms) { PyErr_SetString(PyExc_ValueError, (char *)"invalid atom id found"); return NULL; } MolAtom *atom = mol->atom(id); PyObject *atomids = PyList_GET_ITEM(bondlist, i); if (!PyList_Check(atomids)) { PyErr_SetString(PyExc_TypeError, (char *)"bondlist must contain lists"); return NULL; } int numbonds = PyList_Size(atomids); int k=0; for (int j=0; j<numbonds; j++) { int bond = PyInt_AsLong(PyList_GET_ITEM(atomids, j)); if (PyErr_Occurred()) return NULL; if (bond >= 0 && bond < mol->nAtoms) { atom->bondTo[k++] = bond; } else { char buf[40]; sprintf(buf, "Invalid atom id in bondlist: %d", bond); PyErr_SetString(PyExc_ValueError, buf); return NULL; } } atom->bonds = k; } Py_INCREF(Py_None); return Py_None; }
/* * Initialize all Dihedral objects for Molecules of one Species. * * This functions assigns pointers to Atoms and Dihedral types ids within * a contiguous block of Dihedral objects, and sets a pointer in each * Molecule to the first Dihedral in the associated block. */ void Simulation::initializeSpeciesDihedrals(int iSpecies) { Species* speciesPtr = 0; Molecule *moleculePtr = 0; Dihedral *dihedralPtr = 0; Atom *firstAtomPtr, *atom0Ptr, *atom1Ptr, *atom2Ptr, *atom3Ptr; int iMol, iDihedral, atom0Id, atom1Id, atom2Id, atom3Id, type; int capacity, nDihedral; speciesPtr = &species(iSpecies); capacity = speciesPtr->capacity(); nDihedral = speciesPtr->nDihedral(); // Initialize pointers before loop moleculePtr = &molecules_[firstMoleculeIds_[iSpecies]]; dihedralPtr = &dihedrals_[firstDihedralIds_[iSpecies]]; // Loop over molecules in Species for (iMol = 0; iMol < capacity; ++iMol) { firstAtomPtr = &(moleculePtr->atom(0)); moleculePtr->setFirstDihedral(*dihedralPtr); moleculePtr->setNDihedral(nDihedral); if (nDihedral > 0) { // Create dihedrals for a molecule for (iDihedral = 0; iDihedral < nDihedral; ++iDihedral) { // Get local indices for atoms and dihedral type atom0Id = speciesPtr->speciesDihedral(iDihedral).atomId(0); atom1Id = speciesPtr->speciesDihedral(iDihedral).atomId(1); atom2Id = speciesPtr->speciesDihedral(iDihedral).atomId(2); atom3Id = speciesPtr->speciesDihedral(iDihedral).atomId(3); type = speciesPtr->speciesDihedral(iDihedral).typeId(); // Calculate atom pointers atom0Ptr = firstAtomPtr + atom0Id; atom1Ptr = firstAtomPtr + atom1Id; atom2Ptr = firstAtomPtr + atom2Id; atom3Ptr = firstAtomPtr + atom3Id; // Set fields of the Dihedral object dihedralPtr->setAtom(0, *atom0Ptr); dihedralPtr->setAtom(1, *atom1Ptr); dihedralPtr->setAtom(2, *atom2Ptr); dihedralPtr->setAtom(3, *atom3Ptr); dihedralPtr->setTypeId(type); ++dihedralPtr; } } ++moleculePtr; } }
/// Evaluate end-to-end vectors of all chains. void EndtoEndXYZ::sample(long iStep) { if (isAtInterval(iStep)) { Molecule* moleculePtr; Vector r1, r2, dR; double dxSq, dySq, dzSq; int i, j, nMolecule; dxSq = 0.0; dySq = 0.0; dzSq = 0.0; nMolecule = system().nMolecule(speciesId_); for (i = 0; i < system().nMolecule(speciesId_); i++) { moleculePtr = &system().molecule(speciesId_, i); // Construct map of molecule with no periodic boundary conditions positions_[0] = moleculePtr->atom(0).position(); for (j = 1 ; j < nAtom_; j++) { r1 = moleculePtr->atom(j-1).position(); r2 = moleculePtr->atom(j).position(); system().boundary().distanceSq(r1, r2, dR); positions_[j] = positions_[j-1]; positions_[j] += dR; } dR.subtract(positions_[0], positions_[nAtom_-1]); dxSq += dR[0]*dR[0]; dySq += dR[1]*dR[1]; dzSq += dR[2]*dR[2]; } dxSq /= double(nMolecule); dySq /= double(nMolecule); dzSq /= double(nMolecule); accumulatorX_.sample(dxSq, outputFileX_); accumulatorY_.sample(dySq, outputFileY_); accumulatorZ_.sample(dzSq, outputFileZ_); } // if isAtInterval }
static PyObject *contacts(PyObject *self, PyObject *args) { int mol1, frame1, mol2, frame2; PyObject *selected1, *selected2; float cutoff; if (!PyArg_ParseTuple(args, (char *)"iiO!iiO!f:atomselection.contacts", &mol1, &frame1, &PyTuple_Type, &selected1, &mol2, &frame2, &PyTuple_Type, &selected2, &cutoff)) return NULL; VMDApp *app = get_vmdapp(); AtomSel *sel1 = sel_from_py(mol1, frame1, selected1, app); AtomSel *sel2 = sel_from_py(mol2, frame2, selected2, app); if (!sel1 || !sel2) { delete sel1; delete sel2; return NULL; } const float *ts1 = sel1->coordinates(app->moleculeList); const float *ts2 = sel2->coordinates(app->moleculeList); if (!ts1 || !ts2) { PyErr_SetString(PyExc_ValueError, "No coordinates in selection"); delete sel1; delete sel2; return NULL; } Molecule *mol = app->moleculeList->mol_from_id(mol1); GridSearchPair *pairlist = vmd_gridsearch3( ts1, sel1->num_atoms, sel1->on, ts2, sel2->num_atoms, sel2->on, cutoff, -1, (sel1->num_atoms + sel2->num_atoms) * 27); delete sel1; delete sel2; GridSearchPair *p, *tmp; PyObject *list1 = PyList_New(0); PyObject *list2 = PyList_New(0); for (p=pairlist; p != NULL; p=tmp) { // throw out pairs that are already bonded MolAtom *a1 = mol->atom(p->ind1); if (mol1 != mol2 || !a1->bonded(p->ind2)) { PyList_Append(list1, PyInt_FromLong(p->ind1)); PyList_Append(list2, PyInt_FromLong(p->ind2)); } tmp = p->next; free(p); } PyObject *result = PyList_New(2); PyList_SET_ITEM(result, 0, list1); PyList_SET_ITEM(result, 1, list2); return result; }
/* * Evaluate Rosenbluth weight, and add to accumulator. */ void McChemicalPotential::sample(long iStep) { if (isAtInterval(iStep)) { Species* speciesPtr; Molecule* molPtr; Molecule::BondIterator bondIter; Atom* endPtr; double w; double rosenbluth = 1; double de; double e = 0; speciesPtr = &(simulation().species(speciesId_)); // Pop a new molecule off the species reservoir molPtr = &(speciesPtr->reservoir().pop()); system().addMolecule(*molPtr); // Loop over molecule growth trials for (int i = 0; i < nMoleculeTrial_; i++) { // Pick a random position for the first atom endPtr = &molPtr->atom(0); boundary().randomPosition(random(), endPtr->position()); e = system().pairPotential().atomEnergy(*endPtr); rosenbluth = boltzmann(e); system().pairPotential().addAtom(*endPtr); for (molPtr->begin(bondIter); bondIter.notEnd(); ++bondIter) { addEndAtom(&(bondIter->atom(1)), &(bondIter->atom(0)), bondIter->typeId(), w, de); e += de; rosenbluth *= w; system().pairPotential().addAtom(bondIter->atom(1)); } rosenbluth = rosenbluth / pow(nTrial_,molPtr->nAtom()-1); accumulator_.sample(rosenbluth, outputFile_); system().pairPotential().deleteAtom(*endPtr); for (molPtr->begin(bondIter); bondIter.notEnd(); ++bondIter) { system().pairPotential().deleteAtom(bondIter->atom(1)); } } // Return additional molecule to reservoir system().removeMolecule(*molPtr); speciesPtr->reservoir().push(*molPtr); } }
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); } } }
/* * Evaluate end-to-end vectors of all chains, add to ensemble. */ void RingRouseAutoCorr::sample(long iStep) { if (isAtInterval(iStep)) { Molecule* moleculePtr; Vector r1, r2, dR, atomPos; int i, j; // Confirm that nMolecule has remained constant if (nMolecule_ != system().nMolecule(speciesId_)) { UTIL_THROW("Number of molecules has changed."); } // Loop over molecules for (i=0; i < nMolecule_; i++) { moleculePtr = &(system().molecule(speciesId_, i)); // Retrace non-periodic shape and calculate coefficients atomPos = moleculePtr->atom(0).position(); dR.multiply(atomPos, projector_[0]); data_[i] = dR; for (j = 1; j < nAtom_; j++) { r1 = moleculePtr->atom(j-1).position(); r2 = moleculePtr->atom(j).position(); system().boundary().distanceSq(r2, r1, dR); atomPos += dR; dR.multiply(atomPos, projector_[j]); data_[i] += dR; } } accumulator_.sample(data_); } // if isAtInterval }
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(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()); }
/* * Evaluate end-to-end vectors of all chains, add to ensemble. */ void G1MSD::sample(long iStep) { if (!isAtInterval(iStep)) return; // Confirm that nMolecule has remained constant, and nMolecule > 0. if (nMolecule_ <= 0) { UTIL_THROW("nMolecule <= 0"); } if (nMolecule_ != system().nMolecule(speciesId_)) { UTIL_THROW("Number of molecules has changed."); } Vector r; IntVector shift; Molecule* moleculePtr; Vector lengths = system().boundary().lengths(); int i, j, k; int iatom = 0; for (i = 0; i < nMolecule_; ++i) { moleculePtr = &system().molecule(speciesId_, i); for (j = 0 ; j < nAtom_; j++) { r = moleculePtr->atom(j).position(); system().boundary().shift(r); // Compare current r to previous position, oldPositions_[iatom] system().boundary().distanceSq(r, oldPositions_[iatom], shift); // If this atom crossed a boundary, increment its shift vector shifts_[iatom] += shift; // Reconstruct true position for (k = 0; k < Dimension; ++k) { truePositions_[iatom][k] = r[k] + shifts_[iatom][k]*lengths[k]; } // Store current position in box for comparison to next one oldPositions_[iatom] = r; iatom++; } } accumulator_.sample(truePositions_); }
static PyObject *getbonds(PyObject *self, PyObject *args) { int molid; PyObject *atomlist; if (!PyArg_ParseTuple(args, (char *)"iO!:getbonds", &molid, &PyTuple_Type, &atomlist)) return NULL; // bad args Molecule *mol = get_vmdapp()->moleculeList->mol_from_id(molid); if (!mol) { PyErr_SetString(PyExc_ValueError, "molecule no longer exists"); return NULL; } int num_atoms = mol->nAtoms; int num_selected = PyTuple_Size(atomlist); PyObject *newlist = PyList_New(num_selected); for (int i=0; i< num_selected; i++) { int id = PyInt_AsLong(PyTuple_GET_ITEM(atomlist, i)); if (PyErr_Occurred()) { Py_DECREF(newlist); return NULL; } if (id < 0 || id >= num_atoms) { PyErr_SetString(PyExc_ValueError, (char *)"invalid atom id found"); Py_DECREF(newlist); return NULL; } const MolAtom *atom = mol->atom(id); PyObject *bondlist = PyList_New(atom->bonds); for (int j=0; j<atom->bonds; j++) { PyList_SET_ITEM(bondlist, j, PyInt_FromLong(atom->bondTo[j])); } PyList_SET_ITEM(newlist, i, bondlist); } return newlist; }
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)); }
/* * Generate, attempt and accept or reject a Monte Carlo move. * * A complete move involve the following stepts: * * 1) choose a molecule-i randomly; * 2) find molecule-j of the same type as i, and monomer pairs satisfying * the distance criterion exist; * 3) Delete the two rebridging monomers; first molecule-i, then -j. * 4) Rebuild molecule-j, then -i. (in the JCP paper, the order is chosen * at random.) * */ bool CfbDoubleRebridgeMove::move() { bool found, accept; int iMol, jMol, sign, beginId, nEnd, i; Molecule *iPtr; // pointer to i-th molecule Molecule *jPtr; // pointer to j-th molecule int *bonds; // bond types of a consequtive blocks of atoms Atom *thisPtr; // pointer to the current end atom Atom *tempPtr; // pointer used for swap atom positions double rosenbluth, rosen_r, rosen_f; double energy, energy_r, energy_f; double po2n, pn2o; Vector swapPos; incrementNAttempt(); // Choose a random direction if (random().uniform(0.0, 1.0) > 0.5) sign = +1; else sign = -1; // Search for a pair of candidate sites and calculate probability found = forwardScan(sign, iMol, jMol, beginId, po2n); if (!found) return found; iPtr = &(system().molecule(speciesId_, iMol)); jPtr = &(system().molecule(speciesId_, jMol)); // Save positions for atoms to be regrown thisPtr = &(iPtr->atom(beginId)); tempPtr = &(jPtr->atom(beginId)); for (i = 0; i < nRegrow_; ++i) { iOldPos_[i] = thisPtr->position(); jOldPos_[i] = tempPtr->position(); thisPtr += sign; tempPtr += sign; } // Prepare for the rebridge move accept = false; bonds = new int[nRegrow_ + 1]; if (sign == +1) { for (i = 0; i < nRegrow_ + 1; ++i) bonds[i] = iPtr->bond(beginId - 1 + nRegrow_ - i).typeId(); } else { for (i = 0; i < nRegrow_ + 1; ++i) bonds[i] = iPtr->bond(beginId - nRegrow_ + i).typeId(); } // Deleting atoms: first i-th molecule, then j-th rosen_r = 1.0; energy_r = 0.0; thisPtr = &(iPtr->atom(beginId + (nRegrow_-1)*sign)); deleteSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy); rosen_r *= rosenbluth; energy_r += energy; thisPtr = &(jPtr->atom(beginId + (nRegrow_-1)*sign)); deleteSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy); rosen_r *= rosenbluth; energy_r += energy; // Swap the atom positions of the dangling end if (sign == +1) nEnd = iPtr->nAtom() - beginId - nRegrow_; else nEnd = beginId + 1 - nRegrow_; thisPtr = &(iPtr->atom(beginId + nRegrow_*sign)); tempPtr = &(jPtr->atom(beginId + nRegrow_*sign)); for (i = 0; i < nEnd; ++i) { swapPos = thisPtr->position(); //system().moveAtom(*thisPtr, tempPtr->position()); thisPtr->position() = tempPtr->position(); #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*thisPtr); #endif //system().moveAtom(*tempPtr, swapPos); tempPtr->position() = swapPos; #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*tempPtr); #endif thisPtr += sign; tempPtr += sign; } // Regrow atoms: first j-th molecule, then i-th rosen_f = 1.0; energy_f = 0.0; thisPtr = &(jPtr->atom(beginId)); addSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy); rosen_f *= rosenbluth; energy_f += energy; thisPtr = &(iPtr->atom(beginId)); addSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy); rosen_f *= rosenbluth; energy_f += energy; // Reverse scan found = reverseScan(sign, iMol, jMol, beginId - sign, pn2o); // Decide whether to accept or reject if (found) accept = random().metropolis(rosen_f * pn2o / rosen_r / po2n); else accept = false; if (accept) { // Increment counter for accepted moves of this class. incrementNAccept(); } else { // If the move is rejected, restore nRegrow_ positions thisPtr = &(iPtr->atom(beginId)); tempPtr = &(jPtr->atom(beginId)); for (i = 0; i < nRegrow_; ++i) { //system().moveAtom(*thisPtr, iOldPos_[i]); thisPtr->position() = iOldPos_[i]; #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*thisPtr); #endif //system().moveAtom(*tempPtr, jOldPos_[i]); tempPtr->position() = jOldPos_[i]; #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*tempPtr); #endif thisPtr += sign; tempPtr += sign; } // Restore atom positions at the dangling end thisPtr = &(iPtr->atom(beginId + nRegrow_*sign)); tempPtr = &(jPtr->atom(beginId + nRegrow_*sign)); for (i = 0; i < nEnd; ++i) { swapPos = thisPtr->position(); //system().moveAtom(*thisPtr, tempPtr->position()); thisPtr->position() = tempPtr->position(); #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*thisPtr); #endif //system().moveAtom(*tempPtr, swapPos); tempPtr->position() = swapPos; #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*tempPtr); #endif thisPtr += sign; tempPtr += sign; } } // Release memory delete [] bonds; return accept; }
/* * Generate, attempt and accept or reject a Monte Carlo move. */ bool EndSwapMove::move() { double newEnergy, oldEnergy; Molecule* molPtr; Atom* atomPtr; int i, nAtom; incrementNAttempt(); molPtr = &(system().randomMolecule(speciesId_)); nAtom = molPtr->nAtom(); // Calculate old molecule energy = pair + external oldEnergy = 0.0; #ifndef INTER_NOPAIR oldEnergy += system().pairPotential().moleculeEnergy(*molPtr); #endif #ifdef INTER_EXTERNAL for (i = 0; i < nAtom; ++i) { atomPtr = &molPtr->atom(i); oldEnergy += system().externalPotential().atomEnergy(*atomPtr); } #endif // Reverse sequence of atom types for (i = 0; i < nAtom; ++i) { assert(molPtr->atom(i).typeId() == atomTypeIds_[i]); molPtr->atom(i).setTypeId(atomTypeIds_[nAtom - 1 - i]); } // Calculate new energy (with reversed sequence of atom types). newEnergy = 0.0; #ifndef INTER_NOPAIR newEnergy += system().pairPotential().moleculeEnergy(*molPtr); #endif #ifdef INTER_EXTERNAL for (i = 0; i < nAtom; ++i) { molPtr->atom(i).setTypeId(atomTypeIds_[nAtom - 1 - i]); atomPtr = &molPtr->atom(i); newEnergy += system().externalPotential().atomEnergy(*atomPtr); } #endif // Restore original sequence of atom type Ids for (i = 0; i < nAtom; ++i) { molPtr->atom(i).setTypeId(atomTypeIds_[i]); } // Decide whether to accept or reject bool accept = random().metropolis(boltzmann(newEnergy-oldEnergy)); if (accept) { // Store all atomic positions for (i = 0; i < nAtom; ++i) { positions_[i] = molPtr->atom(i).position(); } // Reverse sequence of atomic positions for (i = 0; i < nAtom; ++i) { atomPtr = &molPtr->atom(i); atomPtr->position() = positions_[nAtom - 1 - i]; #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*atomPtr); #endif } incrementNAccept(); } return accept; }
/* * Generate, attempt and accept or reject a Monte Carlo move. * * Convention for index * head of molecule tail of molecule * | | * 0 1 2 3 ... length-1 * o---o---o---o---o---o---o---o---o---o * |_______________|___________| * valid beginId nRegrow * */ bool CfbRebridgeMove::move() { Molecule *molPtr; // pointer to randomly chosen molecule Atom *thisPtr; // pointer to the current end atom int length, sign, beginId, endId, i; int *bonds; double rosen_r, rosen_f; double energy_r, energy_f; bool accept; incrementNAttempt(); // Choose a molecule at random molPtr = &(system().randomMolecule(speciesId_)); length = molPtr->nAtom(); // Require that chain length - 2 >= nRegrow_ if (nRegrow_ > length - 2) { UTIL_THROW("nRegrow_ >= chain length"); } // Allocate bonds array bonds = new int[nRegrow_ + 1]; // Choose the beginId of the growing interior bridge beginId = random().uniformInt(1, length - nRegrow_); // Choose direction: sign = +1 if beginId < endId if (random().uniform(0.0, 1.0) > 0.5) { sign = +1; endId = beginId + (nRegrow_ - 1); } else { sign = -1; endId = beginId; beginId = endId + (nRegrow_ - 1); } // Store current atomic positions from segment to be regrown thisPtr = &(molPtr->atom(beginId)); for (i = 0; i < nRegrow_; ++i) { oldPos_[i] = thisPtr->position(); thisPtr += sign; } // Get bond types. if (sign == +1) { for (i = 0; i < nRegrow_ + 1; ++i) bonds[i] = molPtr->bond(endId - i).typeId(); } else { for (i = 0; i < nRegrow_ + 1; ++i) bonds[i] = molPtr->bond(endId - 1 + i).typeId(); } // Delete atoms: endId -> beginId thisPtr = &(molPtr->atom(endId)); deleteSequence(nRegrow_, sign, thisPtr, bonds, rosen_r, energy_r); // Regrow atoms: endId -> beginId thisPtr = &(molPtr->atom(beginId)); addSequence(nRegrow_, sign, thisPtr, bonds, rosen_f, energy_f); // Release bonds array delete [] bonds; // Decide whether to accept or reject accept = random().metropolis(rosen_f/rosen_r); if (accept) { // Increment counter for accepted moves of this class. incrementNAccept(); // If the move is accepted, keep current positions. } else { // If the move is rejected, restore old positions thisPtr = &(molPtr->atom(beginId)); for (i = 0; i < nRegrow_; ++i) { //system().moveAtom(*thisPtr, oldPos_[i]); thisPtr->position() = oldPos_[i]; #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*thisPtr); #endif thisPtr += sign; } } return accept; }
/** * Recursive function to try to place an atom. */ bool Linear::tryPlaceAtom(Molecule& molecule, int atomId, DArray<double> exclusionRadius, System& system, CellList &cellList, BondPotential *bondPotentialPtr, const Boundary &boundary) { Atom& lastAtom = molecule.atom(atomId); Atom& thisAtom = molecule.atom(++atomId); Random& random = system.simulation().random(); bool hasBeenPlaced = false; for (int iAttempt = 0; iAttempt < maxPlacementAttempts_; iAttempt++) { // draw a random bond vector int beta = 1; Vector v; random.unitVector(v); v *= bondPotentialPtr->randomBondLength(&random, beta, calculateBondTypeId(lastAtom.indexInMolecule())); Vector newPos; newPos = lastAtom.position(); newPos += v; // shift into simulation cell boundary.shift(newPos); // check if the atom can be placed at the new position CellList::NeighborArray neighbors; cellList.getNeighbors(newPos, neighbors); int nNeighbor = neighbors.size(); bool canBePlaced = true; for (int j = 0; j < nNeighbor; ++j) { Atom *jAtomPtr = neighbors[j]; double r = sqrt(boundary.distanceSq( jAtomPtr->position(), newPos)); if (r < (exclusionRadius[thisAtom.typeId()] + exclusionRadius[jAtomPtr->typeId()])) { canBePlaced = false; break; } } if (canBePlaced) { // place the particle thisAtom.position() = newPos; // add to cell list cellList.addAtom(thisAtom); // are we add the end of the chain? if (atomId == molecule.nAtom()-1) return true; // recursion step if (! tryPlaceAtom(molecule, atomId, exclusionRadius, system, cellList, bondPotentialPtr, boundary) ) { // If the next monomer cannot be inserted, delete this monomer // again cellList.deleteAtom(thisAtom); } else { hasBeenPlaced = true; break; } } } return hasBeenPlaced; }
/* * Generate, attempt and accept or reject a Monte Carlo move. */ bool CfbHomoReptationMove::move() { Vector oldPos, newPos; double rosen_r, rosen_f; double energy_r, energy_f; Atom *tailPtr; // pointer to the tail atom (to be removed) Atom *atomPtr; // resetable atom pointer Molecule *molPtr; // pointer to randomly chosen molecule int length, sign, headId, tailId, bondType, i; bool accept; incrementNAttempt(); // Choose a molecule at random molPtr = &(system().randomMolecule(speciesId_)); length = molPtr->nAtom(); // Choose which chain end to regrow if (random().uniform(0.0, 1.0) > 0.5) { sign = +1; headId = length - 1; tailId = 0; } else { sign = -1; headId = 0; tailId = length - 1; } // Store current positions of tail oldPos = molPtr->atom(tailId).position(); // Delete tail monomers tailPtr = &(molPtr->atom(tailId)); atomPtr = tailPtr + sign; if (sign == 1) { bondType = molPtr->bond(0).typeId(); } else { bondType = molPtr->bond(length-2).typeId(); } deleteEndAtom(tailPtr, atomPtr, bondType, rosen_r, energy_r); #ifndef INTER_NOPAIR // Delete from McSystem cell list system().pairPotential().deleteAtom(*tailPtr); #endif // Regrow head, using tailPtr to store properties of the new head. atomPtr = &(molPtr->atom(headId)); tailPtr->setTypeId(atomPtr->typeId()); tailPtr->mask().clear(); #ifndef MCMD_NOMASKBONDED tailPtr->mask().append(*atomPtr); #endif if (sign == 1) { bondType = molPtr->bond(length-2).typeId(); } else { bondType = molPtr->bond(0).typeId(); } addEndAtom(tailPtr, atomPtr, bondType, rosen_f, energy_f); // Restore original type and connectivity of tail Atom atomPtr = tailPtr + sign; tailPtr->setTypeId(atomPtr->typeId()); tailPtr->mask().clear(); #ifndef MCMD_NOMASKBONDED tailPtr->mask().append(*atomPtr); #endif // Decide whether to accept or reject accept = random().metropolis(rosen_f/rosen_r); if (accept) { // Increment nAccept, the number accepted moves. incrementNAccept(); // Store new head position newPos = tailPtr->position(); tailPtr->position() = atomPtr->position(); #ifndef INTER_NOPAIR // Add back to system cell list system().pairPotential().addAtom(*tailPtr); #endif // Shift atom positions towards the head for (i=1; i < length - 1; ++i) { //system().moveAtom(*atomPtr, (atomPtr+sign)->position()); atomPtr->position() = (atomPtr+sign)->position(); #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*atomPtr); #endif atomPtr += sign; } // Move head atom to new chosen position //system().moveAtom(*atomPtr, newPos); atomPtr->position() = newPos; #ifndef INTER_NOPAIR system().pairPotential().updateAtomCell(*atomPtr); #endif } else { // Restore old position of tail tailPtr->position() = oldPos; #ifndef INTER_NOPAIR // Add tail back to System cell list. system().pairPotential().addAtom(*tailPtr); #endif } return accept; }
/* * Initialize all Bond objects for Molecules of one Species. (private) * * This functions assigns pointers to Atoms and bond types ids within a * contiguous block of Bond objects, and sets a pointer in each Molecule * to the first Bond in the associated block. */ void Simulation::initializeSpeciesBonds(int iSpecies) { if (nBondType_ <= 0) { UTIL_THROW("nBondType_ must be positive"); } Species* speciesPtr = 0; Molecule* moleculePtr = 0; Bond* bondPtr = 0; Atom* firstAtomPtr; Atom* atom0Ptr; Atom* atom1Ptr; int iMol, iBond, atom0Id, atom1Id, type; int capacity, nBond; speciesPtr = &species(iSpecies); nBond = speciesPtr->nBond(); capacity = speciesPtr->capacity(); // Initialize pointers before loop moleculePtr = &molecules_[firstMoleculeIds_[iSpecies]]; bondPtr = &bonds_[firstBondIds_[iSpecies]]; // Loop over molecules in Species for (iMol = 0; iMol < capacity; ++iMol) { firstAtomPtr = &(moleculePtr->atom(0)); moleculePtr->setFirstBond(*bondPtr); moleculePtr->setNBond(nBond); if (nBond > 0) { // Create bonds for a molecule for (iBond = 0; iBond < nBond; ++iBond) { // Get pointers to bonded atoms and bond type atom0Id = speciesPtr->speciesBond(iBond).atomId(0); atom1Id = speciesPtr->speciesBond(iBond).atomId(1); type = speciesPtr->speciesBond(iBond).typeId(); atom0Ptr = firstAtomPtr + atom0Id; atom1Ptr = firstAtomPtr + atom1Id; // Set fields of the Bond object bondPtr->setAtom(0, *atom0Ptr); bondPtr->setAtom(1, *atom1Ptr); bondPtr->setTypeId(type); // If MaskBonded, add each bonded atom to its partners Mask if (maskedPairPolicy_ == MaskBonded) { atom0Ptr->mask().append(*atom1Ptr); atom1Ptr->mask().append(*atom0Ptr); } ++bondPtr; } } ++moleculePtr; } }
// Calculate total intramolecular forces void DUQ::intramolecularForces(ProcessPool& procPool, Configuration* cfg, double* fx, double* fy, double* fz) { /* * Calculate the total intramolecular forces within the system, arising from Bond, Angle, and Torsion * terms in all molecules. * * This is a parallel routine. */ double distance, angle, force, dp, magji, magjk; int index, start, stride; Atom* i, *j, *k; Vec3<double> vecji, vecjk, forcei, forcek; // Set start/skip for parallel loop start = procPool.interleavedLoopStart(ProcessPool::OverPoolProcesses); stride = procPool.interleavedLoopStride(ProcessPool::OverPoolProcesses); // Main loop over molecules for (Molecule* mol = cfg->molecules(); mol != NULL; mol = mol->next) { // Bonds for (SpeciesBond* b = mol->species()->bonds(); b != NULL; b = b->next) { // Grab pointers to atoms involved in bond i = mol->atom(b->indexI()); j = mol->atom(b->indexJ()); // Determine whether we need to apply minimum image to the vector calculation if (cfg->useMim(i->grain()->cell(), j->grain()->cell())) vecji = cfg->box()->minimumVector(i, j); else vecji = j->r() - i->r(); // Get distance and normalise vector ready for force calculation distance = vecji.magAndNormalise(); // Determine final forces vecji *= b->force(distance); // Calculate forces index = b->i()->index(); fx[index] -= vecji.x; fy[index] -= vecji.y; fz[index] -= vecji.z; index = b->j()->index(); fx[index] += vecji.x; fy[index] += vecji.y; fz[index] += vecji.z; } // Angles for (SpeciesAngle* a = mol->species()->angles(); a != NULL; a = a->next) { // Grab pointers to atoms involved in angle i = mol->atom(a->indexI()); j = mol->atom(a->indexJ()); k = mol->atom(a->indexK()); // Determine whether we need to apply minimum image between 'j-i' and 'j-k' if (cfg->useMim(j->grain()->cell(), i->grain()->cell())) vecji = cfg->box()->minimumVector(j, i); else vecji = i->r() - j->r(); if (cfg->useMim(j->grain()->cell(), k->grain()->cell())) vecjk = cfg->box()->minimumVector(j, k); else vecjk = k->r() - j->r(); // Calculate angle magji = vecji.magAndNormalise(); magjk = vecjk.magAndNormalise(); angle = Box::angle(vecji, vecjk, dp); // Determine Angle force vectors for atoms force = a->force(angle); forcei = vecjk - vecji * dp; forcei *= force / magji; forcek = vecji - vecjk * dp; forcek *= force / magjk; // Store forces index = a->i()->index(); fx[index] += forcei.x; fy[index] += forcei.y; fz[index] += forcei.z; index = a->j()->index(); fx[index] -= forcei.x + forcek.x; fy[index] -= forcei.y + forcek.y; fz[index] -= forcei.z + forcek.z; index = a->k()->index(); fx[index] += forcek.x; fy[index] += forcek.y; fz[index] += forcek.z; } } }
// Create or destroy the slip-springs. bool SliplinkerAll::move() { System::MoleculeIterator molIter; Molecule::AtomIterator atomIter; Atom *atom0Ptr, *atom1Ptr; Atom* atomPtr; Molecule *mol0Ptr, *mol1Ptr; Molecule* molIPtr; double prob, dRSq, mindRSq=cutoff_*cutoff_, rnd, norm; int i, ntrials, j, nNeighbor, idLink, iAtom, id1, id0; int iAtom0, iAtom1, iMolecule0, iMolecule1, n0; Link* linkPtr; static const int maxNeighbor = CellList::MaxNeighbor; double cdf[maxNeighbor], energy, sum; int idneighbors[maxNeighbor]; ntrials = 2 * system().simulation().atomCapacity(); for (i=0; i < ntrials; ++i){ //Choose to create or destroy a link with prob 0.5 if (random().uniform(0.0, 1.0) > 0.5){ // Try to create a link. incrementNAttempt(); // Choose a molecule and atom at random molIPtr = &(system().randomMolecule(speciesId_)); iMolecule0 = system().moleculeId(*molIPtr); iAtom = random().uniformInt(0, molIPtr->nAtom()); atomPtr = &molIPtr->atom(iAtom); id0 = atomPtr->id(); // Get array of neighbors system().pairPotential().cellList().getNeighbors(atomPtr->position(), neighbors_); nNeighbor = neighbors_.size(); n0 = 0; sum = 0; // Loop over neighboring atoms for (j = 0; j < nNeighbor; ++j) { atom1Ptr = neighbors_[j]; mol1Ptr = &atom1Ptr->molecule(); iMolecule1 = system().moleculeId(*mol1Ptr); id1 = atom1Ptr->id(); // Check if atoms are the same if (id0 != id1){ // Exclude masked pairs if (!atomPtr->mask().isMasked(*atom1Ptr)) { // Identify possible partners and calculate the cumulative distribution function dRSq = system().boundary().distanceSq(atomPtr->position(), atom1Ptr->position()); if (dRSq <= mindRSq) { energy = system().linkPotential().energy(dRSq, 0); //energy = 0.5*dRSq; sum = sum + boltzmann(energy); cdf[n0] = sum; idneighbors[n0] = j; n0++; } } } } // If at least 1 candidate has been found. if (n0 > 0) { // Choose a partner with probability cdf[j]/cdf[n0-1] j = 0; rnd = random().uniform(0.0, 1.0); norm = 1.0/cdf[n0-1]; while (rnd > cdf[j]*norm ){ j = j + 1; } atom1Ptr = neighbors_[idneighbors[j]]; // Create a slip-link between the selected atoms with probability = prob prob = 2.0 * (system().linkMaster().nLink() + 1.0); prob = system().simulation().atomCapacity() * boltzmann(-mu_) * cdf[n0-1]/ prob ; //prob = 2.0 * system().nMolecule(speciesId_) * boltzmann(-mu_) * cdf[n0-1]/ prob ; if (system().simulation().random().uniform(0.0, 1.0) < prob) { system().linkMaster().addLink(*atomPtr, *atom1Ptr, 0); incrementNAccept(); } } } else { // Try to destroy a link incrementNAttempt(); // Choose a link at random if (system().linkMaster().nLink() > 0){ idLink = random().uniformInt(0, system().linkMaster().nLink()); // Indentify the atoms for this link. linkPtr = &(system().linkMaster().link(idLink)); atom0Ptr = &(linkPtr->atom0()); mol0Ptr = &atom0Ptr->molecule(); iMolecule0 = system().moleculeId(*mol0Ptr); iAtom0 = atom0Ptr->indexInMolecule(); atom1Ptr = &(linkPtr->atom1()); mol1Ptr = &atom1Ptr->molecule(); iMolecule1 = system().moleculeId(*mol1Ptr); iAtom1 = atom1Ptr->indexInMolecule(); // try to delete the slip-spring dRSq = system().boundary().distanceSq(atom0Ptr->position(), atom1Ptr->position()); // try to delete the link if the bond is smaller than the cutoff if (dRSq <= mindRSq) { // Get array of neighbors system().pairPotential().cellList().getNeighbors(atom0Ptr->position(), neighbors_); nNeighbor = neighbors_.size(); id0 = atom0Ptr->id(); n0 = 0; sum = 0; // Loop over neighboring atoms for (j = 0; j < nNeighbor; ++j) { atom1Ptr = neighbors_[j]; mol1Ptr = &atom1Ptr->molecule(); iMolecule1 = system().moleculeId(*mol1Ptr); id1 = atom1Ptr->id(); // Check if atoms are the same if (id0 != id1){ // Exclude masked pairs if (!atom0Ptr->mask().isMasked(*atom1Ptr)) { // Identify possible partners and calculate the cumulative distribution function dRSq = system().boundary().distanceSq(atom0Ptr->position(), atom1Ptr->position()); if (dRSq <= mindRSq) { energy = system().linkPotential().energy(dRSq, 0); //energy = 0.5*dRSq; sum = sum + boltzmann(energy); cdf[n0] = sum; idneighbors[n0] = j; n0++; } } } } // Destroy the slip-link between the selected atoms with probability = prob //prob = 2.0 * system().nMolecule(speciesId_) * boltzmann(-mu_) * cdf[n0-1]; prob = system().simulation().atomCapacity() * boltzmann(-mu_) * cdf[n0-1]; prob = 2.0 * system().linkMaster().nLink() / prob; if (system().simulation().random().uniform(0.0, 1.0) < prob) { system().linkMaster().removeLink(idLink); incrementNAccept(); } } } } } return true; }
static PyObject *contacts(PyObject *self, PyObject *args) { int mol1, frame1, mol2, frame2; PyObject *selected1, *selected2; float cutoff; if (!PyArg_ParseTuple(args, (char *)"iiO!iiO!f:atomselection.contacts", &mol1, &frame1, &PyTuple_Type, &selected1, &mol2, &frame2, &PyTuple_Type, &selected2, &cutoff)) return NULL; VMDApp *app = get_vmdapp(); AtomSel *sel1 = sel_from_py(mol1, frame1, selected1, app); AtomSel *sel2 = sel_from_py(mol2, frame2, selected2, app); if (!sel1 || !sel2) { delete sel1; delete sel2; return NULL; } const float *ts1 = sel1->coordinates(app->moleculeList); const float *ts2 = sel2->coordinates(app->moleculeList); if (!ts1 || !ts2) { PyErr_SetString(PyExc_ValueError, "No coordinates in selection"); delete sel1; delete sel2; return NULL; } Molecule *mol = app->moleculeList->mol_from_id(mol1); GridSearchPair *pairlist = vmd_gridsearch3( ts1, sel1->num_atoms, sel1->on, ts2, sel2->num_atoms, sel2->on, cutoff, -1, (sel1->num_atoms + sel2->num_atoms) * 27); delete sel1; delete sel2; GridSearchPair *p, *tmp; PyObject *list1 = PyList_New(0); PyObject *list2 = PyList_New(0); PyObject *tmp1; PyObject *tmp2; for (p=pairlist; p != NULL; p=tmp) { // throw out pairs that are already bonded MolAtom *a1 = mol->atom(p->ind1); if (mol1 != mol2 || !a1->bonded(p->ind2)) { // Needed to avoid a memory leak. Append increments the refcount // of whatever gets added to it, but so does PyInt_FromLong. // Without a decref, the integers created never have their refcount // go to zero, and you leak memory. tmp1 = PyInt_FromLong(p->ind1); tmp2 = PyInt_FromLong(p->ind2); PyList_Append(list1, tmp1); PyList_Append(list2, tmp2); Py_DECREF(tmp1); Py_DECREF(tmp2); } tmp = p->next; free(p); } PyObject *result = PyList_New(2); PyList_SET_ITEM(result, 0, list1); PyList_SET_ITEM(result, 1, list2); return result; }