/** Set angle up for this parmtop. Get masks etc. */ Action::RetType Action_AreaPerMol::Setup(Topology* currentParm, Topology** parmAddress) { // Needs box info if (currentParm->BoxType() == Box::NOBOX) { mprintf("Warning: No box information for '%s', cannot calculate area.\n", currentParm->c_str()); return Action::ERR; } // Probably will not work for non-orthorhombic cells if (currentParm->BoxType() != Box::ORTHO) mprintf("Warning: Box is not orthorhombic, calculated area may not be correct.\n"); // Determine how many molecules are selected if (Mask1_.MaskStringSet()) { if (currentParm->SetupCharMask(Mask1_)) return Action::ERR; if (Mask1_.None()) { mprinterr("Warning: Mask '%s' selects no atoms.\n", Mask1_.MaskString()); return Action::ERR; } Nmols_ = 0.0; for (Topology::mol_iterator mol = currentParm->MolStart(); mol != currentParm->MolEnd(); ++mol) { if (Mask1_.AtomsInCharMask(mol->BeginAtom(), mol->EndAtom())) Nmols_ += 1.0; } mprintf("\tMask '%s' selects %.0f molecules.\n", Mask1_.MaskString(), Nmols_); if (Nmols_ < 1.0) return Action::ERR; Nmols_ /= Nlayers_; mprintf("\tArea per %.0f molecules (%0.f layers) will be determined.\n", Nmols_, Nlayers_); } return Action::OK; }
/** 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; }
/** Set up solute and solvent masks. If no solvent mask was specified use * solvent information in the current topology. */ Action::RetType Action_Watershell::Setup(ActionSetup& setup) { // Set up solute mask if (setup.Top().SetupIntegerMask( soluteMask_ )) return Action::ERR; if ( soluteMask_.None() ) { mprintf("Warning: No atoms in solute mask [%s].\n",soluteMask_.MaskString()); return Action::SKIP; } // Set up solvent mask if (!solventmaskexpr_.empty()) { if (setup.Top().SetupIntegerMask( solventMask_ )) return Action::ERR; } else { solventMask_.ResetMask(); for (Topology::mol_iterator mol = setup.Top().MolStart(); mol != setup.Top().MolEnd(); ++mol) { if ( mol->IsSolvent() ) solventMask_.AddAtomRange( mol->BeginAtom(), mol->EndAtom() ); } } if ( solventMask_.None() ) { if (!solventmaskexpr_.empty()) mprintf("Warning: No solvent atoms selected by mask [%s]\n", solventmaskexpr_.c_str()); else mprintf("Warning: No solvent atoms in topology %s\n",setup.Top().c_str()); return Action::SKIP; } SetupImaging( setup.CoordInfo().TrajBox().Type() ); // Create space for residues # ifdef _OPENMP // Only re-allocate for larger # of residues if ( setup.Top().Nres() > NactiveResidues_ ) { if (activeResidues_thread_ != 0) { // Deallocate each thread for (int i = 0; i < NactiveResidues_; ++i) delete[] activeResidues_thread_[i]; } else { // Initial thread allocation needed activeResidues_thread_ = new int*[ numthreads_ ]; } // Allocate each thread for (int i = 0; i < numthreads_; ++i) { activeResidues_thread_[i] = new int[ setup.Top().Nres() ]; std::fill( activeResidues_thread_[i], activeResidues_thread_[i] + setup.Top().Nres(), 0 ); } } NactiveResidues_ = setup.Top().Nres(); # else activeResidues_.resize( setup.Top().Nres(), 0 ); # endif // Store current Parm CurrentParm_ = setup.TopAddress(); return Action::OK; }
/** 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; }
/** Set LCPO surface area calc parameters for this parmtop if not already set. * Get the mask, and check that the atoms in mask belong to solute. */ Action::RetType Action_Surf::Setup(Topology* currentParm, Topology** parmAddress) { SurfInfo SI; if (currentParm->SetupIntegerMask( Mask1_ )) return Action::ERR; if (Mask1_.None()) { mprintf("Warning: Mask '%s' corresponds to 0 atoms.\n", Mask1_.MaskString()); return Action::ERR; } mprintf("\tLCPO surface area will be calculated for %i atoms.\n",Mask1_.Nselected()); // Setup surface area calc for this parm. // Check that each atom in Mask1 is part of solute // Create a separate mask for building the atom neighbor list that only // includes atoms with vdw radius > 2.5. Consider all atoms for icosa, only // non-H's for LCPO atomi_neighborMask_.ResetMask(); atomi_noNeighborMask_.ResetMask(); atomj_neighborMask_.ResetMask(); SurfaceInfo_neighbor_.clear(); SurfaceInfo_noNeighbor_.clear(); int soluteAtoms = 0; for (AtomMask::const_iterator atomi = Mask1_.begin(); atomi!=Mask1_.end(); atomi++) { int molNum = (*currentParm)[ *atomi ].MolNum(); if (currentParm->Mol( molNum ).IsSolvent()) { mprinterr("Error: Atom %i in mask %s does not belong to solute.\n", *atomi+1, Mask1_.MaskString()); return Action::ERR; } ++soluteAtoms; SetAtomLCPO( *currentParm, *atomi, &SI ); if (SI.vdwradii > 2.5) { atomi_neighborMask_.AddAtom(*atomi); SurfaceInfo_neighbor_.push_back( SI ); } else { atomi_noNeighborMask_.AddAtom(*atomi); SurfaceInfo_noNeighbor_.push_back( SI ); } } mprintf("\t%i solute atoms.\n",soluteAtoms); if (soluteAtoms <= 0) { mprinterr("Error: No solute atoms in %s.\n",currentParm->c_str()); return Action::ERR; } // From all solute atoms, create a second mask for building atom // neighbor list that only includes atoms with vdw radius > 2.5. VDW_.clear(); VDW_.reserve( soluteAtoms ); if (currentParm->Nmol() < 1) { mprinterr("Error: Topology %s has no molecule information, LCPO surface area\n" "Error: cannot be calculated. Try using 'fixatomorder' prior to 'surf' command.\n", currentParm->c_str()); return Action::ERR; } for (Topology::mol_iterator mol = currentParm->MolStart(); mol != currentParm->MolEnd(); ++mol) { if (!mol->IsSolvent()) { for (int atomj=mol->BeginAtom(); atomj != mol->EndAtom(); atomj++) { SetAtomLCPO( *currentParm, atomj, &SI ); VDW_.push_back( SI.vdwradii ); if (SI.vdwradii > 2.5) atomj_neighborMask_.AddAtom(atomj); } } } return Action::OK; }
// Action_RandomizeIons::Setup() Action::RetType Action_RandomizeIons::Setup(ActionSetup& setup) { n_solvent_ = setup.Top().Nsolvent(); if (n_solvent_ < 1) { mprinterr("Error: This command only works if solvent information has been specified.\n"); return Action::ERR; } // Set up ion mask if (setup.Top().SetupIntegerMask( ions_ )) return Action::ERR; if ( ions_.None() ) { mprintf("Warning: Ion mask '%s' has no atoms.\n", ions_.MaskString()); return Action::SKIP; } mprintf("\tIon mask is '%s' (%i atoms)\n", ions_.MaskString(), ions_.Nselected()); // Set up the around mask if necessary if (around_.MaskStringSet()) { if (setup.Top().SetupIntegerMask( around_ )) return Action::ERR; if ( around_.None() ) { mprintf("Warning: Around mask '%s' has no atoms.\n", around_.MaskString()); } else { mprintf("\tAround mask is '%s' (%i atoms)\n", around_.MaskString(), around_.Nselected()); } } // Check that each ion is only a single atom residue. // NOTE: Should this be a molecule check instead? If so can then get rid of ResSize for (AtomMask::const_iterator ion = ions_.begin(); ion != ions_.end(); ++ion) { int res = setup.Top()[*ion].ResNum(); if (debug_ > 0) mprintf("\tAtom %i is in residue %i which is %i atoms\n", *ion+1, res+1, setup.Top().Res( res ).NumAtoms() ); if ( setup.Top().Res( res ).NumAtoms() > 1 ) { mprintf("Warning: randomizeions: Ion atom %i belongs to residue %i which\n", *ion + 1, res + 1); mprintf("Warning: contains more than 1 atom (%i)!\n", setup.Top().Res( res ).NumAtoms()); } } // Check the solvent information to make sure that each solvent listed has the // same number of atoms in each molecule; otherwise a uniform trajectory is not // possible and therefore this command will be ignored. // Also save the start and end atom of each solvent molecule. int NsolventAtoms = -1; solventStart_.clear(); solventEnd_.clear(); solventStart_.reserve( n_solvent_ ); solventEnd_.reserve( n_solvent_ ); for (Topology::mol_iterator Mol = setup.Top().MolStart(); Mol != setup.Top().MolEnd(); ++Mol) { if ( Mol->IsSolvent() ) { if (NsolventAtoms == -1) NsolventAtoms = Mol->NumAtoms(); else if ( NsolventAtoms != Mol->NumAtoms() ) { mprinterr("Error: Solvent molecules in %s are not of uniform size.\n", setup.Top().c_str()); mprinterr("Error: First solvent mol = %i atoms, this solvent mol = %i atoms.\n", NsolventAtoms, Mol->NumAtoms()); return Action::ERR; } solventStart_.push_back( Mol->BeginAtom() ); solventEnd_.push_back( Mol->EndAtom() ); } } image_.SetupImaging( setup.CoordInfo().TrajBox().Type() ); // Allocate solvent molecule mask solvent_.resize( n_solvent_ ); return Action::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; }
/** Set up solute and solvent masks. If no solvent mask was specified use * solvent information in the current topology. */ Action::RetType Action_Watershell::Setup(ActionSetup& setup) { // Set up solute mask if (setup.Top().SetupIntegerMask( soluteMask_ )) return Action::ERR; soluteMask_.MaskInfo(); if ( soluteMask_.None() ) { mprintf("Warning: No atoms in solute mask [%s].\n",soluteMask_.MaskString()); return Action::SKIP; } if (solventMask_.MaskStringSet()) { // Set up solvent mask if (setup.Top().SetupIntegerMask( solventMask_ )) return Action::ERR; solventMask_.MaskInfo(); } else { // Use all solvent atoms. solventMask_.ResetMask(); // Set number of atoms; needed for CharMask conversion. solventMask_.SetNatoms( setup.Top().Natom() ); for (Topology::mol_iterator mol = setup.Top().MolStart(); mol != setup.Top().MolEnd(); ++mol) if ( mol->IsSolvent() ) solventMask_.AddAtomRange( mol->BeginAtom(), mol->EndAtom() ); mprintf("\tSelecting all solvent atoms (%i total)\n", solventMask_.Nselected()); } if ( solventMask_.None() ) { if ( solventMask_.MaskStringSet() ) mprintf("Warning: No solvent atoms selected by mask [%s]\n", solventMask_.MaskString()); else mprintf("Warning: No solvent atoms in topology %s\n", setup.Top().c_str()); return Action::SKIP; } #ifdef CUDA // Since we are using the 'closest' kernels under the hood, all solvent mols // must have the same size. int first_solvent_mol = setup.Top()[ solventMask_[0] ].MolNum(); NAtoms_ = setup.Top().Mol( first_solvent_mol ).NumAtoms(); for (AtomMask::const_iterator atm = solventMask_.begin(); atm != solventMask_.end(); ++atm) { int mol = setup.Top()[*atm].MolNum(); if (NAtoms_ != setup.Top().Mol( mol ).NumAtoms()) { mprinterr("Error: CUDA version of 'watershell' requires all solvent mols be same size.\n"); return Action::ERR; } } // Determine how many solvent molecules are selected NsolventMolecules_ = 0; CharMask cMask( solventMask_.ConvertToCharMask(), solventMask_.Nselected() ); for (Topology::mol_iterator mol = setup.Top().MolStart(); mol != setup.Top().MolEnd(); ++mol) if ( cMask.AtomsInCharMask( mol->BeginAtom(), mol->EndAtom() ) ) NsolventMolecules_++; // Sanity check if ( (NsolventMolecules_ * NAtoms_) != solventMask_.Nselected() ) { mprinterr("Error: CUDA version of 'watershell' requires all atoms in solvent mols be selected.\n"); return Action::ERR; } // Allocate space for selected solvent atom coords and distances V_atom_coords_.resize( NsolventMolecules_ * NAtoms_ * 3, 0.0 ); V_distances_.resize( NsolventMolecules_ ); #else /* CUDA */ // Allocate space to record status of each solvent molecule. // NOTE: Doing this by residue instead of by molecule does waste some memory, // but it means watershell can be used even if no molecule info present. # ifdef _OPENMP // Each thread needs space to record residue status to avoid clashes for (std::vector<Iarray>::iterator it = shellStatus_thread_.begin(); it != shellStatus_thread_.end(); ++it) it->assign( setup.Top().Nres(), 0 ); # else shellStatus_.assign( setup.Top().Nres(), 0 ); # endif #endif /* CUDA */ // Set up imaging image_.SetupImaging( setup.CoordInfo().TrajBox().Type() ); if (image_.ImagingEnabled()) mprintf("\tImaging is on.\n"); else mprintf("\tImaging is off.\n"); // Allocate temp space for selected solute atom coords. soluteCoords_.resize( soluteMask_.Nselected() * 3 ); // Store current topology CurrentParm_ = setup.TopAddress(); return Action::OK; }