void Phrase::CreateFromString(const std::vector<FactorType> &factorOrder, const StringPiece &phraseString, const StringPiece &factorDelimiter) { FactorCollection &factorCollection = FactorCollection::Instance(); for (util::TokenIter<util::AnyCharacter, true> word_it(phraseString, util::AnyCharacter(" \t")); word_it; ++word_it) { Word &word = AddWord(); size_t index = 0; for (util::TokenIter<util::MultiCharacter, false> factor_it(*word_it, util::MultiCharacter(factorDelimiter)); factor_it && (index < factorOrder.size()); ++factor_it, ++index) { word[factorOrder[index]] = factorCollection.AddFactor(*factor_it); } if (index != factorOrder.size()) { TRACE_ERR( "[ERROR] Malformed input: '" << *word_it << "'" << std::endl << "In '" << phraseString << "'" << endl << " Expected input to have words composed of " << factorOrder.size() << " factor(s) (form FAC1|FAC2|...)" << std::endl << " but instead received input with " << index << " factor(s).\n"); abort(); } } }
// This method does the actual simulation stuff // It runs for the indicated number of iterations // restart=true means that the counting of iterations is started with the end // value of the previous run bool MicroCanonicalMD::simulateIterations(Size iterations, bool restart) { // local variables double current_energy = 0; Size max_number = 0; Atom *atom_ptr = 0; Size force_update_freq = 0; Size iteration = 0; if (!restart) { // reset the current number of iteration and the simulation time to the values given // in the options number_of_iteration_ = (Size)options.getInteger(MolecularDynamics::Option::NUMBER_OF_ITERATION); current_time_ = options.getReal(MolecularDynamics::Option::CURRENT_TIME); } else { // the values from the last simulation run are used; increase by one to start in the // next iteration number_of_iteration_++; } // determine the largest value for the iteration counter max_number = number_of_iteration_ + iterations; // pre-calculate some needed factors calculateFactors(); // make sure that the MD simulation operates on the same set of atoms // as the forcefield does (this may have changed since setup was called) atom_vector_ = force_field_ptr_->getAtoms(); // First check whether the force field and the MD instance // are valid if (!valid_ || force_field_ptr_ == 0 || !force_field_ptr_->isValid()) { Log.error() << "MD simulation not possible! " << "MD class is not valid." << std::endl; return false; } // Get the frequency for updating the Force Field pair lists force_update_freq = force_field_ptr_->getUpdateFrequency(); // If the simulation runs with periodic boundary conditions, update the // list and position of molecules if (force_field_ptr_->periodic_boundary.isEnabled()) { force_field_ptr_->periodic_boundary.updateMolecules(); } // Calculate the forces at the beginning of the simulation force_field_ptr_->updateForces(); // DEBUG ??? //force_field_ptr_->updateEnergy(); // only done for debugging purposes // This is the main loop of the MD simulation. The Velocity-Verlet method // is used for the propagation of atomic positions and velocities for (iteration = number_of_iteration_; iteration < max_number; iteration++) { // The force field data structures must be updated regularly if (iteration % force_update_freq == 0) { force_field_ptr_->update(); } // If the simulation runs with periodic boundary conditions, update the // list and position of molecules if (force_field_ptr_->periodic_boundary.isEnabled()) { force_field_ptr_->periodic_boundary.updateMolecules(); } // In regular intervals, calculate and output the current energy if (iteration % energy_output_frequency_ == 0) { current_energy = force_field_ptr_->updateEnergy(); updateInstantaneousTemperature(); Log.info() << "Microcanonical MD simulation System has potential energy " << current_energy << " kJ/mol at time " << current_time_ + (double) iteration *time_step_ << " ps " << std::endl; Log.info() << "Microcanonical MD simulation System has kinetic energy " << kinetic_energy_ << " kJ/mol at time " << current_time_ + (double) iteration *time_step_ << " ps " << std::endl; } // Calculate new atomic positions and new tentative velocities vector<Atom*>::iterator atom_it(atom_vector_.begin()); vector<AuxFactors>::iterator factor_it(mass_factor_.begin()); for (; atom_it != atom_vector_.end(); ++atom_it, ++factor_it) { atom_ptr = *atom_it; // First calculate the new atomic position // x(t+1) = x(t) + time_step_ * v(t) + time_step_^2/(2*mass) * F(t) atom_ptr->setPosition(atom_ptr->getPosition() + (float)time_step_ * atom_ptr->getVelocity() + (float)factor_it->factor1 * atom_ptr->getForce()); // calculate a tentative velocity 'v_tent' for the next iteration // v_tent(t+1) = v(t) + time_step_ / (2 * mass) * F(t) atom_ptr->setVelocity(atom_ptr->getVelocity() + (float)factor_it->factor2 * atom_ptr->getForce()); } // next atom // Determine the forces for the next iteration force_field_ptr_->updateForces(); for (atom_it = atom_vector_.begin(), factor_it = mass_factor_.begin(); atom_it != atom_vector_.end(); ++atom_it, ++factor_it) { atom_ptr = *atom_it; // Calculate the final velocity for the next iteration atom_ptr->setVelocity(atom_ptr->getVelocity() + (float)factor_it->factor2 * atom_ptr->getForce()); } // next atom // Take a snapshot in regular intervals if desired if (snapshot_manager_ptr_ != 0 && iteration % snapshot_frequency_ == 0) { snapshot_manager_ptr_->takeSnapShot(); } if (abort_by_energy_enabled_) { if ((Maths::isNan(force_field_ptr_->getEnergy())) || (force_field_ptr_->getEnergy() > abort_energy_)) { return false; } } } // next iteration // update the current time current_time_ += (double)iterations * time_step_; // set the current iteration number_of_iteration_ = iteration - 1; // update the current temperature in the system force_field_ptr_->updateEnergy(); updateInstantaneousTemperature(); return true; } // end of simulateIterations()