/** Print atoms for which the cumulative energy satisfies the given * cutoffs. Also create MOL2 files containing those atoms. */ int Action_Pairwise::PrintCutAtoms(Frame const& frame, int frameNum, EoutType ctype, Darray const& Earray, double cutIn) { AtomMask CutMask; // Hold atoms that satisfy the cutoff Darray CutCharges; // Hold evdw/eelec corresponding to CutMask atoms. if (Eout_ != 0) { if (nb_calcType_==COMPARE_REF) Eout_->Printf("\tPAIRWISE: Cumulative d%s:", CalcString[ctype]); else Eout_->Printf("\tPAIRWISE: Cumulative %s:", CalcString[ctype]); Eout_->Printf(" %s < %.4f, %s > %.4f\n", CalcString[ctype], -cutIn, CalcString[ctype], cutIn); } for (AtomMask::const_iterator atom = Mask0_.begin(); atom != Mask0_.end(); ++atom) { if (fabs(Earray[*atom]) > cutIn) { if (Eout_ != 0) Eout_->Printf("\t\t%6i@%s: %12.4f\n", *atom+1, (*CurrentParm_)[*atom].c_str(), Earray[*atom]); CutMask.AddAtom(*atom); CutCharges.push_back(Earray[*atom]); } } // Write mol2 with atoms satisfying cutoff if (!mol2Prefix_.empty() && !CutMask.None()) { if (WriteCutFrame(frameNum, *CurrentParm_, CutMask, CutCharges, frame, mol2Prefix_ + CutName[ctype])) return 1; } return 0; }
/** Determine VDW long range correction prefactor. */ void Ewald::Setup_VDW_Correction(Topology const& topIn, AtomMask const& maskIn) { Vdw_Recip_term_ = 0.0; NB_ = static_cast<NonbondParmType const*>( &(topIn.Nonbond()) ); if (!NB_->HasNonbond()) { mprintf("Warning: '%s' has no nonbonded parameters. Cannot calculate VDW correction.\n", topIn.c_str()); return; } // Count the number of each unique nonbonded type. Iarray N_vdw_type( NB_->Ntypes(), 0 ); for (AtomMask::const_iterator atm = maskIn.begin(); atm != maskIn.end(); ++atm) N_vdw_type[ topIn[*atm].TypeIndex() ]++; if (debug_ > 0) { mprintf("DEBUG: %zu VDW types.\n", N_vdw_type.size()); for (Iarray::const_iterator it = N_vdw_type.begin(); it != N_vdw_type.end(); ++it) mprintf("\tType %li = %i\n", it-N_vdw_type.begin(), *it); } // Determine correction term from types and LJ B parameters for (unsigned int itype = 0; itype != N_vdw_type.size(); itype++) { unsigned int offset = N_vdw_type.size() * itype; for (unsigned int jtype = 0; jtype != N_vdw_type.size(); jtype++) { unsigned int idx = offset + jtype; int nbidx = NB_->NBindex()[ idx ]; if (nbidx > -1) Vdw_Recip_term_ += N_vdw_type[itype] * N_vdw_type[jtype] * NB_->NBarray()[ nbidx ].B(); } } }
/** Write file containing only cut atoms and energies as charges. */ int Action_Pairwise::WriteCutFrame(int frameNum, Topology const& Parm, AtomMask const& CutMask, Darray const& CutCharges, Frame const& frame, std::string const& outfilename) { if (CutMask.Nselected() != (int)CutCharges.size()) { mprinterr("Error: WriteCutFrame: # of charges (%u) != # mask atoms (%i)\n", CutCharges.size(), CutMask.Nselected()); return 1; } Frame CutFrame(frame, CutMask); Topology* CutParm = Parm.modifyStateByMask( CutMask ); if (CutParm == 0) return 1; // Set new charges for (int i = 0; i != CutParm->Natom(); i++) CutParm->SetAtom(i).SetCharge( CutCharges[i] ); int err = 0; Trajout_Single tout; if (tout.PrepareTrajWrite(outfilename, "multi", CutParm, CoordinateInfo(), 1, TrajectoryFile::MOL2FILE)) { mprinterr("Error: Could not set up cut mol2 file %s\n", outfilename.c_str()); err = 1; } else { tout.WriteSingle(frameNum, CutFrame); tout.EndTraj(); } delete CutParm; return err; }
/** Set up the exclusion list based on the given mask and parm. * \return the total number of interactions, -1 on error. */ int Action_Pairwise::SetupNonbondParm(AtomMask const& maskIn, Topology const& ParmIn) { // Check if LJ parameters present - need at least 2 atoms for it to matter. if (ParmIn.Natom() > 1 && !ParmIn.Nonbond().HasNonbond()) { mprinterr("Error: Topology does not have LJ information.\n"); return -1; } // Determine the actual number of pairwise interactions that will be calcd. // This is ((N^2 - N) / 2) - SUM[ #excluded atoms] int N_interactions = ((maskIn.Nselected() * maskIn.Nselected()) - maskIn.Nselected()) / 2; for (AtomMask::const_iterator at = maskIn.begin(); at != maskIn.end(); ++at) N_interactions -= ParmIn[ *at ].Nexcluded(); // DEBUG - Print total number of interactions for this parm mprintf("\t%i interactions for this parm.\n",N_interactions); // DEBUG - Print exclusion list for each atom /*for (unsigned int atom = 0; atom < exclusionList.size(); atom++) { mprintf("\t%8u:",atom + 1); for (std::vector<int>::iterator eat = exclusionList[atom].begin(); eat != exclusionList[atom].end(); eat++) { mprintf(" %i",*eat + 1); } mprintf("\n"); }*/ return N_interactions; }
// Action_Matrix::MaskToMatResArray() Action_Matrix::MatResArray Action_Matrix::MaskToMatResArray(Topology const& currentParm, AtomMask const& mask) const { MatResArray residues; int currentResNum = -1; matrix_res blank_res; for (int idx = 0; idx != mask.Nselected(); idx++) { int atom1 = mask[idx]; int resNum = currentParm[atom1].ResNum(); if (resNum != currentResNum) { residues.push_back( blank_res ); residues.back().resnum_ = resNum; currentResNum = resNum; } residues.back().maskIdxs_.push_back( idx ); } if (debug_ > 0) { mprintf("DEBUG: BYRES: MASK '%s'\n", mask.MaskString()); for (MatResArray::const_iterator res = residues.begin(); res != residues.end(); ++res) { mprintf("\tRes %i:", res->resnum_+1); for (Iarray::const_iterator it = res->maskIdxs_.begin(); it != res->maskIdxs_.end(); ++it) mprintf(" %i (%i)", mask[*it] + 1, *it); mprintf("\n"); } } return residues; }
// Action_Matrix::FillMassArray() Action_Matrix::Darray Action_Matrix::FillMassArray(Topology const& currentParm, AtomMask const& mask) const { Darray mass; mass.reserve( mask.Nselected() ); for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) mass.push_back( currentParm[ *atom ].Mass() ); return mass; }
// Action_Center::Init() Action::RetType Action_Center::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { // Get keywords useMass_ = actionArgs.hasKey("mass"); ReferenceFrame refFrm = init.DSL().GetReferenceFrame( actionArgs ); if (refFrm.error()) return Action::ERR; // Determine center mode. if (!refFrm.empty()) centerMode_ = REF; else if (actionArgs.hasKey("origin")) centerMode_ = ORIGIN; else if (actionArgs.hasKey("point")) { centerMode_ = POINT; refCenter_[0] = actionArgs.getNextDouble(0.0); refCenter_[1] = actionArgs.getNextDouble(0.0); refCenter_[2] = actionArgs.getNextDouble(0.0); } else centerMode_ = BOXCTR; // Get Masks Mask_.SetMaskString( actionArgs.GetMaskNext() ); // Get reference mask if reference specified. AtomMask refMask; if (centerMode_ == REF) { std::string rMaskExpr = actionArgs.GetMaskNext(); if (rMaskExpr.empty()) rMaskExpr = Mask_.MaskExpression(); refMask.SetMaskString( rMaskExpr ); if (refFrm.Parm().SetupIntegerMask( refMask, refFrm.Coord() )) return Action::ERR; // Get center of mask in reference if (useMass_) refCenter_ = refFrm.Coord().VCenterOfMass( refMask ); else refCenter_ = refFrm.Coord().VGeometricCenter( refMask ); } mprintf(" CENTER: Centering coordinates using"); if (useMass_) mprintf(" center of mass"); else mprintf(" geometric center"); mprintf(" of atoms in mask (%s) to\n", Mask_.MaskString()); switch (centerMode_) { case ORIGIN: mprintf("\tcoordinate origin.\n"); break; case BOXCTR: mprintf("\tbox center.\n"); break; case REF: mprintf("\tcenter of mask (%s) in reference '%s'.\n", refMask.MaskString(), refFrm.refName()); break; case POINT: mprintf("\tpoint (%g, %g, %g).\n", refCenter_[0], refCenter_[1], refCenter_[2]); break; } return Action::OK; }
/** Remove any selected solvent atoms from mask. */ static void removeSelectedSolvent( Topology const& parmIn, AtomMask& mask ) { AtomMask newMask = mask; newMask.ClearSelected(); for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) { int molnum = parmIn[*atom].MolNum(); if (!parmIn.Mol(molnum).IsSolvent()) newMask.AddSelectedAtom( *atom ); } mask = newMask; }
/** Set up atom/residue indices corresponding to atoms selected in mask. * This is done to make creating an atom/residue contact map easier. */ Action_NativeContacts::Iarray Action_NativeContacts::SetupContactIndices( AtomMask const& mask, Topology const& parmIn) { Iarray contactIdx; for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) if (byResidue_) contactIdx.push_back( parmIn[*atom].ResNum() ); else contactIdx.push_back( *atom ); return contactIdx; }
/** Check that all atoms in mask belong to same residue. */ int Action_NMRrst::CheckSameResidue(Topology const& top, AtomMask const& mask) const { if (mask.None()) return -1; int resnum = top[mask[0]].ResNum(); for (AtomMask::const_iterator at = mask.begin(); at != mask.end(); ++at) { int r = top[*at].ResNum(); if (r != resnum) { mprintf("Warning: Mask atom %i %s not in same residue as %i %s\n", *at + 1, top.AtomMaskName(*at).c_str(), mask[0] + 1, top.AtomMaskName(mask[0]).c_str()); } } return resnum; }
void Ewald::CalculateC6params(Topology const& topIn, AtomMask const& maskIn) { Cparam_.clear(); if (lw_coeff_ > 0.0) { for (AtomMask::const_iterator atom = maskIn.begin(); atom != maskIn.end(); ++atom) { double rmin = topIn.GetVDWradius( *atom ); double eps = topIn.GetVDWdepth( *atom ); Cparam_.push_back( 8.0 * (rmin*rmin*rmin) * sqrt(2 * eps) ); if (debug_ > 0) mprintf("DEBUG: C6 param atom %8i = %16.8f\n", *atom+1, Cparam_.back()); } } else Cparam_.assign(maskIn.Nselected(), 0.0); }
/** Calculate full nonbonded energy with PME */ double Ewald_ParticleMesh::CalcEnergy(Frame const& frameIn, AtomMask const& maskIn, double& e_vdw) { t_total_.Start(); Matrix_3x3 ucell, recip; double volume = frameIn.BoxCrd().ToRecip(ucell, recip); double e_self = Self( volume ); double e_vdw_lr_correction; pairList_.CreatePairList(frameIn, ucell, recip, maskIn); // TODO make more efficient int idx = 0; coordsD_.clear(); for (AtomMask::const_iterator atm = maskIn.begin(); atm != maskIn.end(); ++atm, ++idx) { const double* XYZ = frameIn.XYZ( *atm ); coordsD_.push_back( XYZ[0] ); coordsD_.push_back( XYZ[1] ); coordsD_.push_back( XYZ[2] ); } // MapCoords(frameIn, ucell, recip, maskIn); double e_recip = Recip_ParticleMesh( frameIn.BoxCrd() ); // TODO branch double e_vdw6self, e_vdw6recip; if (lw_coeff_ > 0.0) { e_vdw6self = Self6(); e_vdw6recip = LJ_Recip_ParticleMesh( frameIn.BoxCrd() ); if (debug_ > 0) { mprintf("DEBUG: e_vdw6self = %16.8f\n", e_vdw6self); mprintf("DEBUG: Evdwrecip = %16.8f\n", e_vdw6recip); } e_vdw_lr_correction = 0.0; } else { e_vdw6self = 0.0; e_vdw6recip = 0.0; e_vdw_lr_correction = Vdw_Correction( volume ); } e_vdw = 0.0; double e_direct = Direct( pairList_, e_vdw ); if (debug_ > 0) mprintf("DEBUG: Eself= %20.10f Erecip= %20.10f Edirect= %20.10f Evdw= %20.10f\n", e_self, e_recip, e_direct, e_vdw); e_vdw += (e_vdw_lr_correction + e_vdw6self + e_vdw6recip); t_total_.Stop(); return e_self + e_recip + e_direct; }
/** Convert charges to Amber units. Calculate sum of charges and squared charges. */ void Ewald::CalculateCharges(Topology const& topIn, AtomMask const& maskIn) { sumq_ = 0.0; sumq2_ = 0.0; Charge_.clear(); TypeIndices_.clear(); for (AtomMask::const_iterator atom = maskIn.begin(); atom != maskIn.end(); ++atom) { double qi = topIn[*atom].Charge() * Constants::ELECTOAMBER; Charge_.push_back(qi); sumq_ += qi; sumq2_ += (qi * qi); // Store atom type indices for selected atoms. TypeIndices_.push_back( topIn[*atom].TypeIndex() ); } //mprintf("DEBUG: sumq= %20.10f sumq2= %20.10f\n", sumq_, sumq2_); Setup_VDW_Correction( topIn, maskIn ); }
// ----------------------------------------------------------------------------- void Image::WrapToCell0(std::vector<double>& CoordsIn, Frame const& frmIn, AtomMask const& maskIn, Matrix_3x3 const& ucell, Matrix_3x3 const& recip) { double* uFrac = &CoordsIn[0]; int nUatoms = maskIn.Nselected(); int idx; double* result; const double* XYZ; # ifdef _OPENMP # pragma omp parallel private(idx, result, XYZ) { # pragma omp for # endif for (idx = 0; idx < nUatoms; idx++) { result = uFrac + idx*3; XYZ = frmIn.XYZ( maskIn[idx] ); // Convert to frac coords recip.TimesVec( result, XYZ ); // Wrap to primary unit cell result[0] = result[0] - floor(result[0]); result[1] = result[1] - floor(result[1]); result[2] = result[2] - floor(result[2]); // Convert back to Cartesian ucell.TransposeMult( result, result ); } # ifdef _OPENMP } // END pragma omp parallel # endif }
// Action_Center::Init() Action::RetType Action_Center::Init(ArgList& actionArgs, TopologyList* PFL, DataSetList* DSL, DataFileList* DFL, int debugIn) { // Get keywords if (actionArgs.hasKey("origin")) centerMode_ = ORIGIN; else centerMode_ = BOXCTR; useMass_ = actionArgs.hasKey("mass"); ReferenceFrame refFrm = DSL->GetReferenceFrame( actionArgs ); if (refFrm.error()) return Action::ERR; // Get Masks Mask_.SetMaskString( actionArgs.GetMaskNext() ); // Get reference mask if reference specified. AtomMask refMask; if (!refFrm.empty()) { std::string rMaskExpr = actionArgs.GetMaskNext(); if (rMaskExpr.empty()) rMaskExpr = Mask_.MaskExpression(); refMask.SetMaskString( rMaskExpr ); if (refFrm.Parm().SetupIntegerMask( refMask, refFrm.Coord() )) return Action::ERR; // Get center of mask in reference if (useMass_) refCenter_ = refFrm.Coord().VCenterOfMass( refMask ); else refCenter_ = refFrm.Coord().VGeometricCenter( refMask ); centerMode_ = POINT; } mprintf(" CENTER: Centering coordinates using"); if (useMass_) mprintf(" center of mass"); else mprintf(" geometric center"); mprintf(" of atoms in mask (%s) to\n", Mask_.MaskString()); if (centerMode_ == POINT) mprintf("\tcenter of mask (%s) in reference '%s'.\n", refMask.MaskString(), refFrm.refName()); else if (centerMode_ == ORIGIN) mprintf("\tcoordinate origin.\n"); else mprintf("\tbox center.\n"); return Action::OK; }
/** Setup PME calculation. */ int Ewald_ParticleMesh::Setup(Topology const& topIn, AtomMask const& maskIn) { CalculateCharges(topIn, maskIn); // NOTE: These dont need to actually be calculated if the lj ewald coeff // is 0.0, but do it here anyway to avoid segfaults. CalculateC6params( topIn, maskIn ); coordsD_.clear(); coordsD_.reserve( maskIn.Nselected() * 3); SetupExcluded(topIn, maskIn); return 0; }
Action::RetType Action_AtomicCorr::Setup(ActionSetup& setup) { if (setup.Top().SetupIntegerMask( mask_ )) return Action::ERR; mask_.MaskInfo(); if (mask_.None()) return Action::SKIP; if (acorr_mode_ == ATOM) { // Setup output array; labels and index atom_vectors_.clear(); for (AtomMask::const_iterator atom = mask_.begin(); atom != mask_.end(); ++atom) atom_vectors_.push_back( AtomVector(integerToString( *atom + 1 ), *atom) ); } else { std::map<int,AtomMask> rmaskmap; // Find which residues selected atoms belong to. for (AtomMask::const_iterator atom = mask_.begin(); atom != mask_.end(); ++atom) { int current_res = setup.Top()[*atom].ResNum(); std::map<int,AtomMask>::iterator rmask = rmaskmap.find( current_res ); if ( rmask == rmaskmap.end() ) { // Residue not yet in map. AtomMask newmask; newmask.AddAtom( *atom ); rmaskmap.insert( std::pair<int,AtomMask>( current_res, newmask ) ); } else { // Residue is already in map. Add this atom. rmask->second.AddAtom( *atom ); } } // Place selected residues in mask vector and setup output array; labels and index. resmasks_.clear(); atom_vectors_.clear(); for (std::map<int,AtomMask>::const_iterator rmask = rmaskmap.begin(); rmask != rmaskmap.end(); ++rmask) { if (debug_ > 0) mprintf("DBG:\tRes mask for %i has %i atoms\n", rmask->first, rmask->second.Nselected()); resmasks_.push_back( rmask->second ); atom_vectors_.push_back( AtomVector( setup.Top().TruncResNameNum( rmask->first ), rmask->first ) ); } mprintf("\tSelected %zu residues.\n", resmasks_.size()); } return Action::OK; }
/** Set up exclusion lists for selected atoms. */ void Ewald::SetupExcluded(Topology const& topIn, AtomMask const& maskIn) { Excluded_.clear(); Excluded_.resize( maskIn.Nselected() ); // Create a character mask so we can see if atoms in excluded lists are // also selected. CharMask Cmask(maskIn.ConvertToCharMask(), maskIn.Nselected()); // Create a map of atom number to maskIn index. int selectedIdx = 0; Iarray atToIdx( Cmask.Natom(), -1 ); for (int cidx = 0; cidx != Cmask.Natom(); cidx++) if (Cmask.AtomInCharMask(cidx)) atToIdx[cidx] = selectedIdx++; // Loop over selected atoms for (int idx = 0; idx != maskIn.Nselected(); idx++) { // Always exclude self Excluded_[idx].insert( idx ); int at = maskIn[idx]; for (Atom::excluded_iterator excluded_atom = topIn[at].excludedbegin(); excluded_atom != topIn[at].excludedend(); ++excluded_atom) { if (Cmask.AtomInCharMask(*excluded_atom)) { // Find excluded atoms index in maskIn int excluded_idx = atToIdx[*excluded_atom]; Excluded_[idx ].insert( excluded_idx ); Excluded_[excluded_idx].insert( idx ); } } } unsigned int ex_size = 0; for (Iarray2D::const_iterator it = Excluded_.begin(); it != Excluded_.end(); ++it) ex_size += it->size(); mprintf("\tMemory used by full exclusion list: %s\n", ByteString(ex_size * sizeof(int), BYTE_DECIMAL).c_str()); }
/** Set up masks. */ int Cpptraj::MaskArray::SetupMasks(AtomMask const& maskIn, Topology const& topIn) { if (type_ == BY_MOLECULE && topIn.Nmol() < 1) { mprintf("Warning: '%s' has no molecule information, cannot setup by molecule.\n", topIn.c_str()); return 1; } masks_.clear(); if ( maskIn.None() ) { mprintf("Warning: Nothing selected by mask '%s'\n", maskIn.MaskString()); return 0; } int last = -1; int current = 0; maxAtomsPerMask_ = 0; sameNumAtomsPerMask_ = true; for (AtomMask::const_iterator atm = maskIn.begin(); atm != maskIn.end(); ++atm) { switch (type_) { case BY_ATOM : current = *atm; break; case BY_RESIDUE : current = topIn[*atm].ResNum(); break; case BY_MOLECULE : current = topIn[*atm].MolNum(); break; } if (current != last) { if (!masks_.empty()) checkAtomsPerMask( masks_.back().Nselected() ); masks_.push_back( AtomMask() ); masks_.back().SetNatoms( topIn.Natom() ); } masks_.back().AddSelectedAtom( *atm ); last = current; } if (!masks_.empty()) checkAtomsPerMask( masks_.back().Nselected() ); return 0; }
/** Place selected atoms into grid cells. Convert to fractional coords, wrap * into primary cell, then determine grid cell. */ void PairList::GridUnitCell(Frame const& frmIn, Matrix_3x3 const& ucell, Matrix_3x3 const& recip, AtomMask const& maskIn) { // Clear any existing atoms in cells. for (Carray::iterator cell = cells_.begin(); cell != cells_.end(); ++cell) cell->ClearAtoms(); Frac_.clear(); Frac_.reserve( maskIn.Nselected() ); if (frmIn.BoxCrd().Type() == Box::ORTHO) { // Orthogonal imaging for (AtomMask::const_iterator atom = maskIn.begin(); atom != maskIn.end(); ++atom) { const double* XYZ = frmIn.XYZ(*atom); Vec3 fc( XYZ[0]*recip[0], XYZ[1]*recip[4], XYZ[2]*recip[8] ); Vec3 fcw(fc[0]-floor(fc[0]), fc[1]-floor(fc[1]), fc[2]-floor(fc[2])); Vec3 ccw(fcw[0]*ucell[0], fcw[1]*ucell[4], fcw[2]*ucell[8] ); # ifdef DEBUG_PAIRLIST mprintf("DBG: o %6i fc=%7.3f%7.3f%7.3f fcw=%7.3f%7.3f%7.3f ccw=%7.3f%7.3f%7.3f\n", *atom+1, fc[0], fc[1], fc[2], fcw[0], fcw[1], fcw[2], ccw[0], ccw[1], ccw[2]); # endif GridAtom( atom-maskIn.begin(), fcw, ccw ); } } else { // Non-orthogonal imaging for (AtomMask::const_iterator atom = maskIn.begin(); atom != maskIn.end(); ++atom) { Vec3 fc = recip * Vec3(frmIn.XYZ(*atom)); Vec3 fcw(fc[0]-floor(fc[0]), fc[1]-floor(fc[1]), fc[2]-floor(fc[2])); Vec3 ccw = ucell.TransposeMult( fcw ); # ifdef DEBUG_PAIRLIST mprintf("DBG: n %6i fc=%7.3f%7.3f%7.3f fcw=%7.3f%7.3f%7.3f ccw=%7.3f%7.3f%7.3f\n", *atom+1, fc[0], fc[1], fc[2], fcw[0], fcw[1], fcw[2], ccw[0], ccw[1], ccw[2]); # endif GridAtom( atom-maskIn.begin(), fcw, ccw ); } } }
/** Add the atoms in Mask to this mask starting at the specified positon. * Currently only used by Closest for modifying the original stripped * mask with the calculated closest waters. */ void AtomMask::AddMaskAtPosition(AtomMask const& maskIn, int idx) { // NOTE: NO BOUNDS CHECK! for (const_iterator atom = maskIn.begin(); atom != maskIn.end(); atom++) Selected_[idx++] = *atom; }
// Exec_RotateDihedral::Execute() Exec::RetType Exec_RotateDihedral::Execute(CpptrajState& State, ArgList& argIn) { // Get input COORDS set std::string setname = argIn.GetStringKey("crdset"); if (setname.empty()) { mprinterr("Error: Specify COORDS dataset name with 'crdset'.\n"); return CpptrajState::ERR; } DataSet_Coords* CRD = (DataSet_Coords*)State.DSL().FindCoordsSet( setname ); if (CRD == 0) { mprinterr("Error: Could not find COORDS set '%s'\n", setname.c_str()); return CpptrajState::ERR; } if (CRD->Size() < 1) { mprinterr("Error: COORDS set is empty.\n"); return CpptrajState::ERR; } int frame = argIn.getKeyInt("frame", 0); if (frame < 0 || frame >= (int)CRD->Size()) { mprinterr("Error: Specified frame %i is out of range.\n", frame+1); return CpptrajState::ERR; } mprintf(" ROTATEDIHEDRAL: Using COORDS '%s', frame %i\n", CRD->legend(), frame+1); // Get target frame Frame FRM = CRD->AllocateFrame(); CRD->GetFrame(frame, FRM); // Save as reference Frame refFrame = FRM; // Create output COORDS set if necessary DataSet_Coords* OUT = 0; int outframe = 0; std::string outname = argIn.GetStringKey("name"); if (outname.empty()) { // This will not work for TRAJ data sets if (CRD->Type() == DataSet::TRAJ) { mprinterr("Error: Using TRAJ as input set requires use of 'name' keyword for output.\n"); return CpptrajState::ERR; } OUT = CRD; outframe = frame; } else { // Create new output set with 1 empty frame. OUT = (DataSet_Coords*)State.DSL().AddSet( DataSet::COORDS, outname ); if (OUT == 0) return CpptrajState::ERR; OUT->Allocate( DataSet::SizeArray(1, 1) ); OUT->CoordsSetup( CRD->Top(), CRD->CoordsInfo() ); OUT->AddFrame( CRD->AllocateFrame() ); mprintf("\tOutput to set '%s'\n", OUT->legend()); } // Determine whether we are setting or incrementing. enum ModeType { SET = 0, INCREMENT }; ModeType mode = SET; if (argIn.Contains("value")) mode = SET; else if (argIn.Contains("increment")) mode = INCREMENT; else { mprinterr("Error: Specify 'value <value>' or 'increment <increment>'\n"); return CpptrajState::ERR; } double value = argIn.getKeyDouble(ModeStr[mode], 0.0); switch (mode) { case SET: mprintf("\tDihedral will be set to %g degrees.\n", value); break; case INCREMENT: mprintf("\tDihedral will be incremented by %g degrees.\n", value); break; } // Convert to radians value *= Constants::DEGRAD; // Select dihedral atoms int A1, A2, A3, A4; if (argIn.Contains("type")) { // By type ArgList typeArg = argIn.GetStringKey("type"); if (typeArg.empty()) { mprinterr("Error: No dihedral type specified after 'type'\n"); return CpptrajState::ERR; } DihedralSearch dihSearch; dihSearch.SearchForArgs( typeArg ); if (dihSearch.NoDihedralTokens()) { mprinterr("Error: Specified dihedral type not recognized.\n"); return CpptrajState::ERR; } // Get residue int res = argIn.getKeyInt("res", -1); if (res <= 0) { mprinterr("Error: If 'type' specified 'res' must be specified and > 0.\n"); return CpptrajState::ERR; } // Search for dihedrals. User residue #s start from 1. if (dihSearch.FindDihedrals(CRD->Top(), Range(res-1))) return CpptrajState::ERR; DihedralSearch::mask_it dih = dihSearch.begin(); A1 = dih->A0(); A2 = dih->A1(); A3 = dih->A2(); A4 = dih->A3(); } else { // By masks AtomMask m1( argIn.GetMaskNext() ); AtomMask m2( argIn.GetMaskNext() ); AtomMask m3( argIn.GetMaskNext() ); AtomMask m4( argIn.GetMaskNext() ); if (CRD->Top().SetupIntegerMask( m1 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m2 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m3 )) return CpptrajState::ERR; if (CRD->Top().SetupIntegerMask( m4 )) return CpptrajState::ERR; if (m1.Nselected() != 1) return MaskError( m1 ); if (m2.Nselected() != 1) return MaskError( m2 ); if (m3.Nselected() != 1) return MaskError( m3 ); if (m4.Nselected() != 1) return MaskError( m4 ); A1 = m1[0]; A2 = m2[0]; A3 = m3[0]; A4 = m4[0]; } mprintf("\tRotating dihedral defined by atoms '%s'-'%s'-'%s'-'%s'\n", CRD->Top().AtomMaskName(A1).c_str(), CRD->Top().AtomMaskName(A2).c_str(), CRD->Top().AtomMaskName(A3).c_str(), CRD->Top().AtomMaskName(A4).c_str()); // Set mask of atoms that will move during dihedral rotation AtomMask Rmask = DihedralSearch::MovingAtoms(CRD->Top(), A2, A3); // Calculate current value of dihedral double torsion = Torsion( FRM.XYZ(A1), FRM.XYZ(A2), FRM.XYZ(A3), FRM.XYZ(A4) ); // Calculate delta needed to get to target value. double delta; switch (mode) { case SET: delta = value - torsion; break; case INCREMENT: delta = value; break; } mprintf("\tOriginal torsion is %g, rotating by %g degrees.\n", torsion*Constants::RADDEG, delta*Constants::RADDEG); // Set axis of rotation Vec3 axisOfRotation = FRM.SetAxisOfRotation( A2, A3 ); // Calculate rotation matrix for delta. Matrix_3x3 rotationMatrix; rotationMatrix.CalcRotationMatrix(axisOfRotation, delta); // Rotate around axis FRM.Rotate(rotationMatrix, Rmask); // RMS-fit the non-moving part of the coords back on original AtomMask refMask = Rmask; refMask.InvertMask(); FRM.Align( refFrame, refMask ); // Update coords OUT->SetCRD( outframe, FRM ); return CpptrajState::OK; }
static inline Exec::RetType MaskError(AtomMask const& mask) { mprinterr("Error: Mask '%s' selects %i atoms, expected 1.\n", mask.MaskString(), mask.Nselected()); return CpptrajState::ERR; }
/** Calculate non-bonded energy using the nonbondParm array. The total * LJ (vdw) energy is put in ELJ, and the total Coulomb (elec) energy * is put in Eelec. Depending on the value of nb_calcType, each pair * energy is either compared to a reference, distributed over both atoms * evenly in the cumulative array, or reference values are set. If comparing * to a reference structure, pairs for which the energy difference exceeds * the cutoffs are printed. */ void Action_Pairwise::NonbondEnergy(Frame const& frameIn, Topology const& parmIn, AtomMask const& maskIn) { double delta2; NonbondEnergyType refE; ELJ_ = 0.0; Eelec_ = 0.0; std::vector<NonbondEnergyType>::const_iterator refpair = ref_nonbondEnergy_.begin(); // Loop over all atom pairs and set information // Outer loop for (AtomMask::const_iterator maskatom1 = maskIn.begin(); maskatom1 != maskIn.end(); ++maskatom1) { // Get coordinates for first atom. Vec3 coord1 = frameIn.XYZ( *maskatom1 ); // Set up exclusion list for this atom Atom::excluded_iterator excluded_atom = parmIn[*maskatom1].excludedbegin(); // Inner loop for (AtomMask::const_iterator maskatom2 = maskatom1 + 1; maskatom2 != maskIn.end(); ++maskatom2) { // If atom is excluded, just increment to next excluded atom; // otherwise perform energy calc. if ( excluded_atom != parmIn[*maskatom1].excludedend() && *maskatom2 == *excluded_atom ) ++excluded_atom; else { // Calculate the vector pointing from atom2 to atom1 Vec3 JI = coord1 - Vec3(frameIn.XYZ( *maskatom2 )); double rij2 = JI.Magnitude2(); // Normalize double rij = sqrt(rij2); JI /= rij; // LJ energy NonbondType const& LJ = parmIn.GetLJparam(*maskatom1, *maskatom2); double r2 = 1.0 / rij2; double r6 = r2 * r2 * r2; double r12 = r6 * r6; double f12 = LJ.A() * r12; // A/r^12 double f6 = LJ.B() * r6; // B/r^6 double e_vdw = f12 - f6; // (A/r^12)-(B/r^6) ELJ_ += e_vdw; // LJ Force //force=((12*f12)-(6*f6))*r2; // (12A/r^13)-(6B/r^7) //scalarmult(f,JI,F); // Coulomb energy double qiqj = QFAC * parmIn[*maskatom1].Charge() * parmIn[*maskatom2].Charge(); double e_elec = qiqj / rij; Eelec_ += e_elec; // Coulomb Force //force=e_elec/rij; // kes_*(qiqj/r)*(1/r) //scalarmult(f,JI,F); // ---------------------------------------- int atom1 = *maskatom1; int atom2 = *maskatom2; if (nb_calcType_ == COMPARE_REF) { // 1 - Comparison to reference, cumulative dEnergy on atoms // dEvdw double delta_vdw = refpair->evdw - e_vdw; // dEelec double delta_eelec = refpair->eelec - e_elec; // Output if (Eout_ != 0) WriteEnergies(parmIn, atom1, atom2, delta_vdw, delta_eelec, "d"); vdwMat_->Element(atom1, atom2) += delta_vdw; eleMat_->Element(atom1, atom2) += delta_eelec; // Divide the total pair dEvdw between both atoms. delta2 = delta_vdw * 0.5; atom_evdw_[atom1] += delta2; atom_evdw_[atom2] += delta2; // Divide the total pair dEelec between both atoms. delta2 = delta_eelec * 0.5; atom_eelec_[atom1] += delta2; atom_eelec_[atom2] += delta2; } else if (nb_calcType_ == NORMAL) { // 2 - No reference, just cumulative Energy on atoms if (Eout_ != 0) WriteEnergies(parmIn, atom1, atom2, e_vdw, e_elec, ""); vdwMat_->Element(atom1, atom2) += e_vdw; eleMat_->Element(atom1, atom2) += e_elec; // Cumulative evdw - divide between both atoms delta2 = e_vdw * 0.5; atom_evdw_[atom1] += delta2; atom_evdw_[atom2] += delta2; // Cumulative eelec - divide between both atoms delta2 = e_elec * 0.5; atom_eelec_[atom1] += delta2; atom_eelec_[atom2] += delta2; } else { // if nb_calcType_ == SET_REF // 3 - Store the reference nonbond energy for this pair refE.evdw = e_vdw; refE.eelec = e_elec; ref_nonbondEnergy_.push_back( refE ); } ++refpair; // ---------------------------------------- } // END pair not excluded } // END Inner loop } // END Outer loop }
/** Find potential symmetric atoms. All residues up to the last selected * residue are considered. */ int SymmetricRmsdCalc::SetupSymmRMSD(Topology const& topIn, AtomMask const& tgtMask, bool remapIn) { // Allocate space for remapping selected atoms in target frame. This will // also put the correct masses in based on the mask. tgtRemap_.SetupFrameFromMask(tgtMask, topIn.Atoms()); // Create map of original atom numbers to selected indices Iarray SelectedIdx( topIn.Natom(), -1 ); int tgtIdx = 0; for (int originalAtom = 0; originalAtom != topIn.Natom(); ++originalAtom) if ( originalAtom == tgtMask[tgtIdx] ) SelectedIdx[originalAtom] = tgtIdx++; if (debug_ > 0) { mprintf("DEBUG: Original atom -> Selected Index mapping:\n"); for (int originalAtom = 0; originalAtom != topIn.Natom(); ++originalAtom) mprintf("\t%8i -> %8i\n", originalAtom + 1, SelectedIdx[originalAtom] + 1); } // Create initial 1 to 1 atom map for all selected atoms; indices in // SymmetricAtomIndices will correspond to positions in AMap. AMap_.resize( tgtRemap_.Natom() ); // Determine last selected residue. int last_res = topIn[tgtMask.back()].ResNum() + 1; mprintf("\tResidues up to %s will be considered for symmetry correction.\n", topIn.TruncResNameNum(last_res-1).c_str()); // In each residue, determine which selected atoms are symmetric. SymmetricAtomIndices_.clear(); AtomMap resmap; if (debug_ > 1) resmap.SetDebug(1); for (int res = 0; res < last_res; ++res) { AtomMap::AtomIndexArray residue_SymmetricGroups; if (resmap.SymmetricAtoms(topIn, residue_SymmetricGroups, res)) { mprinterr("Error: Finding symmetric atoms in residue '%s'\n", topIn.TruncResNameNum(res).c_str()); return 1; } if (!residue_SymmetricGroups.empty()) { // Which atoms in symmetric groups are selected? bool resHasSelectedSymmAtoms = false; for (AtomMap::AtomIndexArray::const_iterator symmGroup = residue_SymmetricGroups.begin(); symmGroup != residue_SymmetricGroups.end(); ++symmGroup) { Iarray selectedAtomIndices; for (Iarray::const_iterator atnum = symmGroup->begin(); atnum != symmGroup->end(); ++atnum) { if ( SelectedIdx[*atnum] != -1 ) selectedAtomIndices.push_back( SelectedIdx[*atnum] ); // Store tgtMask indices } if (!selectedAtomIndices.empty()) { SymmetricAtomIndices_.push_back( selectedAtomIndices ); resHasSelectedSymmAtoms = true; } } // If remapping and not all atoms in a residue are selected, warn user. // TODO: Should they just be considered even if not selected? if (remapIn && resHasSelectedSymmAtoms) { for (int atom = topIn.Res(res).FirstAtom(); atom != topIn.Res(res).LastAtom(); ++atom) if (SelectedIdx[atom] == -1) { mprintf("Warning: Not all atoms selected in residue '%s'. Re-mapped\n" "Warning: structures may appear distorted.\n", topIn.TruncResNameNum(res).c_str()); break; } } } } if (debug_ > 0) { mprintf("DEBUG: Potential Symmetric Atom Groups:\n"); for (AtomIndexArray::const_iterator symmatoms = SymmetricAtomIndices_.begin(); symmatoms != SymmetricAtomIndices_.end(); ++symmatoms) { mprintf("\t%8u) ", symmatoms - SymmetricAtomIndices_.begin()); for (Iarray::const_iterator atom = symmatoms->begin(); atom != symmatoms->end(); ++atom) mprintf(" %s(%i)", topIn.AtomMaskName(tgtMask[*atom]).c_str(), tgtMask[*atom] + 1); mprintf("\n"); } } return 0; }
/** Set up each mask/integer loop. */ int ControlBlock_For::SetupBlock(CpptrajState& State, ArgList& argIn) { mprintf(" Setting up 'for' loop.\n"); Vars_.clear(); Topology* currentTop = 0; static const char* TypeStr[] = { "ATOMS ", "RESIDUES ", "MOLECULES ", "MOL_FIRST_RES ", "MOL_LAST_RES " }; static const char* OpStr[] = {"+=", "-=", "<", ">"}; description_.assign("for ("); int MaxIterations = -1; int iarg = 0; while (iarg < argIn.Nargs()) { // Advance to next unmarked argument. while (iarg < argIn.Nargs() && argIn.Marked(iarg)) iarg++; if (iarg == argIn.Nargs()) break; // Determine 'for' type ForType ftype = UNKNOWN; bool isMaskFor = true; int argToMark = iarg; if ( argIn[iarg] == "atoms" ) ftype = ATOMS; else if ( argIn[iarg] == "residues" ) ftype = RESIDUES; else if ( argIn[iarg] == "molecules" ) ftype = MOLECULES; else if ( argIn[iarg] == "molfirstres" ) ftype = MOLFIRSTRES; else if ( argIn[iarg] == "mollastres" ) ftype = MOLLASTRES; else if ( argIn[iarg].find(";") != std::string::npos ) { isMaskFor = false; ftype = INTEGER; } // If type is still unknown, check for list. if (ftype == UNKNOWN) { if (iarg+1 < argIn.Nargs() && argIn[iarg+1] == "in") { ftype = LIST; isMaskFor = false; argToMark = iarg+1; } } // Exit if type could not be determined. if (ftype == UNKNOWN) { mprinterr("Error: for loop type not specfied.\n"); return 1; } argIn.MarkArg(argToMark); Vars_.push_back( LoopVar() ); LoopVar& MH = Vars_.back(); int Niterations = -1; // Set up for specific type if (description_ != "for (") description_.append(", "); // ------------------------------------------- if (isMaskFor) { // {atoms|residues|molecules} <var> inmask <mask> [TOP KEYWORDS] if (argIn[iarg+2] != "inmask") { mprinterr("Error: Expected 'inmask', got %s\n", argIn[iarg+2].c_str()); return 1; } AtomMask currentMask; if (currentMask.SetMaskString( argIn.GetStringKey("inmask") )) return 1; MH.varType_ = ftype; Topology* top = State.DSL().GetTopByIndex( argIn ); if (top != 0) currentTop = top; if (currentTop == 0) return 1; MH.varname_ = argIn.GetStringNext(); if (MH.varname_.empty()) { mprinterr("Error: 'for inmask': missing variable name.\n"); return 1; } MH.varname_ = "$" + MH.varname_; // Set up mask if (currentTop->SetupIntegerMask( currentMask )) return 1; currentMask.MaskInfo(); if (currentMask.None()) return 1; // Set up indices if (MH.varType_ == ATOMS) MH.Idxs_ = currentMask.Selected(); else if (MH.varType_ == RESIDUES) { int curRes = -1; for (AtomMask::const_iterator at = currentMask.begin(); at != currentMask.end(); ++at) { int res = (*currentTop)[*at].ResNum(); if (res != curRes) { MH.Idxs_.push_back( res ); curRes = res; } } } else if (MH.varType_ == MOLECULES || MH.varType_ == MOLFIRSTRES || MH.varType_ == MOLLASTRES) { int curMol = -1; for (AtomMask::const_iterator at = currentMask.begin(); at != currentMask.end(); ++at) { int mol = (*currentTop)[*at].MolNum(); if (mol != curMol) { if (MH.varType_ == MOLECULES) MH.Idxs_.push_back( mol ); else { int res; if (MH.varType_ == MOLFIRSTRES) res = (*currentTop)[ currentTop->Mol( mol ).BeginAtom() ].ResNum(); else // MOLLASTRES res = (*currentTop)[ currentTop->Mol( mol ).EndAtom()-1 ].ResNum(); MH.Idxs_.push_back( res ); } curMol = mol; } } } Niterations = (int)MH.Idxs_.size(); description_.append(std::string(TypeStr[MH.varType_]) + MH.varname_ + " inmask " + currentMask.MaskExpression()); // ------------------------------------------- } else if (ftype == INTEGER) { // [<var>=<start>;[<var><OP><end>;]<var><OP>[<value>]] MH.varType_ = ftype; ArgList varArg( argIn[iarg], ";" ); if (varArg.Nargs() < 2 || varArg.Nargs() > 3) { mprinterr("Error: Malformed 'for' loop variable.\n" "Error: Expected '[<var>=<start>;[<var><OP><end>;]<var><OP>[<value>]]'\n" "Error: Got '%s'\n", argIn[iarg].c_str()); return 1; } // First argument: <var>=<start> ArgList startArg( varArg[0], "=" ); if (startArg.Nargs() != 2) { mprinterr("Error: Malformed 'start' argument.\n" "Error: Expected <var>=<start>, got '%s'\n", varArg[0].c_str()); return 1; } MH.varname_ = startArg[0]; if (!validInteger(startArg[1])) { // TODO allow variables mprinterr("Error: Start argument must be an integer.\n"); return 1; } else MH.start_ = convertToInteger(startArg[1]); // Second argument: <var><OP><end> size_t pos0 = MH.varname_.size(); size_t pos1 = pos0 + 1; MH.endOp_ = NO_OP; int iargIdx = 1; if (varArg.Nargs() == 3) { iargIdx = 2; if ( varArg[1][pos0] == '<' ) MH.endOp_ = LESS_THAN; else if (varArg[1][pos0] == '>') MH.endOp_ = GREATER_THAN; if (MH.endOp_ == NO_OP) { mprinterr("Error: Unrecognized end op: '%s'\n", varArg[1].substr(pos0, pos1-pos0).c_str()); return 1; } std::string endStr = varArg[1].substr(pos1); if (!validInteger(endStr)) { // TODO allow variables mprinterr("Error: End argument must be an integer.\n"); return 1; } else MH.end_ = convertToInteger(endStr); } // Third argument: <var><OP>[<value>] pos1 = pos0 + 2; MH.incOp_ = NO_OP; bool needValue = false; if ( varArg[iargIdx][pos0] == '+' ) { if (varArg[iargIdx][pos0+1] == '+') { MH.incOp_ = INCREMENT; MH.inc_ = 1; } else if (varArg[iargIdx][pos0+1] == '=') { MH.incOp_ = INCREMENT; needValue = true; } } else if ( varArg[iargIdx][pos0] == '-' ) { if (varArg[iargIdx][pos0+1] == '-' ) { MH.incOp_ = DECREMENT; MH.inc_ = 1; } else if (varArg[iargIdx][pos0+1] == '=') { MH.incOp_ = DECREMENT; needValue = true; } } if (MH.incOp_ == NO_OP) { mprinterr("Error: Unrecognized increment op: '%s'\n", varArg[iargIdx].substr(pos0, pos1-pos0).c_str()); return 1; } if (needValue) { std::string incStr = varArg[iargIdx].substr(pos1); if (!validInteger(incStr)) { mprinterr("Error: increment value is not a valid integer.\n"); return 1; } MH.inc_ = convertToInteger(incStr); if (MH.inc_ < 1) { mprinterr("Error: Extra '-' detected in increment.\n"); return 1; } } // Description MH.varname_ = "$" + MH.varname_; std::string sval = integerToString(MH.start_); description_.append("(" + MH.varname_ + "=" + sval + "; "); std::string eval; if (iargIdx == 2) { // End argument present eval = integerToString(MH.end_); description_.append(MH.varname_ + std::string(OpStr[MH.endOp_]) + eval + "; "); // Check end > start for increment, start > end for decrement int maxval, minval; if (MH.incOp_ == INCREMENT) { if (MH.start_ >= MH.end_) { mprinterr("Error: start must be less than end for increment.\n"); return 1; } minval = MH.start_; maxval = MH.end_; } else { if (MH.end_ >= MH.start_) { mprinterr("Error: end must be less than start for decrement.\n"); return 1; } minval = MH.end_; maxval = MH.start_; } // Figure out number of iterations Niterations = (maxval - minval) / MH.inc_; if (((maxval-minval) % MH.inc_) > 0) Niterations++; } description_.append( MH.varname_ + std::string(OpStr[MH.incOp_]) + integerToString(MH.inc_) + ")" ); // If decrementing just negate value if (MH.incOp_ == DECREMENT) MH.inc_ = -MH.inc_; // DEBUG //mprintf("DEBUG: start=%i endOp=%i end=%i incOp=%i val=%i startArg=%s endArg=%s\n", // MH.start_, (int)MH.endOp_, MH.end_, (int)MH.incOp_, MH.inc_, // MH.startArg_.c_str(), MH.endArg_.c_str()); // ------------------------------------------- } else if (ftype == LIST) { // <var> in <string0>[,<string1>...] MH.varType_ = ftype; // Variable name MH.varname_ = argIn.GetStringNext(); if (MH.varname_.empty()) { mprinterr("Error: 'for in': missing variable name.\n"); return 1; } MH.varname_ = "$" + MH.varname_; // Comma-separated list of strings std::string listArg = argIn.GetStringNext(); if (listArg.empty()) { mprinterr("Error: 'for in': missing comma-separated list of strings.\n"); return 1; } ArgList list(listArg, ","); if (list.Nargs() < 1) { mprinterr("Error: Could not parse '%s' for 'for in'\n", listArg.c_str()); return 1; } for (int il = 0; il != list.Nargs(); il++) { // Check if file name expansion should occur if (list[il].find_first_of("*?") != std::string::npos) { File::NameArray files = File::ExpandToFilenames( list[il] ); for (File::NameArray::const_iterator fn = files.begin(); fn != files.end(); ++fn) MH.List_.push_back( fn->Full() ); } else MH.List_.push_back( list[il] ); } Niterations = (int)MH.List_.size(); // Description description_.append( MH.varname_ + " in " + listArg ); } // Check number of values if (MaxIterations == -1) MaxIterations = Niterations; else if (Niterations != -1 && Niterations != MaxIterations) { mprintf("Warning: # iterations %i != previous # iterations %i\n", Niterations, MaxIterations); MaxIterations = std::min(Niterations, MaxIterations); } } mprintf("\tLoop will execute for %i iterations.\n", MaxIterations); if (MaxIterations < 1) { mprinterr("Error: Loop has less than 1 iteration.\n"); return 1; } description_.append(") do"); return 0; }
/** Set up bond parameters for bonds for which both atoms present in mask. */ void Action_CheckStructure::SetupBondList(AtomMask const& iMask, Topology const& top) { CharMask cMask( iMask.ConvertToCharMask(), iMask.Nselected() ); ProcessBondArray(top.Bonds(), top.BondParm(), cMask); ProcessBondArray(top.BondsH(), top.BondParm(), cMask); }
// DEBUG static void DebugContactList(AtomMask const& mask, Topology const& parmIn) { for (AtomMask::const_iterator atom = mask.begin(); atom != mask.end(); ++atom) mprintf("\tPotential Contact %li: %s\n", atom - mask.begin(), parmIn.AtomMaskName(*atom).c_str()); }