/** Set angle up for this parmtop. Get masks etc. */ Action::RetType Action_Energy::Setup(Topology* currentParm, Topology** parmAddress) { if (currentParm->SetupCharMask(Mask1_)) return Action::ERR; if (Mask1_.None()) { mprinterr("Warning: Mask '%s' selects no atoms.\n", Mask1_.MaskString()); return Action::ERR; } Mask1_.MaskInfo(); Imask_ = AtomMask(Mask1_.ConvertToIntMask(), Mask1_.Natom()); currentParm_ = currentParm; return Action::OK; }
/** Set angle up for this parmtop. Get masks etc. */ Action::RetType Action_Energy::Setup(ActionSetup& setup) { if (setup.Top().SetupCharMask(Mask1_)) return Action::ERR; if (Mask1_.None()) { mprintf("Warning: Mask '%s' selects no atoms.\n", Mask1_.MaskString()); return Action::SKIP; } Mask1_.MaskInfo(); Imask_ = AtomMask(Mask1_.ConvertToIntMask(), Mask1_.Natom()); // Check for LJ terms for (calc_it calc = Ecalcs_.begin(); calc != Ecalcs_.end(); ++calc) if ((*calc == N14 || *calc == NBD) && !setup.Top().Nonbond().HasNonbond()) { mprinterr("Error: Nonbonded energy calc requested but topology '%s'\n" "Error: does not have non-bonded parameters.\n", setup.Top().c_str()); return Action::ERR; } currentParm_ = setup.TopAddress(); return Action::OK; }
/** 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; }
// ----------------------------------------------------------------------------- // Action_NMRrst::Init() Action::RetType Action_NMRrst::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { # ifdef MPI if (init.TrajComm().Size() > 1) { mprinterr("Error: 'nmrrst' action does not work with > 1 thread (%i threads currently).\n", init.TrajComm().Size()); return Action::ERR; } # endif debug_ = debugIn; // Get Keywords Image_.InitImaging( !(actionArgs.hasKey("noimage")) ); useMass_ = !(actionArgs.hasKey("geom")); findNOEs_ = actionArgs.hasKey("findnoes"); findOutput_ = init.DFL().AddCpptrajFile(actionArgs.GetStringKey("findout"), "Found NOEs", DataFileList::TEXT, true); specOutput_ = init.DFL().AddCpptrajFile(actionArgs.GetStringKey("specout"), "Specified NOEs", DataFileList::TEXT, true); if (findOutput_ == 0 || specOutput_ == 0) return Action::ERR; resOffset_ = actionArgs.getKeyInt("resoffset", 0); DataFile* outfile = init.DFL().AddDataFile( actionArgs.GetStringKey("out"), actionArgs ); max_cut_ = actionArgs.getKeyDouble("cut", 6.0); strong_cut_ = actionArgs.getKeyDouble("strongcut", 2.9); medium_cut_ = actionArgs.getKeyDouble("mediumcut", 3.5); weak_cut_ = actionArgs.getKeyDouble("weakcut", 5.0); series_ = actionArgs.hasKey("series"); std::string rstfilename = actionArgs.GetStringKey("file"); viewrst_ = actionArgs.GetStringKey("viewrst"); setname_ = actionArgs.GetStringKey("name"); if (setname_.empty()) setname_ = init.DSL().GenerateDefaultName("NMR"); nframes_ = 0; // Atom Mask Mask_.SetMaskString( actionArgs.GetMaskNext() ); // Pairs specified on command line. std::string pair1 = actionArgs.GetStringKey("pair"); while (!pair1.empty()) { std::string pair2 = actionArgs.GetStringNext(); if (pair2.empty()) { mprinterr("Error: Only one mask specified for pair (%s)\n", pair1.c_str()); return Action::ERR; } Pairs_.push_back( MaskPairType(AtomMask(pair1), AtomMask(pair2)) ); pair1 = actionArgs.GetStringKey("pair"); } // Check that something will be done if (!findNOEs_ && rstfilename.empty() && Pairs_.empty()) { mprinterr("Error: Must specify restraint file, 'pair', and/or 'findnoes'.\n"); return Action::ERR; } // Read in NMR restraints. if (!rstfilename.empty()) { if (ReadNmrRestraints( rstfilename )) return Action::ERR; } // Set up distances. int num_noe = 1; for (noeDataArray::iterator noe = NOEs_.begin(); noe != NOEs_.end(); ++noe, ++num_noe) { // Translate any ambiguous atom names TranslateAmbiguous( noe->aName1_ ); TranslateAmbiguous( noe->aName2_ ); // Create mask expressions from resnum/atom name noe->dMask1_.SetMaskString( MaskExpression( noe->resNum1_, noe->aName1_ ) ); noe->dMask2_.SetMaskString( MaskExpression( noe->resNum2_, noe->aName2_ ) ); // Dataset to store distances AssociatedData_NOE noeData(noe->bound_, noe->boundh_, noe->rexp_); MetaData md(setname_, "NOE", num_noe); md.SetLegend( noe->dMask1_.MaskExpression() + " and " + noe->dMask2_.MaskExpression()); md.SetScalarMode( MetaData::M_DISTANCE ); md.SetScalarType( MetaData::NOE ); noe->dist_ = init.DSL().AddSet(DataSet::DOUBLE, md); if (noe->dist_==0) return Action::ERR; noe->dist_->AssociateData( &noeData ); // Add dataset to data file if (outfile != 0) outfile->AddDataSet( noe->dist_ ); } masterDSL_ = init.DslPtr(); mprintf("Warning: *** THIS ACTION IS EXPERIMENTAL. ***\n"); mprintf(" NMRRST: %zu NOEs from NMR restraint file.\n", NOEs_.size()); mprintf("\tShifting residue numbers in restraint file by %i\n", resOffset_); // DEBUG - print NOEs for (noeDataArray::const_iterator noe = NOEs_.begin(); noe != NOEs_.end(); ++noe) mprintf("\t'%s' %f < %f < %f\n", noe->dist_->legend(), noe->bound_, noe->rexp_, noe->boundh_); if (findNOEs_) { mprintf("\tSearching for potential NOEs. Max cutoff is %g Ang.\n", max_cut_); mprintf("\tNOE distance criteria (Ang.): S= %g, M= %g, W= %g\n", strong_cut_, medium_cut_, weak_cut_); if (series_) mprintf("\tDistance data for NOEs less than cutoff will be saved as '%s[foundNOE]'.\n", setname_.c_str()); mprintf("\tFound NOEs will be written to '%s'\n", findOutput_->Filename().full()); } if (!Pairs_.empty()) { mprintf("\tSpecified NOE pairs:\n"); for (MaskPairArray::const_iterator mp = Pairs_.begin(); mp != Pairs_.end(); ++mp) mprintf("\t\t[%s] to [%s]\n", mp->first.MaskString(), mp->second.MaskString()); mprintf("\tSpecified NOE data will be written to '%s'\n", specOutput_->Filename().full()); } if (!Image_.UseImage()) mprintf("\tNon-imaged"); else mprintf("\tImaged"); if (useMass_) mprintf(", center of mass.\n"); else mprintf(", geometric center.\n"); if (!viewrst_.empty()) mprintf("\tTopologies corresponding to found NOEs will be written to '%s'\n", viewrst_.c_str()); return Action::OK; }
// Action_Density::Init() Action::RetType Action_Density::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { # ifdef MPI trajComm_ = init.TrajComm(); # endif DataFile* outfile = init.DFL().AddDataFile(actionArgs.GetStringKey("out"), actionArgs); std::string dsname = actionArgs.GetStringKey("name"); if (actionArgs.hasKey("x") ) { axis_ = DX; area_coord_[0] = DY; area_coord_[1] = DZ; } else if (actionArgs.hasKey("y") ) { axis_ = DY; area_coord_[0] = DX; area_coord_[1] = DZ; } else if (actionArgs.hasKey("z") ) { axis_ = DZ; area_coord_[0] = DX; area_coord_[1] = DY; } property_ = NUMBER; if (actionArgs.hasKey("number") ) property_ = NUMBER; else if (actionArgs.hasKey("mass") ) property_ = MASS; else if (actionArgs.hasKey("charge") ) property_ = CHARGE; else if (actionArgs.hasKey("electron") ) property_ = ELECTRON; binType_ = CENTER; if (actionArgs.hasKey("bincenter")) binType_ = CENTER; else if (actionArgs.hasKey("binedge") ) binType_ = EDGE; delta_ = actionArgs.getKeyDouble("delta", 0.01); if (delta_ <= 0) { mprinterr("Error: Delta must be > 0.0\n"); return Action::ERR; } // for compatibility with ptraj, ignored because we rely on the atom code to // do the right thing, see Atom.{h,cpp} if (actionArgs.hasKey("efile")) mprintf("Warning: The 'efile' keyword is deprecated.\n"); // read the rest of the command line as a series of masks std::string maskstr; unsigned int idx = 1; while ( (maskstr = actionArgs.GetMaskNext() ) != emptystring) { masks_.push_back( AtomMask(maskstr) ); if (dsname.empty()) dsname = init.DSL().GenerateDefaultName("DENSITY"); MetaData MD(dsname, "avg", idx); MD.SetTimeSeries( MetaData::NOT_TS ); // Hold average density DataSet* ads = init.DSL().AddSet( DataSet::DOUBLE, MD ); if (ads == 0) return Action::ERR; ads->SetLegend( NoWhitespace(masks_.back().MaskExpression()) ); AvSets_.push_back( ads ); if (outfile != 0) outfile->AddDataSet( ads ); // Hold SD density MD.SetAspect("sd"); DataSet* sds = init.DSL().AddSet( DataSet::DOUBLE, MD ); if (sds == 0) return Action::ERR; sds->SetLegend( NoWhitespace("sd(" + masks_.back().MaskExpression() + ")") ); SdSets_.push_back( sds ); if (outfile != 0) outfile->AddDataSet( sds ); # ifdef MPI ads->SetNeedsSync( false ); // Populated in Print() sds->SetNeedsSync( false ); # endif idx++; } if (masks_.empty()) { // If no masks assume we want total system density. if (dsname.empty()) dsname = actionArgs.GetStringNext(); density_ = init.DSL().AddSet(DataSet::DOUBLE, dsname, "DENSITY"); if (density_ == 0) return Action::ERR; if (outfile != 0) outfile->AddDataSet( density_ ); image_.InitImaging( true ); // Hijack delta for storing sum of masses delta_ = 0.0; } else { // Density selected by mask(s) along an axis density_ = 0; histograms_.resize(masks_.size() ); } mprintf(" DENSITY:"); if (density_ == 0) { const char* binStr[] = {"center", "edge"}; mprintf(" Determining %s density for %zu masks.\n", PropertyStr_[property_], masks_.size()); mprintf("\troutine version: %s\n", ROUTINE_VERSION_STRING); mprintf("\tDelta is %f\n", delta_); mprintf("\tAxis is %s\n", AxisStr_[axis_]); mprintf("\tData set name is '%s'\n", dsname.c_str()); mprintf("\tData set aspect [avg] holds the mean, aspect [sd] holds standard deviation.\n"); mprintf("\tBin coordinates will be to bin %s.\n", binStr[binType_]); } else { mprintf(" No masks specified, calculating total system density in g/cm^3.\n"); mprintf("\tData set name is '%s'\n", density_->legend()); } if (outfile != 0) mprintf("\tOutput to '%s'\n", outfile->DataFilename().full()); return Action::OK; }
/** Given the structure of a molecule and its normal mode vibrational * frequencies this routine uses standard statistical mechanical * formulas for an ideal gas (in the canonical ensemble, see, * for example, d. a. mcquarrie, "statistical thermodynamics", * harper & row, new york, 1973, chapters 5, 6, and 8) to compute * the entropy, heat capacity, and internal energy. * The si system of units is used internally. Conversion to units * more familiar to most chemists is made for output. * * \param outfile output file, should already be open. * \param temp temperature * \param patm pressure, in atmospheres */ int DataSet_Modes::Thermo( CpptrajFile& outfile, int ilevel, double temp, double patm) const { // avgcrd_ Contains coordinates in Angstroms // mass_ Contains masses in amu. // nmodes_ Number of eigenvectors (already converted to frequencies) // evalues_ vibrational frequencies, in cm**-1 and in ascending order double rtemp, rtemp1, rtemp2, rtemp3; // ----- Constants ------------------- const double thresh = 900.0; // vibrational frequency threshold const double tokg = 1.660531e-27; // kilograms per amu. const double boltz = 1.380622e-23; // boltzman constant, in joules per kelvin. const double planck = 6.626196e-34; // planck constant, in joule-seconds. // const double avog = 6.022169e+23; // avogadro constant, in mol**(-1). const double jpcal = 4.18674e+00; // joules per calorie. const double tomet = 1.0e-10; // metres per Angstrom. const double hartre = 4.35981e-18; // joules per hartree. const double pstd = 1.01325e+05; // Standard pressure in pascals // compute the gas constant, pi, pi**2, and e. // compute the conversion factors cal per joule and kcal per joule. // const double gas = avog * boltz; // pi = four * datan(one) const double pipi = Constants::PI * Constants::PI; const double e = exp(1.0); const double tocal = 1.0 / jpcal; const double tokcal = tocal / 1000.0; if (!outfile.IsOpen()) { mprinterr("Internal Error: DataSet_Modes::Thermo(): output file is not open.\n"); return 1; } // print the temperature and pressure. outfile.Printf("\n *******************\n"); outfile.Printf( " - Thermochemistry -\n"); outfile.Printf( " *******************\n\n"); outfile.Printf("\n temperature %9.3f kelvin\n pressure %9.5f atm\n",temp,patm); double pressure = pstd * patm; double rt = Constants::GASK_J * temp; // compute and print the molecular mass in amu, then convert to // kilograms. double weight = 0.0; for (Darray::const_iterator m = mass_.begin(); m != mass_.end(); ++m) weight += *m; outfile.Printf(" molecular mass (principal isotopes) %11.5f amu\n", weight); weight *= tokg; //trap non-unit multiplicities. //if (multip != 1) { // outfile.Printf("\n Warning-- assumptions made about the electronic partition function\n"); // outfile.Printf( " are not valid for multiplets!\n\n"); //} // compute contributions due to translation: // etran-- internal energy // ctran-- constant v heat capacity // stran-- entropy double dum1 = boltz * temp; double dum2 = pow(Constants::TWOPI, 1.5); double arg = pow(dum1, 1.5) / planck; arg = (arg / pressure) * (dum1 / planck); arg = arg * dum2 * (weight / planck); arg = arg * sqrt(weight) * exp(2.5); double stran = Constants::GASK_J * log(arg); double etran = 1.5 * rt; double ctran = 1.5 * Constants::GASK_J; // Compute contributions due to electronic motion: // It is assumed that the first electronic excitation energy // is much greater than kt and that the ground state has a // degeneracy of one. Under these conditions the electronic // partition function can be considered to be unity. The // ground electronic state is taken to be the zero of // electronic energy. // for monatomics print and return. if (avgcrd_.size() <= 3){ outfile.Printf("\n internal energy: %10.3f joule/mol %10.3f kcal/mol\n", etran, etran * tokcal); outfile.Printf( " entropy: %10.3f joule/k-mol %10.3f cal/k-mol\n", stran, stran * tocal); outfile.Printf( " heat capacity cv: %10.3f joule/k-mol %10.3f cal/k-mol\n", ctran, ctran * tocal); return 0; } Frame AVG; AVG.SetupFrameXM( avgcrd_, mass_ ); // Allocate workspace memory // vtemp vibrational temperatures, in kelvin. // evibn contribution to e from the vibration n. // cvibn contribution to cv from the vibration n. // svibn contribution to s from the vibration n. double* WorkSpace = new double[ 4 * nmodes_ ]; double* vtemp = WorkSpace; double* evibn = WorkSpace + nmodes_; double* cvibn = WorkSpace + nmodes_*2; double* svibn = WorkSpace + nmodes_*3; // compute contributions due to rotation. // Compute the principal moments of inertia, get the rotational // symmetry number, see if the molecule is linear, and compute // the rotational temperatures. Note the imbedded conversion // of the moments to SI units. Matrix_3x3 Inertia; AVG.CalculateInertia( AtomMask(0, AVG.Natom()), Inertia ); // NOTE: Diagonalize_Sort sorts evals/evecs in descending order, but // thermo() expects ascending. // pmom principal moments of inertia, in amu-bohr**2 and in ascending order. Vec3 pmom; Inertia.Diagonalize_Sort( pmom ); rtemp = pmom[0]; pmom[0] = pmom[2]; pmom[2] = rtemp; outfile.Printf("\n principal moments of inertia (nuclei only) in amu-A**2:\n"); outfile.Printf( " %12.2f%12.2f%12.2f\n", pmom[0], pmom[1], pmom[2]); bool linear = false; // Symmetry number: only for linear molecules. for others symmetry number is unity double sn = 1.0; if (AVG.Natom() <= 2) { linear = true; if (AVG.Mass(0) == AVG.Mass(1)) sn = 2.0; } outfile.Printf("\n rotational symmetry number %3.0f\n", sn); double con = planck / (boltz*8.0*pipi); con = (con / tokg) * (planck / (tomet*tomet)); if (linear) { rtemp = con / pmom[2]; if (rtemp < 0.2) { outfile.Printf("\n Warning-- assumption of classical behavior for rotation\n"); outfile.Printf( " may cause significant error\n"); } outfile.Printf("\n rotational temperature (kelvin) %12.5f\n", rtemp); } else { rtemp1 = con / pmom[0]; rtemp2 = con / pmom[1]; rtemp3 = con / pmom[2]; if (rtemp1 < 0.2) { outfile.Printf("\n Warning-- assumption of classical behavior for rotation\n"); outfile.Printf( " may cause significant error\n"); } outfile.Printf("\n rotational temperatures (kelvin) %12.5f%12.5f%12.5f\n", rtemp1, rtemp2, rtemp3); } // erot-- rotational contribution to internal energy. // crot-- rotational contribution to cv. // srot-- rotational contribution to entropy. double erot, crot, srot; if (linear) { erot = rt; crot = Constants::GASK_J; arg = (temp/rtemp) * (e/sn); srot = Constants::GASK_J * log(arg); } else { erot = 1.5 * rt; crot = 1.5 * Constants::GASK_J; arg = sqrt(Constants::PI*e*e*e) / sn; double dum = (temp/rtemp1) * (temp/rtemp2) * (temp/rtemp3); arg = arg * sqrt(dum); srot = Constants::GASK_J * log(arg); } // compute contributions due to vibration. // compute vibrational temperatures and zero point vibrational // energy. only real frequencies are included in the analysis. // ndof = 3*natoms - 6 - nimag // if (nimag .ne. 0) write(iout,1210) nimag // if (linear) ndof = ndof + 1 int ndof = nmodes_; // (---iff is the first frequency to include in thermo:) int iff; if (ilevel != 0) iff = 0; else if (linear) iff = 5; else iff = 6; con = planck / boltz; double ezpe = 0.0; for (int i = 0; i < ndof; ++i) { vtemp[i] = evalues_[i+iff] * con * 3.0e10; ezpe += evalues_[i+iff] * 3.0e10; } ezpe = 0.5 * planck * ezpe; outfile.Printf("\n zero point vibrational energy %12.1f (joules/mol) \n" " %12.5f (kcal/mol)\n" " %12.7f (hartree/particle)\n", ezpe*Constants::NA, ezpe*tokcal*Constants::NA, ezpe/hartre); // compute the number of vibrations for which more than 5% of an // assembly of molecules would exist in vibrational excited states. // special printing for these modes is done to allow the user to // easily take internal rotations into account. the criterion // corresponds roughly to a low frequency of 1.9(10**13) hz, or // 625 cm**(-1), or a vibrational temperature of 900 k. int lofreq = 0; for (int i = 0; i < ndof; ++i) if (vtemp[i] < thresh) ++lofreq; if (lofreq != 0) { outfile.Printf("\n Warning-- %3i vibrations have low frequencies and may represent hindered \n", lofreq); outfile.Printf( " internal rotations. The contributions printed below assume that these \n"); outfile.Printf( " really are vibrations.\n"); } // compute: // evib-- the vibrational component of the internal energy. // cvib-- the vibrational component of the heat capacity. // svib-- the vibrational component of the entropy. double evib = 0.0; double cvib = 0.0; double svib = 0.0; double scont; for (int i = 0; i < ndof; ++i) { // compute some common factors. double tovt = vtemp[i] / temp; double etovt = exp(tovt); double em1 = etovt - 1.0; // compute contributions due to the i'th vibration. double econt = tovt * (0.5 + 1.0/em1); double ccont = etovt * pow(tovt/em1,2.0); double argd = 1.0 - 1.0/etovt; if (argd > 1.0e-7) scont = tovt/em1 - log(argd); else { scont = 0.0; outfile.Printf(" warning: setting vibrational entropy to zero for mode %i with vtemp = %f\n", i+1, vtemp[i]); } // if (lofreq .ge. i) then evibn[i] = econt * rt; cvibn[i] = ccont * Constants::GASK_J; svibn[i] = scont * Constants::GASK_J; // end if evib += econt; cvib += ccont; svib += scont; } evib *= rt; cvib *= Constants::GASK_J; svib *= Constants::GASK_J; // the units are now: // e-- joules/mol // c-- joules/mol-kelvin // s-- joules/mol-kelvin double etot = etran + erot + evib; double ctot = ctran + crot + cvib; double stot = stran + srot + svib; // print the sum of the hartree-fock energy and the thermal energy. // call tread(501,gen,47,1,47,1,0) // esum = gen(32) + etot/avog/hartre // write(iout,1230) esum // convert to the following and print // e-- kcal/mol // c-- cal/mol-kelvin // s-- cal/mol-kelvin etran = etran * tokcal; ctran = ctran * tocal; stran = stran * tocal; erot = erot * tokcal; crot = crot * tocal; srot = srot * tocal; evib = evib * tokcal; cvib = cvib * tocal; svib = svib * tocal; etot = etran + erot + evib; ctot = ctran + crot + cvib; stot = stran + srot + svib; for (int i = 0; i < ndof; ++i) { evibn[i] *= tokcal; cvibn[i] *= tocal; svibn[i] *= tocal; } outfile.Printf("\n\n freq. E Cv S\n"); outfile.Printf( " cm**-1 kcal/mol cal/mol-kelvin cal/mol-kelvin\n"); outfile.Printf( "--------------------------------------------------------------------------------\n"); outfile.Printf( " Total %11.3f %11.3f %11.3f\n",etot,ctot,stot); outfile.Printf( " translational %11.3f %11.3f %11.3f\n",etran,ctran,stran); outfile.Printf( " rotational %11.3f %11.3f %11.3f\n",erot,crot,srot); outfile.Printf( " vibrational %11.3f %11.3f %11.3f\n",evib,cvib,svib); for (int i = 0; i < iff; ++i) outfile.Printf(" %5i%10.3f\n", i+1, evalues_[i]); for (int i = 0; i < ndof; ++i) { outfile.Printf(" %5i%10.3f %11.3f %11.3f %11.3f\n",i+iff+1, evalues_[i+iff], evibn[i], cvibn[i], svibn[i]); } delete[] WorkSpace; return 0; }
// Action_Density::Init() Action::RetType Action_Density::Init(ArgList& actionArgs, ActionInit& init, int debugIn) { # ifdef MPI if (init.TrajComm().Size() > 1) { mprinterr("Error: 'density' action does not work with > 1 thread (%i threads currently).\n", init.TrajComm().Size()); return Action::ERR; } # endif DataFile* outfile = init.DFL().AddDataFile(actionArgs.GetStringKey("out"), actionArgs); std::string dsname = actionArgs.GetStringKey("name"); if (dsname.empty()) dsname = init.DSL().GenerateDefaultName("DENSITY"); if (actionArgs.hasKey("x") ) { axis_ = DX; area_coord_[0] = DY; area_coord_[1] = DZ; } else if (actionArgs.hasKey("y") ) { axis_ = DY; area_coord_[0] = DX; area_coord_[1] = DZ; } else if (actionArgs.hasKey("z") ) { axis_ = DZ; area_coord_[0] = DX; area_coord_[1] = DY; } property_ = NUMBER; if (actionArgs.hasKey("number") ) property_ = NUMBER; if (actionArgs.hasKey("mass") ) property_ = MASS; if (actionArgs.hasKey("charge") ) property_ = CHARGE; if (actionArgs.hasKey("electron") ) property_ = ELECTRON; delta_ = actionArgs.getKeyDouble("delta", 0.01); // for compatibility with ptraj, ignored because we rely on the atom code to // do the right thing, see Atom.{h,cpp} if (actionArgs.hasKey("efile")) mprintf("Warning: The 'efile' keyword is deprecated.\n"); // read the rest of the command line as a series of masks std::string maskstr; unsigned int idx = 1; while ( (maskstr = actionArgs.GetMaskNext() ) != emptystring) { masks_.push_back( AtomMask(maskstr) ); MetaData MD(dsname, "avg", idx); MD.SetTimeSeries( MetaData::NOT_TS ); // Hold average density DataSet* ads = init.DSL().AddSet( DataSet::DOUBLE, MD ); if (ads == 0) return Action::ERR; ads->SetLegend( NoWhitespace(masks_.back().MaskExpression()) ); AvSets_.push_back( ads ); if (outfile != 0) outfile->AddDataSet( ads ); // Hold SD density MD.SetAspect("sd"); DataSet* sds = init.DSL().AddSet( DataSet::DOUBLE, MD ); if (sds == 0) return Action::ERR; sds->SetLegend( NoWhitespace("sd(" + masks_.back().MaskExpression() + ")") ); SdSets_.push_back( sds ); if (outfile != 0) outfile->AddDataSet( sds ); # ifdef MPI ads->SetNeedsSync( false ); // Populated in Print() sds->SetNeedsSync( false ); # endif idx++; } if (masks_.empty()) { mprinterr("Error: No masks specified.\n"); return Action::ERR; } minus_histograms_.resize(masks_.size() ); plus_histograms_.resize(masks_.size() ); mprintf(" DENSITY: Determining %s density for %zu masks.\n", PropertyStr_[property_], masks_.size()); mprintf("\troutine version: %s\n", ROUTINE_VERSION_STRING); mprintf("\tDelta is %f\n", delta_); mprintf("\tAxis is %s\n", AxisStr_[axis_]); mprintf("\tData set name is '%s'\n", dsname.c_str()); if (outfile != 0) mprintf("\tOutput to '%s'\n", outfile->DataFilename().full()); return Action::OK; }