// Execute Method bool Export::process(DUQ& duq, ProcessPool& procPool) { /* * Export data from the target Configuration(s) */ // Loop over target Configurations for (RefListItem<Configuration,bool>* ri = targetConfigurations_.first(); ri != NULL; ri = ri->next) { // Grab Configuration pointer Configuration* cfg = ri->item; // Retrieve control parameters from Configuration const char* saveTrajectory = variableAsChar(cfg, "SaveTrajectory"); /* * Save XYZ Trajectory */ if (!DUQSys::isEmpty(saveTrajectory)) { Messenger::print("Export: Appending to trajectory output file '%s'...\n", cfg->outputCoordinatesFile()); // Only the pool master saves the data if (procPool.isMaster()) { // Open the file LineParser parser; if (!parser.appendOutput(saveTrajectory)) { parser.closeFiles(); procPool.stop(); return false; } else if (!writeConfigurationXYZ(parser, cfg, cfg->name())) { Messenger::print("Export: Failed to append to trajectory file.\n"); parser.closeFiles(); procPool.stop(); return false; } procPool.proceed(); } else if (!procPool.decision()) return false; Messenger::print("Export: Finished appending trajectory file.\n"); } } return true; }
// Load Species information from XYZ file bool Species::loadFromXYZ(const char* filename) { Messenger::print("Loading XYZ data from file '%s'\n", filename); // Open the specified file... LineParser parser; parser.openInput(filename); if (!parser.isFileGoodForReading()) { Messenger::error("Couldn't open XYZ file '%s'.\n", filename); return false; } // Clear any existing data clear(); // Simple format - first line is number of atoms, next line is title, then follow atoms/coordinates, one atom per line parser.getArgsDelim(LineParser::Defaults); int nAtoms = parser.argi(0); parser.readNextLine(LineParser::Defaults); name_ = parser.line(); int el, success; for (int n=0; n<nAtoms; ++n) { success = parser.getArgsDelim(LineParser::Defaults); if (success != 0) { parser.closeFiles(); Messenger::error("Couldn't read Atom %i from file '%s'\n", n+1, filename); return false; } el = PeriodicTable::find(parser.argc(0)); if (el == -1) el = 0; SpeciesAtom* i = addAtom(el, parser.argd(1), parser.argd(2),parser.argd(3)); if (parser.hasArg(4)) i->setCharge(parser.argd(4)); } Messenger::print("Succesfully loaded XYZ data from file '%s'.\n", filename); parser.closeFiles(); return true; }
/* * \brief Perform some MD * \details Evolve the current Configuration using a simple molecular dynamics algorithm. * * This is a parallel routine, with processes operating in process groups. */ bool DUQ::md(Configuration& cfg, double cutoffDistance, int nSteps, double deltaT) { // Check input values if necessary if (cutoffDistance < 0.0) cutoffDistance = pairPotentialRange_; const double cutoffSq = cutoffDistance * cutoffDistance; const double temperature = cfg.temperature(); bool writeTraj = false; bool calcEnergy = true; int writeFreq = 10; // Print summary of parameters Messenger::print("MD: Number of steps = %i\n", nSteps); Messenger::print("MD: Cutoff distance is %f\n", cutoffDistance); Messenger::print("MD: Timestep = %10.3e ps\n", deltaT); if (writeTraj) Messenger::print("MD: Trajectory file '%s' will be appended.\n"); else Messenger::print("MD: Trajectory file off.\n"); Messenger::print("MD: Energy %s be calculated at each step.\n", calcEnergy ? "will" : "will not"); Messenger::print("MD: Summary will be written every %i step(s).\n", writeFreq); // Create force arrays as simple double arrays (easier to sum with MPI) - others are Vec3<double> arrays Array<double> mass(cfg.nAtoms()), fx(cfg.nAtoms()), fy(cfg.nAtoms()), fz(cfg.nAtoms()); Array< Vec3<double> > a(cfg.nAtoms()), v(cfg.nAtoms()), deltaR(cfg.nAtoms()); // Variables int n, maxDeltaId; Atom* atoms = cfg.atoms(); Atom* i; double maxDelta, deltaSq, massSum, tInstant, ke, tScale, pe; double deltaTSq = deltaT*deltaT; Vec3<double> vCom; double maxForce = 100.0; /* * Calculation Begins */ // Assign random velocities to start... (grab atomic masses at the same time...) Messenger::print("Assigning random velocities...\n"); vCom.zero(); massSum = 0.0; for (n=0; n<cfg.nAtoms(); ++n) { i = cfg.atom(n); v[n].x = exp(DUQMath::random()-0.5) / sqrt(TWOPI); v[n].y = exp(DUQMath::random()-0.5) / sqrt(TWOPI); v[n].z = exp(DUQMath::random()-0.5) / sqrt(TWOPI); mass[n] = PeriodicTable::element(i->element()).isotope(0)->atomicWeight(); vCom += v[n] * mass[n]; massSum += mass[n]; } // Remove velocity shift vCom /= massSum; v -= vCom; // Calculate instantaneous temperature // J = kg m2 s-2 --> 10 J = g Ang2 ps-2 // If ke is in units of [g mol-1 Angstroms2 ps-2] then must use kb in units of 10 J mol-1 K-1 (= 0.8314462) const double kb = 0.8314462; ke = 0.0; pe = 0.0; for (n=0; n<cfg.nAtoms(); ++n) ke += 0.5 * mass[n] * v[n].dp(v[n]); tInstant = ke * 2.0 / (3.0 * cfg.nAtoms() * kb); // Rescale velocities for desired temperature tScale = sqrt(temperature / tInstant); for (n=0; n<cfg.nAtoms(); ++n) v[n] *= tScale; // Open trajectory file (if requested) LineParser trajParser; if (writeTraj) { Dnchar trajectoryFile = cfg.name(); trajectoryFile.strcat(".md.xyz"); if (Comm.master()) { if ((!trajParser.openOutput(trajectoryFile, true)) || (!trajParser.isFileGoodForWriting())) { Messenger::error("Failed to open MD trajectory output file '%s'.\n", trajectoryFile.get()); Comm.decide(false); return false; } Comm.decide(true); } else if (!Comm.decision()) return false; } // Write header to screen if (calcEnergy) Messenger::print(" Step T(K) K.E.(kJ/mol) P.E.(kJ/mol) Etot(kJ/mol)\n"); else Messenger::print(" Step T(K) K.E.(kj/mol)\n"); // Start a timer Timer timer; // Ready to do MD propagation of system timer.start(); Comm.resetAccumulatedTime(); for (int step=0; step<nSteps; ++step) { // deltaT = 0.001; // deltaTSq = deltaT*deltaT; // // Velocity Verlet first stage (A) and zero forces // // A: r(t+dt) = r(t) + v(t)*dt + 0.5*a(t)*dt**2 // // A: v(t+dt/2) = v(t) + 0.5*a(t)*dt // // B: a(t+dt) = F(t+dt)/m // // B: v(t+dt) = v(t+dt/2) + 0.5*a(t+dt)*dt // maxDelta = 0.0; // maxDeltaId = -1; // for (n=0; n<cfg.nAtoms(); ++n) // { // // Calculate position deltas and determine maximum displacement for current timestep // deltaR[n] = v[n]*deltaT + a[n]*0.5*deltaTSq; // deltaSq = deltaR[n].magnitudeSq(); // if (deltaSq > maxDelta) // { // maxDelta = deltaSq; // maxDeltaId = n; // } // } // maxDelta = sqrt(maxDelta); // Messenger::print("Current timestep (%e) will give a maximum displacement of %f Angstroms\n", deltaT, maxDelta); // if (step > 0) // { // do // { // deltaT *= (v[maxDeltaId]*deltaT + a[maxDeltaId]*0.5*deltaTSq).magnitude() > maxDisplacement ? 0.99 : 1.01; // deltaTSq = deltaT*deltaT; // } while (fabs((v[maxDeltaId]*deltaT + a[maxDeltaId]*0.5*deltaTSq).magnitude() - maxDisplacement) > (maxDisplacement*0.05)); // // Adjust timestep to give maximum movement and avoid explosion // // dR/dT = v + a*deltaT // // printf("Deriv = %f %f\n", (v[maxDeltaId]+a[maxDeltaId]*deltaT).magnitude(), (v[maxDeltaId]+a[maxDeltaId]*deltaT).magnitude() / (maxDelta - 0.1)); // // deltaT = 1.0 / ((v[maxDeltaId]+a[maxDeltaId]*deltaT).magnitude() / 0.1); // // printf("xxx = %f %f\n", 1.0 / deltaT, (maxDelta/maxDisplacement) * (v[maxDeltaId]+a[maxDeltaId]*deltaT).magnitude()); // // // deltaT = 0.000564480; // // deltaT = 1.0 / ((maxDelta/maxDisplacement) * (v[maxDeltaId]+a[maxDeltaId]*deltaT).magnitude()); // // deltaT = deltaT/2.0; // printf("New DeltaT = %f\n", deltaT); // } // // TEST - Check max displacement with new deltaT // maxDelta = 0.0; // for (n=0; n<cfg.nAtoms(); ++n) // { // // Calculate position deltas and determine maximum displacement for current timestep // deltaR[n] = v[n]*deltaT + a[n]*0.5*deltaTSq; // deltaSq = deltaR[n].magnitudeSq(); // if (deltaSq > maxDelta) maxDelta = deltaSq; // } // printf("New max delta = %f\n", sqrt(maxDelta)); for (n=0; n<cfg.nAtoms(); ++n) { i = cfg.atom(n); // Propagate positions (by whole step)... i->translateCoordinates(v[n]*deltaT + a[n]*0.5*deltaTSq); // ...velocities (by half step)... v[n] += a[n]*0.5*deltaT; // Zero force ready for next calculation fx[n] = 0.0; fy[n] = 0.0; fz[n] = 0.0; } // Grain coordinates will have changed... cfg.updateGrains(); // Calculate forces - must multiply by 100.0 to convert from kJ/mol to 10J/mol (internal MD units) totalForces(cfg, fx, fy, fz, cutoffSq); fx *= 100.0; fy *= 100.0; fz *= 100.0; // // Cap forces // for (n=0; n<cfg.nAtoms(); ++n) // { // // Calculate position deltas and determine maximum displacement for current timestep // if (fx[n] < maxForce) fx[n] = -maxForce; // else if (fx[n] > maxForce) fx[n] = maxForce; // if (fy[n] < maxForce) fy[n] = -maxForce; // else if (fy[n] > maxForce) fy[n] = maxForce; // if (fz[n] < maxForce) fz[n] = -maxForce; // else if (fz[n] > maxForce) fz[n] = maxForce; // } // Velocity Verlet second stage (B) and velocity scaling // A: r(t+dt) = r(t) + v(t)*dt + 0.5*a(t)*dt**2 // A: v(t+dt/2) = v(t) + 0.5*a(t)*dt // B: a(t+dt) = F(t+dt)/m // B: v(t+dt) = v(t+dt/2) + 0.5*a(t+dt)*dt ke = 0.0; for (n=0; n<cfg.nAtoms(); ++n) { // Determine new accelerations a[n].set(fx[n], fy[n], fz[n]); a[n] /= mass[n]; // ..and finally velocities again (by second half-step) v[n] += a[n]*0.5*deltaT; ke += 0.5 * mass[n] * v[n].dp(v[n]); } // Rescale velocities for desired temperature tInstant = ke * 2.0 / (3.0 * cfg.nAtoms() * kb); tScale = sqrt(temperature / tInstant); v *= tScale; // Convert ke from 10J mol-1 to kJ/mol ke *= 0.01; // Calculate step energy if (calcEnergy) pe = intergrainEnergy(cfg) + intramolecularEnergy(cfg); // Write step summary? if (step%writeFreq == 0) { if (calcEnergy) Messenger::print(" %-10i %10.3e %10.3e %10.3e %10.3e\n", step+1, tInstant, ke, pe, ke+pe); else Messenger::print(" %-10i %10.3e %10.3e\n", step+1, tInstant, ke); } // Save trajectory frame if (writeTraj) { if (Comm.master()) { // Write number of atoms trajParser.writeLineF("%i\n", cfg.nAtoms()); // Construct and write header Dnchar header(-1, "Step %i of %i, T = %10.3e, ke = %10.3e", step+1, nSteps, tInstant, ke); if (calcEnergy) header.strcatf(", pe = %10.3e, tot = %10.3e", pe, ke+pe); trajParser.writeLineF("%s\n", header.get()); // Write Atoms for (int n=0; n<cfg.nAtoms(); ++n) { i = cfg.atom(n); trajParser.writeLineF("%-3s %10.3f %10.3f %10.3f\n", PeriodicTable::element(i->element()).symbol(), i->r().x, i->r().y, i->r().z); } } else if (!Comm.decision()) return false; } } timer.stop(); // Close trajectory file if (writeTraj && Comm.master()) trajParser.closeFiles(); Messenger::print("%i molecular dynamics steps performed (%s work, %s comms)\n", nSteps, timer.timeString(), Comm.accumulatedTimeString()); // Increment configuration changeCount_ cfg.incrementCoordinateIndex(); /* * Calculation End */ return true; }
ATEN_USING_NAMESPACE // Load includes void Aten::loadEncoderDefinitions() { Messenger::enter("Aten::loadEncoderDefinitions"); QString encoderDefsFile = dataDirectoryFile("external/encoders.txt"); Messenger::print(Messenger::Verbose, "Looking for encoder definitions (%s)...", qPrintable(encoderDefsFile)); LineParser parser; parser.openInput(encoderDefsFile); if (!parser.isFileGoodForReading()) { Messenger::print("Unable to open encoder definitions file.\n"); return; } // Read in encoder definitions from file QString keyword; EncoderDefinition::EncoderDefinitionKeyword edk; EncoderDefinition* encoder = NULL; ExternalCommand* command = NULL; while (!parser.eofOrBlank()) { // Read first argument from file, which is our keyword parser.getArgsDelim(Parser::SkipBlanks + Parser::StripComments + Parser::UseQuotes); keyword = parser.argc(0); edk = EncoderDefinition::encoderDefinitionKeyword(keyword); if (edk == EncoderDefinition::nEncoderDefinitionKeywords) { Messenger::print("Unrecognised encoder definition keyword '%s'. Ignoring...\n", qPrintable(keyword)); continue; } // Deal with remaining keywords switch (edk) { // Command Name case (EncoderDefinition::CommandNameKeyword): if (!encoder) { Messenger::error("No encoder definition yet created in which to set name data (use 'Name' keyword before all others).\n"); continue; } command = encoder->addCommand(); command->setName(parser.argc(1)); break; // Command case (EncoderDefinition::CommandKeyword): if (!command) { Messenger::error("No command definition yet created in which to set command data (use 'CommandName' keyword before its siblings).\n"); continue; } command->setExecutable(parser.argc(1)); break; // Command arguments case (EncoderDefinition::CommandArgumentsKeyword): if (!command) { Messenger::error("No command definition yet created in which to set argument data (use 'CommandName' keyword before its siblings).\n"); continue; } command->setArguments(parser.argc(1)); break; case (EncoderDefinition::CommandSearchPathsKeyword): if (!command) { Messenger::error("No command definition yet created in which to set searchpath data (use 'CommandName' keyword before its siblings).\n"); continue; } for (int n=1; n<parser.nArgs(); ++n) command->addSearchPath(parser.argc(n)); break; // Name (create new object) case (EncoderDefinition::NameKeyword): encoder = encoders_.add(); encoder->setName(parser.argc(1)); break; case (EncoderDefinition::NicknameKeyword): if (!encoder) { Messenger::error("No encoder definition yet created in which to set data (use 'Name' keyword before all others).\n"); continue; } encoder->setNickname(parser.argc(1)); break; default: break; } } parser.closeFiles(); Messenger::exit("Aten::loadEncoderDefinitions"); }