示例#1
0
void MolecularDynamicsMover::do_reject() {
  IMP_OBJECT_LOG;
  ParticlesTemp ps = md_->get_simulation_particles();
  unsigned nparts = ps.size();
  IMP_USAGE_CHECK(coordinates_.size() == ps.size(),
                  "The list of particles that move has been changed!");
  IMP_USAGE_CHECK(velocities_.size() == ps.size(),
                  "The list of particles that move has been changed!");
  for (unsigned i = 0; i < nparts; i++) {
    bool isnuisance = Nuisance::get_is_setup(ps[i]);
    bool isxyz = core::XYZ::get_is_setup(ps[i]);
    IMP_USAGE_CHECK(isnuisance || isxyz,
                    "Particle " << ps[i] << " is neither nuisance nor xyz!");
    if (isnuisance) {
      IMP_USAGE_CHECK(coordinates_[i].size() == 1,
                      "wrong size for coordinates_[" << i << "] !");
      IMP_USAGE_CHECK(velocities_[i].size() == 1, "wrong size for velocities_["
                                                      << i << "] !");
      Nuisance(ps[i]).set_nuisance(coordinates_[i][0]);
      ps[i]->set_value(FloatKey("vel"), velocities_[i][0]);
    }
    if (isxyz) {
      IMP_USAGE_CHECK(coordinates_[i].size() == 3,
                      "wrong size for coordinates_[" << i << "] !");
      IMP_USAGE_CHECK(velocities_[i].size() == 3, "wrong size for velocities_["
                                                      << i << "] !");
      core::XYZ(ps[i]).set_coordinate(0, coordinates_[i][0]);
      core::XYZ(ps[i]).set_coordinate(1, coordinates_[i][1]);
      core::XYZ(ps[i]).set_coordinate(2, coordinates_[i][2]);
      ps[i]->set_value(FloatKey("vx"), velocities_[i][0]);
      ps[i]->set_value(FloatKey("vy"), velocities_[i][1]);
      ps[i]->set_value(FloatKey("vz"), velocities_[i][2]);
    }
  }
}
示例#2
0
文件: blame.cpp 项目: AljGaber/imp
display::Geometries create_blame_geometries(const RestraintsTemp &rs,
                                            const ParticlesTemp &ps,
                                            double max, std::string name) {
  IMP_FUNCTION_LOG;
  FloatKey key("blame temporary key");
  assign_blame(rs, ps, key);
  if (max == NO_MAX) {
    max = -NO_MAX;
    for (unsigned int i = 0; i < ps.size(); ++i) {
      max = std::max(ps[i]->get_value(key), max);
    }
    IMP_LOG_TERSE("Maximum blame value is " << max << std::endl);
  }
  display::Geometries ret;
  for (unsigned int i = 0; i < ps.size(); ++i) {
    double colorv;
    if (max == 0) {
      colorv = 0;
    } else {
      colorv =
          display::get_linear_color_map_value(0, max, ps[i]->get_value(key));
    }
    display::Color c = display::get_hot_color(colorv);
    IMP_NEW(XYZRGeometry, g, (ps[i]));
    if (!name.empty()) {
      g->set_name(name);
    }
    g->set_color(c);
    ret.push_back(g);
  }
  return ret;
}
示例#3
0
/* Return all particles whose attributes are read by the restraints. To
   do this, ask the pair score what particles it uses.*/
ModelObjectsTemp  SigmoidRestraintSphere::do_get_inputs() const
{
  ParticlesTemp ret;
  ret.push_back(get_model()->get_particle(p1_));
  ret.push_back(get_model()->get_particle(p2_));
  return ret;
}
ParticlesTemp
CoreCloseBipartitePairContainer::get_all_possible_particles() const {
  ParticlesTemp ret = sc_[0]->get_particles();
  ParticlesTemp ret1= sc_[1]->get_particles();
  ret.insert(ret.end(), ret1.begin(), ret1.end());
  return ret;
}
示例#5
0
IMPCORE_BEGIN_NAMESPACE
MoveStatisticsScoreState::MoveStatisticsScoreState(
    const ParticlesTemp &ps)
    : ScoreState(ps[0]->get_model(), "MoveStatisticsScoreState%1%"),
      ps_(ps.begin(), ps.end()) {
  reset();
}
示例#6
0
double get_radius_of_gyration(const ParticlesTemp& ps) {
  IMP_USAGE_CHECK(ps.size() > 0, "No particles provided");
  bool mass = Mass::get_is_setup(ps[0]);
  bool radii = core::XYZR::get_is_setup(ps[0]);
  algebra::Vector3D cm(0, 0, 0);
  double total = 0;
  for (unsigned int i = 0; i < ps.size(); ++i) {
    double weight = get_weight(mass, radii, ps[i]);
    total += weight;
    cm += core::XYZ(ps[i]).get_coordinates() * weight;
  }
  cm /= total;
  double ret = 0;
  for (unsigned int i = 0; i < ps.size(); ++i) {
    double c;
    if (radii) {
      c = .6 * square(core::XYZR(ps[i]).get_radius());
    } else {
      c = 0;
    }
    double d = get_squared_distance(core::XYZ(ps[i]).get_coordinates(), cm);
    ret += get_weight(mass, radii, ps[i]) * (d + c);
  }
  return std::sqrt(ret / total);
}
示例#7
0
文件: Hierarchy.cpp 项目: drussel/imp
void destroy(Hierarchy d) {
  ParticlesTemp all;
  //core::Hierarchy h=d;

  core::gather(d, True(), std::back_inserter(all));
  for (unsigned int i=0; i< all.size(); ++i) {
    if (Bonded::particle_is_instance(all[i])) {
     Bonded b(all[i]);
      while (b.get_number_of_bonds() > 0) {
        destroy_bond(b.get_bond(b.get_number_of_bonds()-1));
      }
    }
    Hierarchy hc(all[i]);
    while (hc.get_number_of_children() > 0) {
      hc.remove_child(hc.get_child(hc.get_number_of_children()-1));
    }
  }

  // If this Hierarchy has a parent, remove the relationship
  Hierarchy parent = d.get_parent();
  if (parent) {
    parent.remove_child(d);
  }

  for (unsigned int i=0; i< all.size(); ++i) {
    all[i]->get_model()->remove_particle(all[i]);
  }
}
示例#8
0
文件: blame.cpp 项目: AljGaber/imp
void assign_blame(const RestraintsTemp &rs,
                  const ParticlesTemp &ps, FloatKey attribute) {
  IMP_FUNCTION_LOG;
  for (unsigned int i = 0; i < ps.size(); ++i) {
    if (ps[i]->has_attribute(attribute)) {
      ps[i]->set_value(attribute, 0);
    } else {
      ps[i]->add_attribute(attribute, 0, false);
    }
  }
  Restraints drs;
  for (unsigned int i = 0; i < rs.size(); ++i) {
    Pointer<Restraint> rd = rs[i]->create_decomposition();
    if (rd) {
      drs.push_back(rd);
    }
  }
  IMP_NEW(RestraintsScoringFunction, rsf, (drs));
  rsf->evaluate(false);
  DependencyGraph dg = get_dependency_graph(IMP::internal::get_model(rs));
  // attempt to get around boost/gcc bug and the most vexing parse
  DependencyGraphVertexIndex dgi((IMP::get_vertex_index(dg)));
  ControlledBy controlled_by;
  for (unsigned int i = 0; i < ps.size(); ++i) {
    ParticlesTemp cps = get_dependent_particles(ps[i], ps, dg, dgi);
    IMP_INTERNAL_CHECK(cps.size() > 0, "No dependent particles for " << ps[i]);
    for (unsigned int j = 0; j < cps.size(); ++j) {
      controlled_by[cps[j]] = ps[i];
    }
  }
  for (unsigned int i = 0; i < drs.size(); ++i) {
    distribute_blame(drs[i], controlled_by, attribute, 1.0);
  }
}
示例#9
0
void MolecularDynamicsMover::save_coordinates() {
  IMP_OBJECT_LOG;
  ParticlesTemp ps = md_->get_simulation_particles();
  unsigned nparts = ps.size();
  coordinates_.clear();
  coordinates_.reserve(nparts);
  velocities_.clear();
  velocities_.reserve(nparts);
  for (unsigned i = 0; i < nparts; i++) {
    bool isnuisance = Nuisance::get_is_setup(ps[i]);
    bool isxyz = core::XYZ::get_is_setup(ps[i]);
    IMP_USAGE_CHECK(isnuisance || isxyz,
                    "Particle " << ps[i] << " is neither nuisance nor xyz!");
    if (isnuisance) {
      std::vector<double> x(1, Nuisance(ps[i]).get_nuisance());
      coordinates_.push_back(x);
      std::vector<double> v(1, ps[i]->get_value(FloatKey("vel")));
      velocities_.push_back(v);
    }
    if (isxyz) {
      std::vector<double> coords;
      core::XYZ d(ps[i]);
      coords.push_back(d.get_coordinate(0));
      coords.push_back(d.get_coordinate(1));
      coords.push_back(d.get_coordinate(2));
      coordinates_.push_back(coords);
      std::vector<double> v;
      v.push_back(ps[i]->get_value(FloatKey("vx")));
      v.push_back(ps[i]->get_value(FloatKey("vy")));
      v.push_back(ps[i]->get_value(FloatKey("vz")));
      velocities_.push_back(v);
    }
  }
}
示例#10
0
InteractionGraph get_interaction_graph(ScoringFunctionAdaptor rsi,
                                       const ParticlesTemp &ps) {
  if (ps.empty()) return InteractionGraph();
  InteractionGraph ret(ps.size());
  Restraints rs =
      create_decomposition(rsi->create_restraints());
  // Model *m= ps[0]->get_model();
  boost::unordered_map<ModelObject *, int> map;
  InteractionGraphVertexName pm = boost::get(boost::vertex_name, ret);
  DependencyGraph dg = get_dependency_graph(ps[0]->get_model());
  DependencyGraphVertexIndex index = IMP::get_vertex_index(dg);
  /*IMP_IF_LOG(VERBOSE) {
    IMP_LOG_VERBOSE( "dependency graph is \n");
    IMP::internal::show_as_graphviz(dg, std::cout);
    }*/
  for (unsigned int i = 0; i < ps.size(); ++i) {
    ParticlesTemp t = get_dependent_particles(
        ps[i], ParticlesTemp(ps.begin(), ps.end()), dg, index);
    for (unsigned int j = 0; j < t.size(); ++j) {
      IMP_USAGE_CHECK(map.find(t[j]) == map.end(),
                      "Currently particles which depend on more "
                          << "than one particle "
                          << "from the input set are not supported."
                          << "  Particle \"" << t[j]->get_name()
                          << "\" depends on \"" << ps[i]->get_name()
                          << "\" and \""
                          << ps[map.find(t[j])->second]->get_name() << "\"");
      map[t[j]] = i;
    }
    IMP_IF_LOG(VERBOSE) {
      IMP_LOG_VERBOSE("Particle \"" << ps[i]->get_name() << "\" controls ");
      for (unsigned int i = 0; i < t.size(); ++i) {
        IMP_LOG_VERBOSE("\"" << t[i]->get_name() << "\" ");
      }
      IMP_LOG_VERBOSE(std::endl);
    }
    pm[i] = ps[i];
  }
  IMP::Restraints all_rs = IMP::get_restraints(rs);
  for (Restraints::const_iterator it = all_rs.begin();
       it != all_rs.end(); ++it) {
    ModelObjectsTemp pl = (*it)->get_inputs();
    add_edges(ps, pl, map, *it, ret);
  }
  /* Make sure that composite score states (eg the normalizer for
     rigid body rotations) don't induce interactions among unconnected
     particles.*/
  ScoreStatesTemp ss = get_required_score_states(rs);
  for (ScoreStatesTemp::const_iterator it = ss.begin(); it != ss.end(); ++it) {
    ModelObjectsTemps interactions = (*it)->get_interactions();
    for (unsigned int i = 0; i < interactions.size(); ++i) {
      add_edges(ps, interactions[i], map, *it, ret);
    }
  }
  IMP_INTERNAL_CHECK(boost::num_vertices(ret) == ps.size(),
                     "Wrong number of vertices " << boost::num_vertices(ret)
                                                 << " vs " << ps.size());
  return ret;
}
示例#11
0
ModelObjectsTemp NOERestraint::do_get_inputs() const {
  ParticlesTemp ret;
  ret.push_back(p0_);
  ret.push_back(p1_);
  ret.push_back(sigma_);
  ret.push_back(gamma_);
  return ret;
}
示例#12
0
const ParticlesTemp
FixedRefiner::get_refined(Particle *) const
{
  ParticlesTemp ps;
  for(unsigned int i=0; i < pis_.size(); i++){
    ps.push_back(m_->get_particle(pis_[i]));
  }
  return ps;
}
ParticlesTemp RadiusOfGyrationRestraint::get_input_particles() const
{
  ParticlesTemp pt;
  for (ParticleConstIterator it= particles_begin();
       it != particles_end(); ++it) {
      pt.push_back(*it);
  }
  return pt;
}
ParticlesTemp
GaussianProcessInterpolationRestraintSparse::get_input_particles() const
{
    ParticlesTemp ret;
    ParticlesTemp ret1 = gpi_->mean_function_->get_input_particles();
    ret.insert(ret.end(),ret1.begin(),ret1.end());
    ParticlesTemp ret2 = gpi_->covariance_function_->get_input_particles();
    ret.insert(ret.end(),ret2.begin(),ret2.end());
    return ret;
}
IMPATOM_BEGIN_NAMESPACE

RemoveRigidMotionOptimizerState::RemoveRigidMotionOptimizerState(
    const ParticlesTemp &pis, unsigned skip_steps) :
  pis_(pis.begin(), pis.end()), skip_steps_(skip_steps),
    call_number_(0)
{
  vs_[0] = FloatKey("vx");
  vs_[1] = FloatKey("vy");
  vs_[2] = FloatKey("vz");
}
示例#16
0
文件: io.cpp 项目: drussel/imp
base::Vector<char>
write_particles_to_buffer(const ParticlesTemp &particles,
                          const FloatKeys &keys) {
  if (particles.empty() || keys.empty()) {
    return base::Vector<char>();
  }
  unsigned int size= particles.size()*keys.size()*sizeof(double);
  base::Vector<char> ret(size);
  write_particles_to_buffer(particles, keys, &ret.front(), size);
  return ret;
}
示例#17
0
const ParticlesTemp RigidLeavesRefiner::get_refined(Particle *p) const {
  ParticlesTemp members = core::RigidBody(p).get_rigid_members();
  ParticlesTemp ret;
  for (ParticlesTemp::const_iterator it = members.begin(); it != members.end();
       ++it) {
    if (atom::Hierarchy::get_is_setup(*it)
        && atom::Hierarchy(*it).get_number_of_children() == 0) {
      ret.push_back(*it);
    }
  }
  return ret;
}
float get_actual_radius_of_gyration(ParticlesTemp ps) {
  algebra::Vector3D cm(0,0,0);
  for (unsigned int i=0; i< ps.size(); ++i) {
    cm+= core::XYZ(ps[i]).get_coordinates();
  }
  cm/=ps.size();
  double ret=0;
  for (unsigned int i=0; i < ps.size(); ++i) {
    double d= get_distance(core::XYZ(ps[i]).get_coordinates(),cm);
    ret+= d;
  }
  return ret/ps.size();
}
示例#19
0
ParticlesTemp get_output_particles(const ModelObjectsTemp &mo) {
  ParticlesTemp ret;
  for (unsigned int i = 0; i < mo.size(); ++i) {
    ModelObject *o = mo[i];
    Particle *p = dynamic_cast<Particle *>(o);
    if (p)
      ret.push_back(p);
    else {
      ret += get_output_particles(o->get_inputs());
    }
  }
  return ret;
}
void DerivativesToRefined
::apply(Particle *p,
        DerivativeAccumulator &da) const
{
  ParticlesTemp ps = refiner_->get_refined(p);

  for (unsigned int i=0; i< ps.size(); ++i) {
    for (unsigned int j=0; j< ks_.size(); ++j) {
      Float f= p->get_derivative(ks_[j]);
      ps[i]->add_to_derivative(ks_[j], f, da);
    }
  }
}
示例#21
0
IMPEM_BEGIN_NAMESPACE

FitRestraint::FitRestraint(
   ParticlesTemp ps,
   DensityMap *em_map,
   FloatPair norm_factors,
   FloatKey weight_key,
   float scale,
   bool use_rigid_bodies,
   KernelType kt
                           ): Restraint(IMP::internal::get_model(ps),
                                        "Fit restraint"),kt_(kt)
{
  use_rigid_bodies_=use_rigid_bodies;
  IMP_LOG(TERSE,"Load fit restraint with the following input:"<<
          "number of particles:"<<ps.size()<<" scale:"<<scale<<
           "\n");
  // special_treatment_of_particles_outside_of_density_=
  //   special_treatment_of_particles_outside_of_density;
  target_dens_map_ = em_map;
  weight_key_=weight_key;
  norm_factors_=norm_factors;
  IMP_IF_CHECK(USAGE) {
    for (unsigned int i=0; i< ps.size(); ++i) {
      IMP_USAGE_CHECK(core::XYZR::particle_is_instance(ps[i]),
                      "Particle " << ps[i]->get_name()
                      << " is not XYZR"
                      << std::endl);
      IMP_USAGE_CHECK(ps[i]->has_attribute(weight_key),
                "Particle " << ps[i]->get_name()
                << " is missing the mass "<< weight_key
                << std::endl);
    }
  }
  scalefac_ = scale;
  store_particles(ps);
  IMP_LOG(TERSE,"after adding "<< all_ps_.size()<<" particles"<<std::endl);
  model_dens_map_ = new SampledDensityMap(*em_map->get_header(),kt_);
  model_dens_map_->set_particles(get_as<ParticlesTemp>(all_ps_),weight_key);
  kernel_params_=model_dens_map_->get_kernel_params();
  dist_mask_=new DistanceMask(model_dens_map_->get_header());
  IMP_LOG(TERSE,"going to initialize_model_density_map"<<std::endl);
  initialize_model_density_map(weight_key);
  IMP_LOG(TERSE,"going to initialize derivatives"<<std::endl);
   // initialize the derivatives
  dv_.insert(dv_.end(),all_ps_.size(),algebra::Vector3D(0.,0.,0.));

  // normalize the target density data
  //target_dens_map->std_normalize();
  IMP_LOG(TERSE, "Finish initialization" << std::endl);
}
/* Return all particles whose attributes are read by the restraints. To
   do this, ask the pair score what particles it uses.*/
ParticlesTemp MarginalHBondRestraint::get_input_particles() const
{
  ParticlesTemp ret;
  for (unsigned i=0; i<volumes_.size(); ++i)
  {
      int npairs = contribs_[i]->get_number_of_particle_pairs();
      for (int j=0; j < npairs; ++j)
      {
          ret.push_back(contribs_[i]->get_particle_pair(j)[0]);
          ret.push_back(contribs_[i]->get_particle_pair(j)[1]);
      }
  }
  return ret;
}
示例#23
0
文件: Refiner.cpp 项目: salilab/imp
ParticleIndexes Refiner::get_refined_indexes(Model *m,
                                             ParticleIndex pi) const {
  ParticlesTemp ps = get_refined( m->get_particle(pi) );
  IMP_IF_CHECK(USAGE_AND_INTERNAL) {
    for(unsigned int i = 0; i < ps.size(); i++) {
      if (ps[i]->get_model() != m) {
        IMP_THROW("Refined particles model does not match parent model - "
                  "this is critical if get_refined_indexes() is used.",
                  IMP::ValueException);
      }
    }
  }
  return get_indexes(ps);
}
示例#24
0
IMPCORE_BEGIN_NAMESPACE

FixedRefiner::FixedRefiner(const ParticlesTemp &ps)
  : Refiner("FixedRefiner%d", true) {
  IMP_USAGE_CHECK(ps.size()>0, "cannot refine with empty particle list");
  IMP_LOG_VERBOSE("Created fixed particle refiner with "
                  << ps.size() << " particles" << std::endl);
  m_ = ps[0]->get_model();
  for(unsigned int i = 0; i < ps.size(); i++){
    IMP_USAGE_CHECK(m_ == ps[i]->get_model(),
                    "refiner assumes all particles are from the same model");
    pis_.push_back(ps[i]->get_index());
  }
}
示例#25
0
core::MonteCarloMoverResult BallMover::do_propose() {
  IMP_OBJECT_LOG;

  // random displacement
  algebra::Vector3D displacement = algebra::get_random_vector_in(
      algebra::Sphere3D(algebra::Vector3D(0.0, 0.0, 0.0), max_tr_));

  // store old coordinates of master particle
  oldcoord_ = core::XYZ(p_).get_coordinates();

  // master particle coordinates after displacement
  algebra::Vector3D nc = oldcoord_ + displacement;

  // find center of the closest cell
  double mindist = 1.0e+24;
  unsigned icell = 0;
  for (unsigned i = 0; i < ctrs_.size(); ++i) {
    // calculate distance between nc and cell center
    double dist = algebra::get_l2_norm(nc - ctrs_[i]);
    // find minimum distance
    if (dist < mindist) {
      mindist = dist;
      icell = i;
    }
  }

  // find inverse transformation
  algebra::Transformation3D cell_tr = trs_[icell].get_inverse();

  // set new coordinates for master particle
  core::XYZ(p_).set_coordinates(cell_tr.get_transformed(nc));

  // set new coordinates for slave particles
  oldcoords_.clear();
  for (unsigned i = 0; i < ps_.size(); ++i) {
    core::XYZ xyz = core::XYZ(ps_[i]);
    algebra::Vector3D oc = xyz.get_coordinates();
    // store old coordinates
    oldcoords_.push_back(oc);
    // apply transformation
    algebra::Vector3D nc = cell_tr.get_transformed(oc);
    xyz.set_coordinates(nc);
  }

  ParticlesTemp ret;
  ret.push_back(p_);
  ret.insert(ret.end(), ps_.begin(), ps_.end());

  return core::MonteCarloMoverResult(get_indexes(ret), 1.0);
}
示例#26
0
IMPCORE_BEGIN_NAMESPACE

FixedRefiner::FixedRefiner(const ParticlesTemp &ps):
  Refiner("FixedRefiner%d"), ps_(ps){
  IMP_LOG(VERBOSE, "Created fixed particle refiner with " << ps.size()
          << " particles" << std::endl);
}
示例#27
0
IMPMULTIFIT_BEGIN_NAMESPACE
void add_surface_index(core::Hierarchy mh, Float apix, FloatKey shell_key,
                       FloatKey, FloatKey) {
  ParticlesTemp ps = core::get_leaves(mh);
  Pointer<em::SurfaceShellDensityMap> shell_map =
      new em::SurfaceShellDensityMap(ps, apix);

  for (unsigned int i = 0; i < ps.size(); i++) {
    IMP_INTERNAL_CHECK(!ps[i]->has_attribute(shell_key),
                       "Particle " << ps[i]->get_name()
                                   << " already has shell attribute"
                                   << std::endl);
    ps[i]->add_attribute(
        shell_key, shell_map->get_value(core::XYZ(ps[i]).get_coordinates()));
  }
}
示例#28
0
void CollisionCrossSection::set_model_particles(
    const ParticlesTemp &ps) {

  IMP_LOG_TERSE("CollisionCrossSection: Model particles set"
                << std::endl);

  for (unsigned int i = 0; i < ps.size(); ++i) {
    IMP_USAGE_CHECK(
        (core::XYZR::get_is_setup(ps[i]) && atom::Mass::get_is_setup(ps[i])),
        "Particle " << i << " does not have the required attributes"
                    << std::endl);
  }
  masks_manager_->create_masks(ps);
  // Compute projections
  collision_cross_section_ = 0.0;
  for (unsigned int i = 0; i < n_projections_; ++i) {
    ProjectingOptions options(pixel_size_, resolution_);
    do_project_particles(ps, average_projection_, regs_[i].get_rotation(),
                         pixel_size_ * regs_[i].get_shift_3d(), options,
                         masks_manager_);
    collision_cross_section_ += get_projected_area(average_projection_);
  }
  collision_cross_section_ /= static_cast<double>(n_projections_);
  particles_set_ = true;
}
示例#29
0
Float MolecularDynamics::get_kinetic_energy() const {
  // Conversion factor to get energy in kcal/mol from velocities in A/fs and
  // mass in g/mol
  static const Float conversion = 1.0 / 4.1868e-4;

  Float ekinetic = 0.;
  ParticlesTemp ps = get_simulation_particles();
  for (ParticlesTemp::iterator iter = ps.begin(); iter != ps.end();
       ++iter) {
    Particle *p = *iter;
    algebra::Vector3D v = LinearVelocity(p).get_velocity();
    Float mass = Mass(p).get_mass();

    ekinetic += mass * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  }
  return 0.5 * ekinetic * conversion;
}
unsigned int MSConnectivityRestraint::add_type(
    const ParticlesTemp &ps) {
  if (!sc_ && !ps.empty()) {
    sc_ = new IMP::internal::StaticListContainer<SingletonContainer>(
        ps[0]->get_model(), "msconnectivity list");
  }
  ms_get_list(sc_)->add(IMP::internal::get_index(ps));
  return particle_matrix_.add_type(ps);
}