/** Based on the given atom mask expression determine what molecules are * selected by the mask. * \return A list of atom pairs that mark the beginning and end of each * selected molecule. */ Action_AutoImage::pairList Action_AutoImage::SetupAtomRanges( Topology const& currentParm, std::string const& maskexpr ) { pairList imageList; CharMask Mask1( maskexpr.c_str() ); if (currentParm.SetupCharMask( Mask1 )) return imageList; if (Mask1.None()) return imageList; for (Topology::mol_iterator mol = currentParm.MolStart(); mol != currentParm.MolEnd(); mol++) { int firstAtom = mol->BeginAtom(); int lastAtom = mol->EndAtom(); // Check that each atom in the range is in Mask1 bool rangeIsValid = true; for (int atom = firstAtom; atom < lastAtom; ++atom) { if (!Mask1.AtomInCharMask(atom)) { rangeIsValid = false; break; } } if (rangeIsValid) { imageList.push_back( firstAtom ); imageList.push_back( lastAtom ); } } mprintf("\tMask [%s] corresponds to %zu molecules\n", Mask1.MaskString(), imageList.size()/2); return imageList; }
/** An atom pair list consists of 2 values for each entry, a beginning * index and ending index. For molecules and residues this is the first * and just beyond the last atom; for atoms it is just the atom itself * twice. */ Image::PairType Image::CreatePairList(Topology const& Parm, Mode modeIn, std::string const& maskExpression) { PairType atomPairs; // Set up mask based on desired imaging mode. if ( modeIn == BYMOL || modeIn == BYRES ) { CharMask cmask( maskExpression ); if ( Parm.SetupCharMask( cmask ) ) return atomPairs; cmask.MaskInfo(); if (cmask.None()) return atomPairs; // Set up atom range for each entity to be imaged. if (modeIn == BYMOL) { atomPairs.reserve( Parm.Nmol()*2 ); for (Topology::mol_iterator mol = Parm.MolStart(); mol != Parm.MolEnd(); ++mol) CheckRange( atomPairs, cmask, mol->BeginAtom(), mol->EndAtom()); } else { // BYRES atomPairs.reserve( Parm.Nres()*2 ); for (Topology::res_iterator residue = Parm.ResStart(); residue != Parm.ResEnd(); ++residue) CheckRange( atomPairs, cmask, residue->FirstAtom(), residue->LastAtom() ); } } else { // BYATOM AtomMask imask( maskExpression ); if ( Parm.SetupIntegerMask( imask ) ) return atomPairs; imask.MaskInfo(); if (imask.None()) return atomPairs; atomPairs.reserve( Parm.Natom()*2 ); for (AtomMask::const_iterator atom = imask.begin(); atom != imask.end(); ++atom) { atomPairs.push_back( *atom ); atomPairs.push_back( (*atom)+1 ); } } // mprintf("\tNumber of %ss to be imaged is %zu based on mask '%s'\n", // ModeString[modeIn], atomPairs.size()/2, maskIn.MaskString()); return atomPairs; }
/** Like the strip action, closest will modify the current parm keeping info * for atoms in mask plus the closestWaters solvent molecules. Set up the * vector of MolDist objects, one for every solvent molecule in the original * parm file. Atom masks for each solvent molecule will be set up. */ Action_Closest::RetType Action_Closest::Setup(Topology const& topIn, CoordinateInfo const& cInfoIn) { // If there are no solvent molecules this action is not valid. if (topIn.Nsolvent()==0) { mprintf("Warning: Parm %s does not contain solvent.\n",topIn.c_str()); return Action_Closest::SKIP; } // If # solvent to keep >= solvent in this parm the action is not valid. if (closestWaters_ >= topIn.Nsolvent()) { mprintf("Warning: # solvent to keep (%i) >= # solvent molecules in '%s' (%i)\n", closestWaters_, topIn.c_str(), topIn.Nsolvent()); return Action_Closest::SKIP; } image_.SetupImaging( cInfoIn.TrajBox().Type() ); if (image_.ImagingEnabled()) mprintf("\tDistances will be imaged.\n"); else mprintf("\tImaging off.\n"); // LOOP OVER MOLECULES // 1: Check that all solvent molecules contain same # atoms. Solvent // molecules must be identical for the command to work properly; // the prmtop strip occurs only once so the solvent params become fixed. // 2: Set up a mask for all solvent molecules. SolventMols_.clear(); // NOTE: May not be necessary to init 'solvent' MolDist solvent; solvent.D = 0.0; solvent.mol = 0; SolventMols_.resize(topIn.Nsolvent(), solvent); std::vector<MolDist>::iterator mdist = SolventMols_.begin(); // 3: Set up the soluteMask for all non-solvent molecules. int molnum = 1; int nclosest = 0; int NsolventAtoms = -1; for (Topology::mol_iterator Mol = topIn.MolStart(); Mol != topIn.MolEnd(); ++Mol) { if ( Mol->IsSolvent() ) { // Solvent, check for same # of atoms. if (NsolventAtoms == -1) NsolventAtoms = Mol->NumAtoms(); else if ( NsolventAtoms != Mol->NumAtoms() ) { mprinterr("Error: Solvent molecules in '%s' are not of uniform size.\n" "Error: First solvent mol = %i atoms, solvent mol %i = %i atoms.\n", topIn.c_str(), NsolventAtoms, molnum, (*Mol).NumAtoms()); return Action_Closest::ERR; } // mol here is the output molecule number which is why it starts from 1. mdist->mol = molnum; // Solvent molecule mask mdist->mask.AddAtomRange( Mol->BeginAtom(), Mol->EndAtom() ); // Atoms in the solvent molecule to actually calculate distances to. if (firstAtom_) { mdist->solventAtoms.assign(1, Mol->BeginAtom() ); } else { mdist->solventAtoms.clear(); mdist->solventAtoms.reserve( Mol->NumAtoms() ); for (int svatom = Mol->BeginAtom(); svatom < Mol->EndAtom(); svatom++) mdist->solventAtoms.push_back( svatom ); } if (debug_ > 0) { mprintf("DEBUG:\tSet up mol %i:", mdist->mol); // DEBUG mdist->mask.PrintMaskAtoms("solvent"); // DEBUG mprintf("\n"); // DEBUG } ++mdist; } ++molnum; } // Setup distance atom mask // NOTE: Should ensure that no solvent atoms are selected! if ( topIn.SetupIntegerMask(distanceMask_) ) return Action_Closest::ERR; if (distanceMask_.None()) { mprintf("Warning: Distance mask '%s' contains no atoms.\n", distanceMask_.MaskString()); return Action_Closest::SKIP; } distanceMask_.MaskInfo(); // Check the total number of solvent atoms to be kept. NsolventAtoms *= closestWaters_; mprintf("\tKeeping %i solvent atoms.\n",NsolventAtoms); if (NsolventAtoms < 1) { mprintf("Warning: # of solvent atoms to be kept is < 1.\n"); return Action_Closest::SKIP; } NsolventMolecules_ = (int)SolventMols_.size(); return Action_Closest::OK; }
/** Search for bonds between atoms in residues and atoms in adjacent residues * using distance-based criterion that depends on atomic elements. * \param top Topology to add bonds to. * \param frameIn Frame containing atomic coordinates. * \param offset Offset to add when determining if a bond is present. * \param debug If > 0 print extra info. */ int BondSearch( Topology& top, Frame const& frameIn, double offset, int debug) { mprintf("\tDetermining bond info from distances.\n"); if (frameIn.empty()) { mprinterr("Internal Error: No coordinates set; cannot search for bonds.\n"); return 1; } # ifdef TIMER Timer time_total, time_within, time_between; time_total.Start(); time_within.Start(); # endif // ----- STEP 1: Determine bonds within residues for (Topology::res_iterator res = top.ResStart(); res != top.ResEnd(); ++res) { int stopatom = res->LastAtom(); // Check for bonds between each atom in the residue. for (int atom1 = res->FirstAtom(); atom1 != stopatom; ++atom1) { Atom::AtomicElementType a1Elt = top[atom1].Element(); // If this is a hydrogen and it already has a bond, move on. if (a1Elt==Atom::HYDROGEN && top[atom1].Nbonds() > 0 ) continue; for (int atom2 = atom1 + 1; atom2 != stopatom; ++atom2) { Atom::AtomicElementType a2Elt = top[atom2].Element(); double D2 = DIST2_NoImage(frameIn.XYZ(atom1), frameIn.XYZ(atom2) ); double cutoff2 = Atom::GetBondLength(a1Elt, a2Elt) + offset; cutoff2 *= cutoff2; if (D2 < cutoff2) { top.AddBond(atom1, atom2); // Once a bond has been made to hydrogen move on. if (a1Elt==Atom::HYDROGEN) break; } } } } # ifdef TIMER time_within.Stop(); time_between.Start(); # endif // ----- STEP 2: Determine bonds between adjacent residues Topology::mol_iterator nextmol = top.MolStart(); if (top.Nmol() > 0) ++nextmol; for (Topology::res_iterator res = top.ResStart() + 1; res != top.ResEnd(); ++res) { // If molecule information is already present, check if first atom of // this residue >= first atom of next molecule, which indicates this // residue and the previous residue are in different molecules. if ( (nextmol != top.MolEnd()) && (res->FirstAtom() >= nextmol->BeginAtom()) ) { ++nextmol; continue; } // If this residue is recognized as solvent, no need to check previous or // next residue if ( res->NameIsSolvent() ) { ++res; if (res == top.ResEnd()) break; continue; } // Get previous residue Topology::res_iterator previous_res = res - 1; // If previous residue is recognized as solvent, no need to check previous. if ( previous_res->NameIsSolvent() ) continue; // Get previous residue start atom int startatom = previous_res->FirstAtom(); // Previous residue stop atom, this residue start atom int midatom = res->FirstAtom(); // This residue stop atom int stopatom = res->LastAtom(); // Check for bonds between adjacent residues for (int atom1 = startatom; atom1 != midatom; atom1++) { Atom::AtomicElementType a1Elt = top[atom1].Element(); if (a1Elt==Atom::HYDROGEN) continue; for (int atom2 = midatom; atom2 != stopatom; atom2++) { Atom::AtomicElementType a2Elt = top[atom2].Element(); if (a2Elt==Atom::HYDROGEN) continue; double D2 = DIST2_NoImage(frameIn.XYZ(atom1), frameIn.XYZ(atom2) ); double cutoff2 = Atom::GetBondLength(a1Elt, a2Elt) + offset; cutoff2 *= cutoff2; if (D2 < cutoff2) top.AddBond(atom1, atom2); } } } # ifdef TIMER time_between.Stop(); time_total.Stop(); time_within.WriteTiming(2, "Distances within residues", time_total.Total()); time_between.WriteTiming(2, "Distances between residues", time_total.Total()); time_total.WriteTiming(1, "Total for determining bonds via distances"); # endif if (debug > 0) mprintf("\t%s: %zu bonds to hydrogen, %zu other bonds.\n", top.c_str(), top.BondsH().size(), top.Bonds().size()); return 0; }