void ReferenceVariableVerletDynamics::update(const OpenMM::System& system, vector<Vec3>& atomCoordinates,
                                          vector<Vec3>& velocities,
                                          vector<Vec3>& forces, vector<double>& masses, double maxStepSize, double tolerance) {
    // first-time-through initialization

    int numberOfAtoms = system.getNumParticles();
    if (getTimeStep() == 0) {
       // invert masses

       for (int ii = 0; ii < numberOfAtoms; ii++) {
          if (masses[ii] == 0.0)
              inverseMasses[ii] = 0.0;
          else
              inverseMasses[ii] = 1.0/masses[ii];
       }
    }

    double error = 0.0;
    for (int i = 0; i < numberOfAtoms; ++i) {
        for (int j = 0; j < 3; ++j) {
            double xerror = inverseMasses[i]*forces[i][j];
            error += xerror*xerror;
        }
    }
    error = sqrt(error/(numberOfAtoms*3));
    double newStepSize = sqrt(getAccuracy()/error);
    if (getDeltaT() > 0.0f)
        newStepSize = std::min(newStepSize, getDeltaT()*2.0f); // For safety, limit how quickly dt can increase.
    if (newStepSize > getDeltaT() && newStepSize < 1.2f*getDeltaT())
        newStepSize = getDeltaT(); // Keeping dt constant between steps improves the behavior of the integrator.
    if (newStepSize > maxStepSize)
        newStepSize = maxStepSize;
    double vstep = 0.5f*(newStepSize+getDeltaT()); // The time interval by which to advance the velocities
    setDeltaT(newStepSize);
    for (int i = 0; i < numberOfAtoms; ++i) {
        if (masses[i] != 0.0)
            for (int j = 0; j < 3; ++j) {
                double vPrime = velocities[i][j] + inverseMasses[i]*forces[i][j]*vstep;
                xPrime[i][j] = atomCoordinates[i][j] + vPrime*getDeltaT();
            }
    }
    ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
    if (referenceConstraintAlgorithm)
        referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses, tolerance);

   // Update the positions and velocities.

   double velocityScale = 1.0/getDeltaT();
   for (int i = 0; i < numberOfAtoms; ++i) {
       if (masses[i] != 0.0)
           for (int j = 0; j < 3; ++j) {
               velocities[i][j] = velocityScale*(xPrime[i][j] - atomCoordinates[i][j]);
               atomCoordinates[i][j] = xPrime[i][j];
           }
   }
   ReferenceVirtualSites::computePositions(system, atomCoordinates);
   incrementTimeStep();
}
void ReferenceVerletDynamics::update(const OpenMM::System& system, vector<RealVec>& atomCoordinates,
                                          vector<RealVec>& velocities,
                                          vector<RealVec>& forces, vector<RealOpenMM>& masses, RealOpenMM tolerance) {

   // ---------------------------------------------------------------------------------------

   static const char* methodName      = "\nReferenceVerletDynamics::update";

   static const RealOpenMM zero       =  0.0;
   static const RealOpenMM one        =  1.0;

   // ---------------------------------------------------------------------------------------

   // first-time-through initialization

   int numberOfAtoms = system.getNumParticles();
   if( getTimeStep() == 0 ){
      // invert masses

      for( int ii = 0; ii < numberOfAtoms; ii++ ){
         if (masses[ii] == zero)
             inverseMasses[ii] = zero;
         else
             inverseMasses[ii] = one/masses[ii];
      }
   }
   
   // Perform the integration.
   
   for (int i = 0; i < numberOfAtoms; ++i) {
       if (masses[i] != zero)
           for (int j = 0; j < 3; ++j) {
               velocities[i][j] += inverseMasses[i]*forces[i][j]*getDeltaT();
               xPrime[i][j] = atomCoordinates[i][j] + velocities[i][j]*getDeltaT();
           }
   }
   ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
   if (referenceConstraintAlgorithm)
      referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses, tolerance);
   
   // Update the positions and velocities.
   
   RealOpenMM velocityScale = static_cast<RealOpenMM>( 1.0/getDeltaT() );
   for (int i = 0; i < numberOfAtoms; ++i) {
       if (masses[i] != zero)
           for (int j = 0; j < 3; ++j) {
               velocities[i][j] = velocityScale*(xPrime[i][j] - atomCoordinates[i][j]);
               atomCoordinates[i][j] = xPrime[i][j];
           }
   }

   ReferenceVirtualSites::computePositions(system, atomCoordinates);
   incrementTimeStep();
}
void ReferenceBrownianDynamics::update(const OpenMM::System& system, vector<RealVec>& atomCoordinates,
                                          vector<RealVec>& velocities,
                                          vector<RealVec>& forces, vector<RealOpenMM>& masses, RealOpenMM tolerance) {

   // ---------------------------------------------------------------------------------------

   static const char* methodName      = "\nReferenceBrownianDynamics::update";

   static const RealOpenMM zero       =  0.0;
   static const RealOpenMM one        =  1.0;

   // ---------------------------------------------------------------------------------------

   // first-time-through initialization

   int numberOfAtoms = system.getNumParticles();
   if( getTimeStep() == 0 ){
      // invert masses

      for( int ii = 0; ii < numberOfAtoms; ii++ ){
         if (masses[ii] == zero)
             inverseMasses[ii] = zero;
         else
             inverseMasses[ii] = one/masses[ii];
      }
   }
   
   // Perform the integration.
   
   const RealOpenMM noiseAmplitude = static_cast<RealOpenMM>( sqrt(2.0*BOLTZ*getTemperature()*getDeltaT()/getFriction()) );
   const RealOpenMM forceScale = getDeltaT()/getFriction();
   for (int i = 0; i < numberOfAtoms; ++i) {
       if (masses[i] != zero)
           for (int j = 0; j < 3; ++j) {
               xPrime[i][j] = atomCoordinates[i][j] + forceScale*inverseMasses[i]*forces[i][j] + noiseAmplitude*SQRT(inverseMasses[i])*SimTKOpenMMUtilities::getNormallyDistributedRandomNumber();
           }
   }
   ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
   if (referenceConstraintAlgorithm)
      referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses, tolerance);
   
   // Update the positions and velocities.
   
   RealOpenMM velocityScale = static_cast<RealOpenMM>( 1.0/getDeltaT() );
   for (int i = 0; i < numberOfAtoms; ++i) {
       if (masses[i] != zero)
           for (int j = 0; j < 3; ++j) {
               velocities[i][j] = velocityScale*(xPrime[i][j] - atomCoordinates[i][j]);
               atomCoordinates[i][j] = xPrime[i][j];
           }
   }
   ReferenceVirtualSites::computePositions(system, atomCoordinates);
   incrementTimeStep();
}
void ReferenceStochasticDynamics::update(const OpenMM::System& system, vector<RealVec>& atomCoordinates,
                                          vector<RealVec>& velocities, vector<RealVec>& forces, vector<RealOpenMM>& masses, RealOpenMM tolerance) {

   // ---------------------------------------------------------------------------------------

   static const char* methodName      = "\nReferenceStochasticDynamics::update";

   static const RealOpenMM zero       =  0.0;
   static const RealOpenMM one        =  1.0;

   // ---------------------------------------------------------------------------------------

   // first-time-through initialization

   int numberOfAtoms = system.getNumParticles();
   if( getTimeStep() == 0 ){
      // invert masses

      for( int ii = 0; ii < numberOfAtoms; ii++ ){
         if (masses[ii] == zero)
             inverseMasses[ii] = zero;
         else
             inverseMasses[ii] = one/masses[ii];
      }
   }

   // 1st update

   updatePart1( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime );

   // 2nd update

   updatePart2( numberOfAtoms, atomCoordinates, velocities, forces, inverseMasses, xPrime );

   ReferenceConstraintAlgorithm* referenceConstraintAlgorithm = getReferenceConstraintAlgorithm();
   if (referenceConstraintAlgorithm)
      referenceConstraintAlgorithm->apply(atomCoordinates, xPrime, inverseMasses, tolerance);

   // copy xPrime -> atomCoordinates

   RealOpenMM invStepSize = 1.0/getDeltaT();
   for (int i = 0; i < numberOfAtoms; ++i)
       if (masses[i] != zero)
           for (int j = 0; j < 3; ++j) {
               velocities[i][j] = invStepSize*(xPrime[i][j]-atomCoordinates[i][j]);
               atomCoordinates[i][j] = xPrime[i][j];
           }

   ReferenceVirtualSites::computePositions(system, atomCoordinates);
   incrementTimeStep();
}
TEST(TestControlBerendsenBins,SingleBin){
    std::ifstream file("../foam-1728.json");
    if(!file.is_open()){
        std::cout<<"File not found"<<std::endl;
        exit(0);
    }
    
    std::string jsonstr;
    std::string line;
    while (!file.eof()) {
        getline(file, line);
        jsonstr += line;
    }
    file.close();
    
    rapidjson::Document document;
    if(document.Parse<0>(jsonstr.c_str()).HasParseError()){
        std::cout<<"Parsing error "<<std::endl;
        exit(0);
    }
    
    const double stepSizeInFs = document["StepSizeInFs"].GetDouble();
    const int numParticles = document["NumberAtoms"].GetInt();
    std::string equationStr = document["Equation"].GetString();
    const double rCut = document["rCut"].GetDouble();
    const rapidjson::Value& b = document["Boxsize"];
    double bx = b[(rapidjson::SizeType)0].GetDouble();
    double by = b[(rapidjson::SizeType)1].GetDouble();
    double bz = b[(rapidjson::SizeType)2].GetDouble();
    int numSpecies = document["NumberSpecies"].GetInt();
    std::vector<OpenMM::Vec3> posInNm;
    std::vector<OpenMM::Vec3> velInNm;
    
    OpenMM::Platform::loadPluginsFromDirectory(
           OpenMM::Platform::getDefaultPluginsDirectory());
    
    OpenMM::System system;
    //add particles to the system by reading from json file
    system.setDefaultPeriodicBoxVectors(OpenMM::Vec3(bx,0,0),OpenMM::Vec3(0,by,0),OpenMM::Vec3(0,0,bz));
    const rapidjson::Value& mass = document["masses"];
    const rapidjson::Value& pos = document["Positions"];
    const rapidjson::Value& vel = document["Velocities"];
    
    posInNm.clear();
    velInNm.clear();
    for(rapidjson::SizeType m=0;m<mass.Size();m++){
        double tm = mass[(rapidjson::SizeType) m].GetDouble();
        system.addParticle(tm);
        posInNm.push_back(OpenMM::Vec3(pos[(rapidjson::SizeType) m]["0"].GetDouble(),
                                       pos[(rapidjson::SizeType) m]["1"].GetDouble(),
                                       pos[(rapidjson::SizeType) m]["2"].GetDouble()
                                       ));
        velInNm.push_back(OpenMM::Vec3(vel[(rapidjson::SizeType) m]["0"].GetDouble(),
                                       vel[(rapidjson::SizeType) m]["1"].GetDouble(),
                                       vel[(rapidjson::SizeType) m]["2"].GetDouble()
                                       ));
    }
    std::cout<<"Initialized System with "<<system.getNumParticles()<<" Particles."<<std::endl;
    
    OpenMM::CustomNonbondedForce* nonbonded = new OpenMM::CustomNonbondedForce(equationStr);
    nonbonded->setNonbondedMethod(OpenMM::CustomNonbondedForce::CutoffPeriodic);
    nonbonded->setCutoffDistance(rCut);// * OpenMM::NmPerAngstrom
    nonbonded->addPerParticleParameter("Ar");//later on collect it from json string based on OF
    for(int p=0;p<numParticles;p++){
        std::vector<double> params(numSpecies);
        params[0] = (double) 1;
        nonbonded->addParticle(params);
    }
    system.addForce(nonbonded);
    std::vector<std::string> ctools(1);
    ctools[0] = "ControlBerendsenInBins";
    OpenMM::Vec3 startPoint = OpenMM::Vec3((10*0.34),(0*0.34),(10*0.34));
    OpenMM::Vec3 endPoint = OpenMM::Vec3((10*0.34),(20*0.34),(10*0.34));
    OpenMM::ControlTools controls(ctools,(double)292,0.001,
                                  startPoint,endPoint);
    int num_plat = OpenMM::Platform::getNumPlatforms();
    std::cout<<"Number of registered platforms: "<< num_plat <<std::endl;
    for(int i=0;i<num_plat;i++)
    {
	    OpenMM::Platform& tempPlatform = OpenMM::Platform::getPlatform(i);
	    std::string tempPlatformName = tempPlatform.getName();
	    std::cout<<"Platform "<<(i+1)<<" is "<<tempPlatformName.c_str()<<std::endl;
    }
    OpenMM::Platform& platform = OpenMM::Platform::getPlatformByName("OpenCL");
    OpenMM::VelocityVerletIntegrator integrator(stepSizeInFs * OpenMM::PsPerFs);
    OpenMM::Context context(system,integrator,platform,controls);
    string Platformname = context.getPlatform().getName();
    std::cout<<"Using OpenMM "<<Platformname.c_str()<<" Platform"<<std::endl;

    context.setPositions(posInNm);
    context.setVelocities(velInNm);
    
    int nbs = context.getControls().getNBins();
    printf("Using %d bins for the system\n",nbs);
    //start the simulation loop
    integrator.step(1);
    printf("Finished initial integration\n");
    int counter=0;
    std::cout<<"starting the loop\n";
    for(int frame=1;frame<400;++frame){
//        OpenMM::State state = context.getState(OpenMM::State::Velocities);
//        const double time = state.getTime();
            double* mola = context.getControls().getBinTemperature();
//            OpenMM::Vec3* tv = context.getControls().getTestVariable();
            double gpuMol = 0.0;
            for(int k=0;k<nbs;k++){
                gpuMol += mola[k];
            }
        EXPECT_EQ((double) numParticles,gpuMol);
        integrator.step(1);
    }
    std::cout<<"Simulation completed with counter value "<<counter<<std::endl;
}
Esempio n. 6
0
OpenMM::System* AmberParm::createSystem(
                OpenMM::NonbondedForce::NonbondedMethod nonbondedMethod,
                double nonbondedCutoff,
                std::string constraints,
                bool rigidWater,
                std::string implicitSolvent,
                double implicitSolventKappa,
                double implicitSolventSaltConc,
                double temperature,
                double soluteDielectric,
                double solventDielectric,
                bool removeCMMotion,
                double ewaldErrorTolerance,
                bool flexibleConstraints,
                bool useSASA) {

    OpenMM::System* system = new OpenMM::System();

    // Make sure we have a legal choice for constraints and implicitSolvent
    if (constraints != "None" && constraints != "HBonds" &&
            constraints != "AllBonds") {
        string msg = "constraints must be None, HBonds, or AllBonds; not " +
                     constraints;
        throw AmberParmError(msg.c_str());
    }

    if (implicitSolvent != "None" && implicitSolvent != "HCT" &&
            implicitSolvent != "OBC1" && implicitSolvent != "OBC2" &&
            implicitSolvent != "GBn" && implicitSolvent != "GBn2") {
        string msg = "implicitSolvent must be None, HCT, OBC1, OBC2, GBn, or "
                     "GBn2; not " + implicitSolvent;
        throw AmberParmError(msg.c_str());
    }

    if (rigidWater && (constraints != "HBonds" && constraints != "AllBonds")) {
        cerr << "rigidWater is incompatible with constraints=None; setting to "
             << "false" << endl;
    }

    // Catch illegal nonbonded choice for system

    if (isPeriodic()) {
        if (nonbondedMethod == OpenMM::NonbondedForce::CutoffNonPeriodic ||
                nonbondedMethod == OpenMM::NonbondedForce::NoCutoff)
            throw AmberParmError("Illegal nonbondedForce choice for periodic system");
    } else {
        if (nonbondedMethod == OpenMM::NonbondedForce::CutoffPeriodic ||
                nonbondedMethod == OpenMM::NonbondedForce::PME ||
                nonbondedMethod == OpenMM::NonbondedForce::Ewald)
            throw AmberParmError("Illegal nonbondedForce choice for non-periodic system");
    }

    // Add all particles
    for (atom_iterator it = AtomBegin(); it != AtomEnd(); it++) {
        system->addParticle(it->getMass());
    }

    // Add constraints
    bool hcons = constraints == "HBonds" || constraints == "AllBonds";
    bool allcons = constraints == "AllBonds";
    for (bond_iterator it = BondBegin(); it != BondEnd(); it++) {
        Atom a1 = atoms_[it->getAtomI()];
        Atom a2 = atoms_[it->getAtomJ()];
        if (hcons && (a1.getElement() == 1 || a2.getElement() == 1)) {
            system->addConstraint(it->getAtomI(), it->getAtomJ(),
                                  it->getEquilibriumDistance()*NANOMETER_PER_ANGSTROM);
        } else if (allcons) {
            system->addConstraint(it->getAtomI(), it->getAtomJ(),
                                  it->getEquilibriumDistance()*NANOMETER_PER_ANGSTROM);
        }
    }
    
    // Add all bonds
    if (!allcons || flexibleConstraints) {
        OpenMM::HarmonicBondForce *bond_force = new OpenMM::HarmonicBondForce();
        bond_force->setForceGroup(BOND_FORCE_GROUP);
        double conv = ANGSTROM_PER_NANOMETER*ANGSTROM_PER_NANOMETER*JOULE_PER_CALORIE;
        for (bond_iterator it=BondBegin(); it != BondEnd(); it++) {
            // See if this bond needs to be skipped due to constraints
            Atom a1 = atoms_[it->getAtomI()];
            Atom a2 = atoms_[it->getAtomJ()];
            if (hcons && (a1.getElement() == 1 || a2.getElement() == 1) &&
                        !flexibleConstraints) continue;

            bond_force->addBond(it->getAtomI(), it->getAtomJ(),
                                it->getEquilibriumDistance()*NANOMETER_PER_ANGSTROM,
                                2*it->getForceConstant()*conv);
        }
        system->addForce(bond_force);
    }

    // Add all angles
    OpenMM::HarmonicAngleForce *angle_force = new OpenMM::HarmonicAngleForce();
    angle_force->setForceGroup(ANGLE_FORCE_GROUP);
    for (angle_iterator it = AngleBegin(); it != AngleEnd(); it++) {
        angle_force->addAngle(it->getAtomI(), it->getAtomJ(), it->getAtomK(),
                              it->getEquilibriumAngle()*RADIAN_PER_DEGREE,
                              2*it->getForceConstant()*JOULE_PER_CALORIE);
    }
    system->addForce(angle_force);

    // Add all torsions
    OpenMM::PeriodicTorsionForce *dihedral_force = new OpenMM::PeriodicTorsionForce();
    dihedral_force->setForceGroup(DIHEDRAL_FORCE_GROUP);
    for (dihedral_iterator it = DihedralBegin(); it != DihedralEnd(); it++) {
        dihedral_force->addTorsion(it->getAtomI(), it->getAtomJ(),
                                   it->getAtomK(), it->getAtomL(),
                                   it->getPeriodicity(),
                                   it->getPhase()*RADIAN_PER_DEGREE,
                                   it->getForceConstant()*JOULE_PER_CALORIE);
    }
    system->addForce(dihedral_force);

    // Add nonbonded force
    OpenMM::NonbondedForce *nonb_frc = new OpenMM::NonbondedForce();
    nonb_frc->setForceGroup(NONBONDED_FORCE_GROUP);
    nonb_frc->setNonbondedMethod(nonbondedMethod);
    if (nonbondedMethod != OpenMM::NonbondedForce::NoCutoff)
        nonb_frc->setCutoffDistance(nonbondedCutoff*NANOMETER_PER_ANGSTROM);
    const double ONE_SIXTH = 1.0 / 6.0;
    const double SIGMA_SCALE = pow(2, -ONE_SIXTH) * 2 * NANOMETER_PER_ANGSTROM;
    for (atom_iterator it = AtomBegin(); it != AtomEnd(); it++) {
        nonb_frc->addParticle(it->getCharge(),
                              it->getLJRadius()*SIGMA_SCALE,
                              it->getLJEpsilon()*JOULE_PER_CALORIE);
    }
    // Now do exceptions
    const double SIGMA_SCALE2 = pow(2, -ONE_SIXTH) * NANOMETER_PER_ANGSTROM;
    for (dihedral_iterator it = DihedralBegin(); it != DihedralEnd(); it++) {
        if (it->ignoreEndGroups()) continue;
        Atom a1 = atoms_[it->getAtomI()];
        Atom a2 = atoms_[it->getAtomL()];
        double eps = sqrt(a1.getLJEpsilon() * a2.getLJEpsilon()) *
                     JOULE_PER_CALORIE / it->getScnb();
        double sig = (a1.getLJRadius() + a2.getLJRadius()) * SIGMA_SCALE2;
        nonb_frc->addException(it->getAtomI(), it->getAtomL(),
                               a1.getCharge()*a2.getCharge()/it->getScee(),
                               sig, eps);
    }
    // Now do exclusions
    for (int i = 0; i < atoms_.size(); i++) {
        if (exclusion_list_[i].size() == 0) continue; // No exclusions here
        for (set<int>::const_iterator it = exclusion_list_[i].begin();
                it != exclusion_list_[i].end(); it++) {
            nonb_frc->addException(i, *it, 0.0, 1.0, 0.0);
        }
    }
    // Set the ewald error tolerance
    if (nonbondedMethod == OpenMM::NonbondedForce::PME ||
            nonbondedMethod == OpenMM::NonbondedForce::Ewald)
        nonb_frc->setEwaldErrorTolerance(ewaldErrorTolerance);
    system->addForce(nonb_frc);
    // See about removing the center of mass motion
    if (removeCMMotion)
        system->addForce(new OpenMM::CMMotionRemover());
    // Add a box if necessary
    if (isPeriodic())
        system->setDefaultPeriodicBoxVectors(unit_cell_.getVectorA()/10,
                                             unit_cell_.getVectorB()/10,
                                             unit_cell_.getVectorC()/10);

    // If no implicit solvent, we can return system now
    if (implicitSolvent == "None")
        return system;

    // Otherwise, we need to add the GB force
    if (implicitSolventKappa <= 0 && implicitSolventSaltConc > 0)
        implicitSolventKappa = 50.33355 * 0.73 *
                sqrt(implicitSolventSaltConc/(solventDielectric*temperature));

    OpenMM::CustomGBForce *gb_frc = 0;
    if (implicitSolvent == "HCT") {
        gb_frc = GB_HCT(*this, solventDielectric, soluteDielectric, useSASA,
                        nonbondedCutoff, implicitSolventKappa);
    } else if (implicitSolvent == "OBC1") {
        gb_frc = GB_OBC1(*this, solventDielectric, soluteDielectric, useSASA,
                         nonbondedCutoff, implicitSolventKappa);
    } else if (implicitSolvent == "OBC2") {
        gb_frc = GB_OBC2(*this, solventDielectric, soluteDielectric, useSASA,
                         nonbondedCutoff, implicitSolventKappa);
    } else if (implicitSolvent == "GBn") {
        gb_frc = GB_GBn(*this, solventDielectric, soluteDielectric, useSASA,
                        nonbondedCutoff, implicitSolventKappa);
    } else if (implicitSolvent == "GBn2") {
        gb_frc = GB_GBn2(*this, solventDielectric, soluteDielectric, useSASA,
                         nonbondedCutoff, implicitSolventKappa);
    } else {
        stringstream iss;
        iss << "Should not be here; bad GB model " << implicitSolvent;
        throw InternalError(iss.str());
    }

    if (nonbondedMethod == OpenMM::NonbondedForce::NoCutoff)
        gb_frc->setNonbondedMethod(OpenMM::CustomGBForce::NoCutoff);
    else if (nonbondedMethod == OpenMM::NonbondedForce::CutoffNonPeriodic)
        gb_frc->setNonbondedMethod(OpenMM::CustomGBForce::CutoffNonPeriodic);
    else // all remaining options are periodic cutoff...
        gb_frc->setNonbondedMethod(OpenMM::CustomGBForce::CutoffPeriodic);

    gb_frc->setForceGroup(NONBONDED_FORCE_GROUP);

    // Since we're using GB, we need to turn off the reaction field dielectric
    nonb_frc->setReactionFieldDielectric(1.0);

    system->addForce(gb_frc);

    return system;
}
Esempio n. 7
0
void simulate(json &molinfo) {

	// Load any shared libraries containing GPU implementations.
	OpenMM::Platform::loadPluginsFromDirectory(
      	OpenMM::Platform::getDefaultPluginsDirectory());

	// force to use CPU platform that is better than CUDA in my simulation scale
	OpenMM::Platform& platform = OpenMM::Platform::getPlatformByName("CPU");
	// force to use single thread 
	platform.setPropertyDefaultValue("Threads", "1");
	
	// Create a system with forces.
	OpenMM::System system;

	const int N_particles = molinfo["resSeq"].size();
	std::cout << "# Number of Particles : " << N_particles << '\n';

	// set MD paramters
	const double Temperature = molinfo["parameters"]["Temperature"];
	const int SimulationSteps = molinfo["parameters"]["SimulationSteps"];
	const double TimePerStepInPs = molinfo["parameters"]["TimePerStepInPs"];
	const int NStepSave = molinfo["parameters"]["NStepSave"];
	const int RandomSeed = molinfo["parameters"]["RandomSeed"];

	// set other parameters
	const std::string filename = molinfo["output"]["filename"];

	// Create Atoms
	std::vector<OpenMM::Vec3> initPosInNm(N_particles);

	// map from resSeq to particle index(0..N-1)
	for (int i=0; i<N_particles; ++i) {
		int resSeq = molinfo["resSeq"][i];
		rs2pi.insert(std::pair<int,int>(resSeq, i));
	}

	double x, y, z;
	for (int i=0; i<N_particles; ++i) {
		x = molinfo["position"][i]["position"][0];
		y = molinfo["position"][i]["position"][1];
		z = molinfo["position"][i]["position"][2];
		initPosInNm[i] = OpenMM::Vec3(x, y, z) * OpenMM::NmPerAngstrom;
		system.addParticle(137.0);	// average mass of amino acid residues
	}

	// add non-local repulsive force
	// This pair potential is excluded from bonded pairs 
	OpenMM::CustomNonbondedForce& nonlocalRepulsion = *new OpenMM::CustomNonbondedForce("epsilon_repul*(d_exclusive/r)^12");
	system.addForce(&nonlocalRepulsion);
	nonlocalRepulsion.setNonbondedMethod(OpenMM::CustomNonbondedForce::NonbondedMethod::CutoffNonPeriodic);
	nonlocalRepulsion.setCutoffDistance(D_ExclusionCutoffInNm);
	nonlocalRepulsion.addGlobalParameter("d_exclusive", D_ExclusiveInNm);
	nonlocalRepulsion.addGlobalParameter("epsilon_repul", E_ExclusionPair);
	for (int i=0; i<N_particles; ++i) {
		nonlocalRepulsion.addParticle();
	}

	// add non-local Go contact for native contact pairs
	OpenMM::CustomBondForce& goContactForce = *new OpenMM::CustomBondForce("epsilon_ngo*(5*(r_native/r)^12 - 6*(r_native/r)^10)");
	system.addForce(&goContactForce);
	goContactForce.addGlobalParameter("epsilon_ngo", E_GoContactPair);
	goContactForce.addPerBondParameter("r_native");
	for (int i=0; i<molinfo["contact"].size(); ++i) {
		int p1 = rs2pi[molinfo["contact"][i]["resSeq"][0]];
		int p2 = rs2pi[molinfo["contact"][i]["resSeq"][1]];
		double r_native = molinfo["contact"][i]["length"];
		std::vector<double> perBondParams = {r_native * OpenMM::NmPerAngstrom};
		goContactForce.addBond(p1, p2, perBondParams);
		nonlocalRepulsion.addExclusion(p1, p2);
	}

	// add bonding force or constraints between two particles
	OpenMM::HarmonicBondForce& bondStretch = *new OpenMM::HarmonicBondForce();
	system.addForce(&bondStretch);
	for (int i=0; i<molinfo["bond"].size(); ++i) {
		int p1 = rs2pi[molinfo["bond"][i]["resSeq"][0]];
		int p2 = rs2pi[molinfo["bond"][i]["resSeq"][1]];
		double length = molinfo["bond"][i]["length"];
		if (UseConstraints) {
			system.addConstraint(p1, p2, length * OpenMM::NmPerAngstrom);
		} else {
			bondStretch.addBond(p1, p2, length * OpenMM::NmPerAngstrom, K_BondStretch);
		}
		nonlocalRepulsion.addExclusion(p1, p2);
	}

	// add angle force
	OpenMM::HarmonicAngleForce& bondBend = *new OpenMM::HarmonicAngleForce();
	system.addForce(&bondBend);
	for (int i=0; i<molinfo["angle"].size(); ++i) {
		int p1 = rs2pi[molinfo["angle"][i]["resSeq"][0]];
		int p2 = rs2pi[molinfo["angle"][i]["resSeq"][1]];
		int p3 = rs2pi[molinfo["angle"][i]["resSeq"][2]];
		double angle = molinfo["angle"][i]["angle"];
		bondBend.addAngle(p1, p2, p3, angle * OpenMM::RadiansPerDegree, K_BondAngle);
		nonlocalRepulsion.addExclusion(p1, p3);
	}

	// add dihedral force
	OpenMM::PeriodicTorsionForce& bondTorsion = *new OpenMM::PeriodicTorsionForce();
	system.addForce(&bondTorsion);
	for (int i=0; i<molinfo["dihedral"].size(); ++i) {
		int p1 = rs2pi[molinfo["dihedral"][i]["resSeq"][0]];
		int p2 = rs2pi[molinfo["dihedral"][i]["resSeq"][1]];
		int p3 = rs2pi[molinfo["dihedral"][i]["resSeq"][2]];
		int p4 = rs2pi[molinfo["dihedral"][i]["resSeq"][3]];
		double dihedral = molinfo["dihedral"][i]["dihedral"];
		bondTorsion.addTorsion(p1, p2, p3, p4, 
			1, (dihedral+180.0) * OpenMM::RadiansPerDegree, K_BondTorsion1);
		bondTorsion.addTorsion(p1, p2, p3, p4, 
			3, (dihedral+180.0) * OpenMM::RadiansPerDegree, K_BondTorsion3);
		nonlocalRepulsion.addExclusion(p1, p4);
	}

	// set langevin integrator
	OpenMM::LangevinIntegrator integrator(Temperature, LangevinFrictionPerPs, TimePerStepInPs);
	integrator.setRandomNumberSeed(RandomSeed);

	// Let OpenMM Context choose best platform
	OpenMM::Context context(system, integrator, platform);

	std::cout << "# Using OpenMM Platform: ";
	std::cout << context.getPlatform().getName().c_str() << std::endl;

	// Set starting positions of the atoms. Leave time and velocity zero.
	context.setPositions(initPosInNm);
	// set initial velocity
	context.setVelocitiesToTemperature(Temperature, RandomSeed);

	// set output files
	std::ofstream opdb, ots;
	opdb.open(filename + ".pdb", std::ios::out);
	ots.open(filename + ".ts", std::ios::out);
	std::cout << "# PDB: " << filename + ".pdb\n";
	std::cout << "# TimeSereis: " << filename + ".ts\n";

	int infoMask = 0;
	infoMask = OpenMM::State::Positions;
	infoMask += OpenMM::State::Energy;

	for (int frameNum = 0;; ++frameNum) {

		// Output current state information
		OpenMM::State state = context.getState(infoMask);
		int steps = frameNum * NStepSave;
		double qscore = getQscore(state, molinfo);

		// write PDB frame
		writePDBFrame(frameNum, state, molinfo, opdb);
		writeTimeSeries(steps, state, ots, qscore);

		// show progress in stdout
		if (SilentMode == false) {
			std::cout << '\r';
			std::cout << "Q=" << std::setw(5) << std::setprecision(3) << qscore;
			std::cout << "; T=" << std::setw(5) << integrator.getTemperature();
			std::cout << "; E=" << std::setw(5) << state.getPotentialEnergy();
			std::cout << std::setw(8) << steps << " steps / ";
			std::cout << std::setw(8) << SimulationSteps << std::flush;
		}

		if (frameNum * NStepSave >= SimulationSteps) break;

		integrator.step(NStepSave);
	}
	std::cout << std::endl;
	opdb.close();
	ots.close();

}