Skip to content
Snippets Groups Projects
Select Git revision
  • 49c92889b16ab61fe309555f3839a8cb9f7b6cb1
  • main default protected
  • review_milestone_2
3 results

representative.py

Blame
  • system_creator.cc 15.81 KiB
    #include <ost/mol/mm/system_creator.hh>
    
    namespace ost{ namespace mol{ namespace mm{
    
    SystemPtr SystemCreator::Create(const TopologyPtr top, 
                                    const MMSettingsPtr settings,
                                    std::map<FuncType,uint>& mapper){
    
      uint mapper_index = 0;
    
      SystemPtr sys(new OpenMM::System);
    
      //add particles to the system
      std::vector<Real> masses = top->GetMasses();
    
      //set masses of position constraints to zero
      const std::vector<uint>& position_constraints = top->GetPositionConstraints();
      if(!position_constraints.empty()){
        for(std::vector<uint>::const_iterator i = position_constraints.begin();
            i != position_constraints.end(); ++i){
          masses[*i] = 0.0;
        }
      }  
    
      for(std::vector<Real>::iterator i = masses.begin(); i != masses.end(); ++i){
        sys->addParticle(*i);
      }
    
      //parameters of all added interactions will temporarily be stored in here
      std::vector<Real> parameters;
    
      const std::vector<std::pair<Index<2>,std::vector<Real> > >& harmonic_bonds = top->GetHarmonicBonds();
      if(!harmonic_bonds.empty()){
        OpenMM::HarmonicBondForce& harmonic_bond_force = *new OpenMM::HarmonicBondForce();
        sys->addForce(&harmonic_bond_force);
        mapper[HarmonicBond] = mapper_index++;
        for(std::vector<std::pair<Index<2>,std::vector<Real> > >::const_iterator i = harmonic_bonds.begin();
            i != harmonic_bonds.end(); ++i){
          harmonic_bond_force.addBond(i->first[0],i->first[1],i->second[0],i->second[1]);
        }
      }
    
      const std::vector<std::pair<Index<3>, std::vector<Real> > >& harmonic_angles = top->GetHarmonicAngles();
      if(!harmonic_angles.empty()){
        OpenMM::HarmonicAngleForce& harmonic_angle_force = *new OpenMM::HarmonicAngleForce();
        sys->addForce(&harmonic_angle_force);
        mapper[HarmonicAngle] = mapper_index++;
        for(std::vector<std::pair<Index<3>,std::vector<Real> > >::const_iterator i = harmonic_angles.begin();
            i != harmonic_angles.end(); ++i){
          harmonic_angle_force.addAngle(i->first[0],i->first[1],i->first[2],
                                        i->second[0],i->second[1]);
        }
      }
      
      const std::vector<std::pair<Index<3>,std::vector<Real> > >& urey_bradley_angles = top->GetUreyBradleyAngles();
      if(!urey_bradley_angles.empty()){
        //urey bradley is a mixture between a harmonic angle and harmonic bond term,
        //that gets split up
        OpenMM::HarmonicAngleForce& urey_angle_force = *new OpenMM::HarmonicAngleForce();
        OpenMM::HarmonicBondForce& urey_bond_force = *new OpenMM::HarmonicBondForce();
        sys->addForce(&urey_angle_force);
        sys->addForce(&urey_bond_force);
        mapper[UreyBradleyAngle] = mapper_index++;
        ++mapper_index;
        for(std::vector<std::pair<Index<3>,std::vector<Real> > >::const_iterator i = urey_bradley_angles.begin();
            i != urey_bradley_angles.end(); ++i){
          urey_angle_force.addAngle(i->first[0],i->first[1],i->first[2],
                                    i->second[0],i->second[1]);
          urey_bond_force.addBond(i->first[0],i->first[2],i->second[2],i->second[3]);
        }
      }
    
      const std::vector<std::pair<Index<4>,std::vector<Real> > >& periodic_dihedrals = top->GetPeriodicDihedrals();
      if(!periodic_dihedrals.empty()){
        OpenMM::PeriodicTorsionForce& periodic_torsion_force = *new OpenMM::PeriodicTorsionForce();
        sys->addForce(&periodic_torsion_force);
        mapper[PeriodicDihedral] = mapper_index++;
        for(std::vector<std::pair<Index<4>,std::vector<Real> > >::const_iterator i = periodic_dihedrals.begin();
            i != periodic_dihedrals.end(); ++i){
          periodic_torsion_force.addTorsion(i->first[0],i->first[1],i->first[2],i->first[3],
                                            i->second[0],i->second[1],i->second[2]);
        }
      }
    
      const std::vector<std::pair<Index<4>,std::vector<Real> > >& periodic_impropers = top->GetPeriodicImpropers();
      if(!periodic_impropers.empty()){
        OpenMM::PeriodicTorsionForce& periodic_improper_force = *new OpenMM::PeriodicTorsionForce();       
        sys->addForce(&periodic_improper_force);
        mapper[PeriodicImproper] = mapper_index++;
        for(std::vector<std::pair<Index<4>,std::vector<Real> > >::const_iterator i = periodic_impropers.begin();
            i != periodic_impropers.end(); ++i){
          periodic_improper_force.addTorsion(i->first[0],i->first[1],i->first[2],i->first[3],
                                            i->second[0],i->second[1],i->second[2]);
        }
      }
    
      const std::vector<std::pair<Index<4>,std::vector<Real> > >& harmonic_impropers = top->GetHarmonicImpropers();
      if(!harmonic_impropers.empty()){
        std::vector<double> custom_parameters;
        custom_parameters.push_back(0.0);
        custom_parameters.push_back(0.0);
        OpenMM::CustomTorsionForce& harmonic_improper_force = *new OpenMM::CustomTorsionForce("0.5*k*(theta-b)^2");
        harmonic_improper_force.addPerTorsionParameter("b");
        harmonic_improper_force.addPerTorsionParameter("k"); 
        sys->addForce(&harmonic_improper_force);
        mapper[HarmonicImproper] = mapper_index++;
        for(std::vector<std::pair<Index<4>,std::vector<Real> > >::const_iterator i = harmonic_impropers.begin();
            i != harmonic_impropers.end(); ++i){
          custom_parameters[0] = i->second[0];
          custom_parameters[1] = i->second[1];
          harmonic_improper_force.addTorsion(i->first[0],i->first[1],i->first[2],i->first[3],
                                             custom_parameters);
        }
      }
    
      const std::vector<std::pair<Index<5>,std::vector<Real> > >& cmaps = top->GetCMaps();
      if(!cmaps.empty()){
        std::vector<std::vector<Real> > unique_cmap_parameters;
        std::vector<Real> current_parameters;
        std::vector<int> map_indices;
        bool cmap_present;
    
        for(std::vector<std::pair<Index<5>,std::vector<Real> > >::const_iterator i = cmaps.begin();
            i != cmaps.end(); ++i){
          cmap_present = false;
          current_parameters = i->second;
          for(uint j = 0; j < unique_cmap_parameters.size(); ++j){
            if(current_parameters == unique_cmap_parameters[j]){
              cmap_present = true;
              map_indices.push_back(j);
              break;
            }
          }
          if(!cmap_present){
            unique_cmap_parameters.push_back(current_parameters);
            map_indices.push_back(unique_cmap_parameters.size()-1);
          }
        } 
    
        OpenMM::CMAPTorsionForce& cmap_force = *new OpenMM::CMAPTorsionForce();       
        sys->addForce(&cmap_force);
        mapper[CMap] = mapper_index++;
    
        for(std::vector<std::vector<Real> >::iterator u_cmap = unique_cmap_parameters.begin();
            u_cmap != unique_cmap_parameters.end(); ++u_cmap){
          uint size = sqrt(u_cmap->size());
          if(size * size != u_cmap->size()){
            throw ost::Error("Expect cmap to be quadratic!");
          }
    
          //in charmm/gromacs the cmap has the following order regarding angle bins:
          //(phi1,psi1),(phi1,psi2)...
          //openmm requires following order:
          //(phi1,psi1),(phi2,psi1)...
    
          //in charmm/gromacs the range of the angles in the map is [-180,180],[-pi,pi]
          //respectively
          //openmm requires the range to be [0,2pi], the map has to be shifted...
    
          //=>we need basically two "transformation"
    
          std::vector<double> transformed_map;
          for(uint i = 0; i < size; ++i){
            for(uint j = 0; j < size; ++j){
              transformed_map.push_back((*u_cmap)[size*((j+size/2)%size) + ((i+size/2)%size)]);
            }
          }
          cmap_force.addMap(size, transformed_map);
        }
    
        //add the cmaps
        int atom1,atom2,atom3,atom4,atom5;
        for(uint i = 0; i < cmaps.size(); ++i){
          atom1 = cmaps[i].first[0];
          atom2 = cmaps[i].first[1];
          atom3 = cmaps[i].first[2];
          atom4 = cmaps[i].first[3];
          atom5 = cmaps[i].first[4];
          cmap_force.addTorsion(map_indices[i],atom1,atom2,atom3,atom4,atom2,atom3,atom4,atom5);
        }
      }
    
      const std::vector<std::pair<Index<1>,std::vector<Real> > >& harmonic_position_restraints = top->GetHarmonicPositionRestraints();
      if(!harmonic_position_restraints.empty()){
        OpenMM::CustomExternalForce& position_restraint_force = *new OpenMM::CustomExternalForce("k_force*(x_scale*(x-x0)^2+y_scale*(y-y0)^2+z_scale*(z-z0)^2)");
        position_restraint_force.addPerParticleParameter("x0");
        position_restraint_force.addPerParticleParameter("y0");
        position_restraint_force.addPerParticleParameter("z0");
        position_restraint_force.addPerParticleParameter("k_force");
        position_restraint_force.addPerParticleParameter("x_scale");
        position_restraint_force.addPerParticleParameter("y_scale");
        position_restraint_force.addPerParticleParameter("z_scale");
        sys->addForce(&position_restraint_force);
        mapper[HarmonicPositionRestraint] = mapper_index++;
        for(std::vector<std::pair<Index<1>,std::vector<Real> > >::const_iterator i = harmonic_position_restraints.begin();
            i != harmonic_position_restraints.end(); ++i){
          //stupid cast
          std::vector<double> parameters;
          for(std::vector<Real>::const_iterator j = i->second.begin();
              j != i->second.end(); ++j){
            parameters.push_back(*j);
          }
          position_restraint_force.addParticle(i->first[0], parameters);
        }
      } 
    
      const std::vector<std::pair<Index<2>,std::vector<Real> > > harmonic_distance_restraints = top->GetHarmonicDistanceRestraints();
      if(!harmonic_distance_restraints.empty()){
        OpenMM::HarmonicBondForce& harmonic_distance_restraint_force = *new OpenMM::HarmonicBondForce();
        sys->addForce(&harmonic_distance_restraint_force);
        mapper[HarmonicDistanceRestraint] = mapper_index++;
        for(std::vector<std::pair<Index<2>,std::vector<Real> > >::const_iterator i = harmonic_distance_restraints.begin();
            i != harmonic_distance_restraints.end(); ++i){
          //note, that the restraint formula is k(b-b0)^2 instead of 1/2*k(b-b0)^2 => multiply by two!
          harmonic_distance_restraint_force.addBond(i->first[0],i->first[1],i->second[0],2*i->second[1]);
        }
      }
    
      std::vector<Real> sigmas = top->GetSigmas();
      std::vector<Real> epsilons = top->GetEpsilons();
      std::vector<Real> charges = top->GetCharges();
      if(!sigmas.empty() && !epsilons.empty() && !charges.empty()){
        OpenMM::NonbondedForce& nonbonded_force = *new OpenMM::NonbondedForce();
        nonbonded_force.setNonbondedMethod(settings->nonbonded_method);
        //we can set the cutoff in any case, since it will have no effect when
        //nonbonded method is NoCutoff
        nonbonded_force.setCutoffDistance(settings->nonbonded_cutoff/10.0);
        nonbonded_force.setReactionFieldDielectric(settings->reaction_field_dielectric);
        nonbonded_force.setUseDispersionCorrection(settings->use_dispersion_correction);
        sys->addForce(&nonbonded_force);
        mapper[LJ] = mapper_index++;
    
        //we first add all single particles to the force
        for(uint i = 0; i < charges.size(); ++i){
          nonbonded_force.addParticle(charges[i], sigmas[i], epsilons[i]);
        }
        //take care of the 1-4 interactions
        const std::vector<std::pair<Index<2>,std::vector<Real> > >& lj_pairs = top->GetLJPairs();
        if(!lj_pairs.empty()){
          Real fudge_lj = top->GetFudgeLJ();
          Real fudge_qq = top->GetFudgeQQ();
          Real charge;
          for(std::vector<std::pair<Index<2>,std::vector<Real> > >::const_iterator i = lj_pairs.begin();
              i != lj_pairs.end(); ++i){
            charge = fudge_qq * charges[i->first[0]] * charges[i->first[1]];
            nonbonded_force.addException(i->first[0],i->first[1],charge,
                                         i->second[0],fudge_lj*i->second[1]);
          }
        }
        //take care of the exclusions
        const std::vector<Index<2> >& exclusions = top->GetExclusions();
        if(!exclusions.empty()){
          for(std::vector<Index<2> >::const_iterator i = exclusions.begin(); i != exclusions.end(); ++i){
            nonbonded_force.addException((*i)[0],(*i)[1],0.0,1.0,0.0);
          }
        }
      }
      std::vector<Real> gbsa_radii = top->GetGBSARadii();
      std::vector<Real> gbsa_scaling = top->GetOBCScalings();
      if(!gbsa_radii.empty() && !gbsa_scaling.empty()){
        std::vector<Real> charges = top->GetCharges();
        if(charges.empty())
          throw ost::Error("GBSA force requires atom charges to be set!");
        OpenMM::GBSAOBCForce& gbsa_force = *new OpenMM::GBSAOBCForce();
        sys->addForce(&gbsa_force);
        if(settings->nonbonded_method == OpenMM::NonbondedForce::NoCutoff){
          gbsa_force.setNonbondedMethod(OpenMM::GBSAOBCForce::NoCutoff);
        }
        else if(settings->nonbonded_method == OpenMM::NonbondedForce::CutoffNonPeriodic){
          gbsa_force.setNonbondedMethod(OpenMM::GBSAOBCForce::CutoffNonPeriodic);
        }
        else if(settings->nonbonded_method == OpenMM::NonbondedForce::CutoffPeriodic){
          gbsa_force.setNonbondedMethod(OpenMM::GBSAOBCForce::CutoffPeriodic);
        }
        else{
          throw ost::Error("Can only use Nonbonded methods NoCutoff, CutoffNonPeriodic,CutoffPeriodic when using GBSA");
        }
        mapper[GBSA] = mapper_index++;
        gbsa_force.setCutoffDistance(settings->nonbonded_cutoff/10);
        gbsa_force.setSolventDielectric(settings->solvent_dielectric);
        gbsa_force.setSoluteDielectric(settings->solute_dielectric);
        //it should be guaranteed from the topology object, that the vectors have the same size 
        for(uint i = 0; i < gbsa_radii.size(); ++i){
          gbsa_force.addParticle(charges[i],
                                 gbsa_radii[i],
                                 gbsa_scaling[i]);
        }
      }
      //set constraints
      std::vector<std::pair<Index<2>,std::vector<Real> > > distance_constraints = top->GetDistanceConstraints();
      if(!distance_constraints.empty()){
        for(std::vector<std::pair<Index<2>,std::vector<Real> > >::iterator i = distance_constraints.begin();
            i != distance_constraints.end(); ++i){
          sys->addConstraint(i->first[0],i->first[1],i->second[0]);
        }
      }
      //set periodic box extents
      if(geom::Length(settings->periodic_box_extents) > 0){
        OpenMM::Vec3 x_vec(settings->periodic_box_extents[0]/10,0.0,0.0);
        OpenMM::Vec3 y_vec(0.0,settings->periodic_box_extents[1]/10,0.0);
        OpenMM::Vec3 z_vec(0.0,0.0,settings->periodic_box_extents[2]/10);
        sys->setDefaultPeriodicBoxVectors(x_vec,y_vec,z_vec);
      }
      else if(settings->add_nonbonded && 
               !(settings->nonbonded_method == OpenMM::NonbondedForce::NoCutoff ||
                settings->nonbonded_method == OpenMM::NonbondedForce::CutoffNonPeriodic)){
        throw ost::Error("Chosen nonbonded method requires to define the periodic box extents!");
      }
      //set the CMMMotion removing force if required
      if(settings->remove_cmm_motion){
        if(settings->cmm_frequency != settings->cmm_frequency){
          throw ost::Error("Cannot set CMM Remover without valid cmm_frequency set!");
        }
        sys->addForce(new OpenMM::CMMotionRemover(settings->cmm_frequency));
      }
      if(settings->add_thermostat){
        if(settings->thermostat_temperature != settings->thermostat_temperature ||
           settings->thermostat_collision_frequency != settings->thermostat_collision_frequency){
          throw ost::Error("Cannot set thermostat without defined temperature and collision frequency!");
        }
        OpenMM::AndersenThermostat& thermostat = *new OpenMM::AndersenThermostat(settings->thermostat_temperature, 
                                                                                 settings->thermostat_collision_frequency);
        sys->addForce(&thermostat);
      }
      if(settings->add_barostat){
        if(geom::Length(settings->periodic_box_extents) == 0){
          throw ost::Error("If you set a barostat, you also have to set nonzero periodic box extents!");
        }
        if(settings->barostat_temperature != settings->barostat_temperature ||
           settings->barostat_pressure != settings->barostat_pressure ||
           settings->barostat_frequency != settings->barostat_frequency){
          throw ost::Error("Cannot set barostat without defined temperature, pressure, and frequency parameters!");
        }
        OpenMM::MonteCarloBarostat& barostat = *new OpenMM::MonteCarloBarostat(settings->barostat_pressure,
                                                                               settings->barostat_temperature,
                                                                               settings->barostat_frequency);
        sys->addForce(&barostat);
      }
      return sys;
    }
    }}} //ns