SecondaryStructureResidue setup_coarse_secondary_structure_residue(
    const Particles &ssr_ps, Model *mdl,
    bool winner_takes_all_per_res) {
  Floats scores;
  scores.push_back(0.0);
  scores.push_back(0.0);
  scores.push_back(0.0);
  int count = 0;
  for (Particles::const_iterator p = ssr_ps.begin(); p != ssr_ps.end();
       ++p) {
    IMP_USAGE_CHECK(SecondaryStructureResidue::get_is_setup(*p),
                    "all particles must be SecondaryStructureResidues");
    SecondaryStructureResidue ssr(*p);
    Floats tmp_scores;
    tmp_scores.push_back(ssr.get_prob_helix());
    tmp_scores.push_back(ssr.get_prob_strand());
    tmp_scores.push_back(ssr.get_prob_coil());
    int max_i = 0;
    Float max = 0.0;
    for (int i = 0; i < 3; i++) {
      if (tmp_scores[i] > max) {
        max = tmp_scores[i];
        max_i = i;
      }
      if (!winner_takes_all_per_res) scores[i] += tmp_scores[i];
    }
    if (winner_takes_all_per_res) scores[max_i] += 1.0;
    count++;
  }
  IMP_NEW(Particle, coarse_p, (mdl));
  SecondaryStructureResidue ssres = SecondaryStructureResidue::setup_particle(
      coarse_p, scores[0] / count, scores[1] / count, scores[2] / count);
  return ssres;
}
Ejemplo n.º 2
0
core::MonteCarloMoverResult WeightMover::do_propose() {
  IMP_OBJECT_LOG;

  // store the old weights in case of reject
  oldweights_ = w_.get_weights();

  // Draw weights from a uniform distribution of variables that sum to one
  // taken from http://stats.stackexchange.com/questions/14059/
  //                     generate-uniformly-distributed-weights-that-sum-to-unity

  // get the old x
  Floats x;
  x.push_back(oldweights_[0]);
  for (unsigned i = 1; i < oldweights_.get_dimension() - 1; ++i) {
    x.push_back(oldweights_[i] + x[i - 1]);
  }

  // zero vector in D dimension
  algebra::VectorKD zero = algebra::get_zero_vector_kd(x.size());

  // generate random perturbation of old components
  algebra::VectorKD dX =
      algebra::get_random_vector_in(algebra::SphereKD(zero, radius_));

  // add perturbation to x and apply reflective boundaries
  for (unsigned i = 0; i < x.size(); ++i) {
    if (x[i] + dX[i] > 1.0)
      x[i] = 2.0 - x[i] - dX[i];
    else if (x[i] + dX[i] < 0.0)
      x[i] = -x[i] - dX[i];
    else
      x[i] += dX[i];
  }

  // sort the new x here
  std::sort(x.begin(), x.end(), std::less<double>());

  // get the new weights
  algebra::VectorKD newweights =
      algebra::get_zero_vector_kd(oldweights_.get_dimension());

  newweights[0] = x[0];
  for (unsigned i = 1; i < newweights.get_dimension() - 1; ++i) {
    newweights[i] = x[i] - x[i - 1];
  }
  newweights[newweights.get_dimension() - 1] = 1.0 - x[x.size() - 1];

  // set the new weights
  w_.set_weights(newweights);

  return core::MonteCarloMoverResult(
      ParticleIndexes(1, w_.get_particle()->get_index()), 1.0);
}
Ejemplo n.º 3
0
Floats CrossLinkData::get_nonmarginal_elements(double sigmai,
                                               Floats dists) const {
  Floats probs;
  if (bias_) {
    for (unsigned n = 0; n < dists.size(); n++) {
      probs.push_back(get_biased_element(dists[n], sigmai));
    }
  }
  if (!bias_) {
    for (unsigned n = 0; n < dists.size(); n++) {
      probs.push_back(get_unbiased_element(dists[n], sigmai));
    }
  }
  return probs;
}
Floats GaussianProcessInterpolation::get_posterior_covariance_derivative(
    Floats x, bool) const {
  IMP_Eigen::VectorXd mat(get_posterior_covariance_derivative(x));
  Floats tmp;
  for (unsigned j = 0; j < mat.rows(); j++) tmp.push_back(mat(j));
  return tmp;
}
Ejemplo n.º 5
0
TEST(Neighbors,CoverTreeDistanceNeighbors)
{
	typedef std::vector<float> Floats;
	const int N = 100;
	const int k = 10;

	Floats floats;
	for (int i=0;i<N;i++) 
		floats.push_back(float(i));

	float_distance_callback fdc;
	tapkee::tapkee_internal::Neighbors neighbors = 
		tapkee::tapkee_internal::find_neighbors(tapkee::CoverTree, floats.begin(), floats.end(),
				tapkee::tapkee_internal::PlainDistance<Floats::iterator,float_distance_callback>(fdc), k, true);

	for (int i=0;i<N;i++)
	{
		// total number of found neighbors is k
		ASSERT_EQ(neighbors[i].size(),k);
		std::set<float> neighbors_set;
		for (int j=0;j<k;j++) 
			neighbors_set.insert(neighbors[i][j]);
		// there are no repeated values
		ASSERT_EQ(neighbors_set.size(),k);
		// the vector is not a neighbor of itself
		ASSERT_EQ(neighbors_set.find(floats[i]),neighbors_set.end());
		// check neighbors
		int k_left = std::min(i,k/2);
		int k_right = std::min(N-i-1,k/2);
		for (int j=0; j<k_left; j++) 
			ASSERT_NE(neighbors_set.find(floats[i-j-1]),neighbors_set.end());
		for (int j=0; j<k_right; j++) 
			ASSERT_NE(neighbors_set.find(floats[i+j+1]),neighbors_set.end());
	}
}
Ejemplo n.º 6
0
Floats CysteineCrossLinkData::get_omegas(Floats fmods, double omega0) const {
  Floats omegas;
  for (unsigned n = 0; n < fmods.size(); ++n) {

    double cumul = 0;
    double cumul2 = 0;

    for (unsigned j = 1; j < omega_grid_.size(); ++j) {
      double omj = omega_grid_[j];
      double omjm1 = omega_grid_[j - 1];
      double dom = omj - omjm1;

      double priorj = get_omega_prior(omj, omega0);
      double priorjm1 = get_omega_prior(omjm1, omega0);

      double pj = get_element(fexp_, fmods[n], omj) * priorj;
      double pjm1 = get_element(fexp_, fmods[n], omjm1) * priorjm1;

      double pj2 = get_element(fexp_, fmods[n], omj) * priorj * omj;
      double pjm12 = get_element(fexp_, fmods[n], omjm1) * priorjm1 * omjm1;

      cumul += (pj + pjm1) / 2.0 * dom;
      cumul2 += (pj2 + pjm12) / 2.0 * dom;
    }

    omegas.push_back(cumul2 / cumul);
  }
  return omegas;
}
Ejemplo n.º 7
0
Floats FStudentT::evaluate_derivative_FX(const Floats FXs) const {
  Floats dervs;
  double c = (N_ + nu_) / IMP::square(sigma_) / (nu_ + t2_);
  for (unsigned int i = 0; i < FXs.size(); i++) {
    dervs.push_back(c * (FXs[i] - FM_));
  }
  return dervs;
}
Ejemplo n.º 8
0
Floats ReplicaExchange::create_temperatures(double tmin,double tmax,int nrep)
{
 Floats temp;
 double tfact=exp(log(tmax/tmin)/double(nrep-1));
 for(int i=0;i<nrep;++i) {
  temp.push_back(tmin*pow(tfact,i));
 }
 return temp;
}
FloatsList GaussianProcessInterpolationRestraint::get_hessian(bool) const {
  IMP_Eigen::MatrixXd tmp(get_hessian());
  FloatsList ret;
  for (unsigned i = 0; i < tmp.rows(); ++i) {
    Floats buf;
    for (unsigned j = 0; j < tmp.cols(); ++j) buf.push_back(tmp(i, j));
    ret.push_back(buf);
  }
  return ret;
}
Ejemplo n.º 10
0
Floats CrossLinkData::get_marginal_elements(double sigma, Floats dists) const {
  Floats probs;
  unsigned is = get_closest(sigma_grid_, sigma);
  for (unsigned n = 0; n < dists.size(); n++) {

    unsigned id = get_closest(dist_grid_, dists[n]);
    probs.push_back(grid_[is][id]);
  }
  return probs;
}
FloatsList GaussianProcessInterpolation::get_data_variance() const {
  FloatsList ret;
  IMP_Eigen::MatrixXd S(get_S());
  for (unsigned i = 0; i < M_; i++) {
    Floats val;
    for (unsigned j = 0; j < M_; j++) val.push_back(S(i, j));
    ret.push_back(val);
  }
  return ret;
}
Ejemplo n.º 12
0
Floats CysteineCrossLinkData::get_nonmarginal_elements(double fexp,
                                                       Floats fmods,
                                                       double omega) const {
  Floats probs;

  for (unsigned n = 0; n < fmods.size(); n++) {
    probs.push_back(get_element(fexp, fmods[n], omega));
  }
  return probs;
}
Ejemplo n.º 13
0
IMPISD_BEGIN_NAMESPACE

CysteineCrossLinkData::CysteineCrossLinkData(double fexp, Floats fmod_grid,
                                             Floats omega_grid,
                                             Floats omega0_grid, int prior_type)
    : Object("Data Structure for CysteineCrossLinkRestraint %1%") {
  prior_type_ = prior_type;
  // fexp is the experimental frequency
  // fmod is the model frequency
  // omega0 is the typical value for omega, i.e., the experimental uncertainty

  // this constructor calculates the marginal likelihood using a
  // truncated gaussian function
  // to account for outliers

  // Store omega0 grid
  omega0_grid_ = omega0_grid;

  // Store the fmod grid
  fmod_grid_ = fmod_grid;

  // Store omega grid
  omega_grid_ = omega_grid;

  fexp_ = fexp;

  for (unsigned k = 0; k < omega0_grid_.size(); ++k) {

    double omega0 = omega0_grid_[k];

    Floats grid;

    for (unsigned i = 0; i < fmod_grid_.size(); ++i) {

      double fmod = fmod_grid_[i];

      double cumul = 0;
      for (unsigned j = 1; j < omega_grid_.size(); ++j) {

        double omj = omega_grid_[j];
        double omjm1 = omega_grid_[j - 1];
        double dom = omj - omjm1;

        double priorj = get_omega_prior(omj, omega0);
        double priorjm1 = get_omega_prior(omjm1, omega0);

        double pj = get_element(fexp_, fmod, omj) * priorj;
        double pjm1 = get_element(fexp_, fmod, omjm1) * priorjm1;
        cumul += (pj + pjm1) / 2.0 * dom;
      }
      grid.push_back(cumul);
    }
    grid_.push_back(grid);
  }
}
FloatsList GaussianProcessInterpolation::get_posterior_covariance_hessian(
    Floats x, bool) const {
  IMP_Eigen::MatrixXd mat(get_posterior_covariance_hessian(x));
  FloatsList ret;
  for (unsigned j = 0; j < mat.rows(); j++) {
    Floats tmp;
    for (unsigned i = 0; i < mat.cols(); i++) tmp.push_back(mat(i, j));
    ret.push_back(tmp);
  }
  return ret;
}
Ejemplo n.º 15
0
Floats CysteineCrossLinkData::get_marginal_elements(Floats fmods,
                                                    double omega0) const {
  Floats probs;
  unsigned is = get_closest(omega0_grid_, omega0);
  for (unsigned n = 0; n < fmods.size(); n++) {

    unsigned id = get_closest(fmod_grid_, fmods[n]);
    probs.push_back(grid_[is][id]);
  }
  return probs;
}
Ejemplo n.º 16
0
void ProbabilisticAnchorGraph::set_particle_probabilities_on_anchors(
    Particle *p, FittingSolutionRecords sols) {
  IMP_USAGE_CHECK(sols.size() > 0, "no solutions provided\n");
  IMP_NEW(algebra::NearestNeighborD<3>, nn, (positions_));
  Ints anchor_counters;
  anchor_counters.insert(anchor_counters.end(), positions_.size(), 0);
  for (unsigned int i = 0; i < sols.size(); i++) {
    algebra::Vector3D loc = sols[i].get_fit_transformation().get_transformed(
        core::XYZ(p).get_coordinates());
    anchor_counters[nn->get_nearest_neighbor(loc)]++;
  }
  Floats probs;
  for (unsigned int i = 0; i < anchor_counters.size(); i++) {
    probs.push_back(1. * anchor_counters[i] / sols.size());
  }
  particle_to_anchor_probabilities_[p] = probs;
}
Ejemplo n.º 17
0
Floats CrossLinkData::get_omegas(double sigma, Floats dists) const {
  Floats omegas;
  for (unsigned n = 0; n < dists.size(); ++n) {

    double cumul = 0;
    double cumul2 = 0;

    if (!bias_) {
      for (unsigned j = 1; j < omega_grid_.size(); ++j) {
        double omj = omega_grid_[j];
        double omjm1 = omega_grid_[j - 1];
        double dom = omj - omjm1;

        double pj = get_unbiased_element(dists[n], omj * sigma) / omj;
        double pjm1 = get_unbiased_element(dists[n], omjm1 * sigma) / omjm1;

        double pj2 = get_unbiased_element(dists[n], omj * sigma);
        double pjm12 = get_unbiased_element(dists[n], omjm1 * sigma);

        cumul += (pj + pjm1) / 2.0 * dom;
        cumul2 += (pj2 + pjm12) / 2.0 * dom;
      }
    }

    if (bias_) {
      for (unsigned j = 1; j < omega_grid_.size(); ++j) {
        double omj = omega_grid_[j];
        double omjm1 = omega_grid_[j - 1];
        double dom = omj - omjm1;

        double pj = get_biased_element(dists[n], omj * sigma) / omj;
        double pjm1 = get_biased_element(dists[n], omjm1 * sigma) / omjm1;

        double pj2 = get_biased_element(dists[n], omj * sigma);
        double pjm12 = get_biased_element(dists[n], omjm1 * sigma);

        cumul += (pj + pjm1) / 2.0 * dom;
        cumul2 += (pj2 + pjm12) / 2.0 * dom;
      }
    }

    omegas.push_back(cumul2 / cumul);
  }
  return omegas;
}
Ejemplo n.º 18
0
Floats ChainStatisticsOptimizerState::get_diffusion_coefficients() const {
  if (positions_.empty()) return Floats();
  base::Vector<algebra::Vector3Ds >
    displacements(positions_[0].size(),
                  algebra::Vector3Ds( positions_.size()-1));
  for (unsigned int i=1; i< positions_.size(); ++i) {
    algebra::Transformation3D rel
        = algebra::get_transformation_aligning_first_to_second(positions_[i-1],
                                                               positions_[i]);
    for (unsigned int j=0; j < positions_[i].size(); ++j) {
      displacements[j][i-1]= rel.get_transformed(positions_[i-1][j])
        - positions_[i][j];
    }
  }
  Floats ret;
  for (unsigned int i=0; i < displacements.size(); ++i) {
    ret.push_back(atom::get_diffusion_coefficient(displacements[i],
                                                  get_period()*get_dt()));
  }
  return ret;
}
Ejemplo n.º 19
0
/* Apply the restraint to two atoms, two Scales, one experimental value.
 */
double
AmbiguousNOERestraint::unprotected_evaluate(DerivativeAccumulator *accum) const
{
  IMP_OBJECT_LOG;
  IMP_USAGE_CHECK(get_model(),
                  "You must at least register the restraint with the model"
                  << " before calling evaluate.");

  /* compute Icalc = 1/(gamma*d^6) where d = (sum d_i^-6)^(-1/6) */
  double vol = 0;
  Floats vols;
  IMP_CONTAINER_FOREACH(PairContainer, pc_,
                        {
            core::XYZ d0(get_model(), _1[0]);
            core::XYZ d1(get_model(), _1[1]);
            algebra::Vector3D c0 = d0.get_coordinates();
            algebra::Vector3D c1 = d1.get_coordinates();
            //will raise an error if c0 == c1
            double tmp = 1.0/(c0-c1).get_squared_magnitude();
            vols.push_back(IMP::cube(tmp)); // store di^-6
            vol += vols.back();
                        });
Ejemplo n.º 20
0
CrossLinkData::CrossLinkData(Floats dist_grid, Floats omega_grid,
                             Floats sigma_grid, Floats pot_x_grid,
                             Floats pot_value_grid, double don, double doff,
                             int prior_type)
    : Object("Data Structure for CrossLinkMSRestraint %1%") {
  prior_type_ = prior_type;
  bias_ = true;
  // this constructor calculates the marginal likelihood using a biasing
  // potential
  // obtained from Free energy calculations.

  // Store dist grid
  dist_grid_ = dist_grid;

  // Store omega grid
  omega_grid_ = omega_grid;

  // Store sigma grid
  sigma_grid_ = sigma_grid;

  // Store the potential x coordinates
  pot_x_grid_ = pot_x_grid;

  // Store the normalized potential
  double cumul = 0;
  for (unsigned j = 1; j < pot_value_grid.size(); ++j) {
    double xj = pot_x_grid_[j];
    double xjm1 = pot_x_grid_[j - 1];
    double dx = xj - xjm1;
    double pj = pot_value_grid[j];
    double pjm1 = pot_value_grid[j - 1];
    cumul += (pj + pjm1) / 2.0 * dx;
  }

  for (unsigned i = 0; i < pot_value_grid.size(); ++i) {
    pot_value_grid_.push_back(pot_value_grid[i] / cumul);
  }

  for (unsigned k = 0; k < sigma_grid_.size(); ++k) {

    double sigma = sigma_grid_[k];

    Floats grid;

    for (unsigned i = 0; i < dist_grid_.size(); ++i) {

      double dist = dist_grid_[i];
      double cumul = 0;

      for (unsigned j = 1; j < omega_grid_.size(); ++j) {

        double omj = omega_grid_[j];
        double omjm1 = omega_grid_[j - 1];

        double dom = omj - omjm1;

        double pj;
        double pjm1;

        if (prior_type_ == 0) {
          pj = get_biased_element(dist, omj * sigma) / omj;
          pjm1 = get_biased_element(dist, omjm1 * sigma) / omjm1;
        } else {
          pj = get_biased_element(dist, omj) * get_omega_prior(omj, sigma);
          pjm1 =
              get_biased_element(dist, omjm1) * get_omega_prior(omjm1, sigma);
        }
        cumul += (pj + pjm1) / 2.0 * dom;
      }

      // switching cumul to zero between don and doff
      if (dist > doff) {
        cumul = 0.;
      }
      if (dist > don && dist <= doff) {
        cumul *= pow(doff * doff - dist * dist, 2) *
                 (doff * doff + 2. * dist * dist - 3. * don * don) /
                 pow(doff * doff - don * don, 3);
      }
      grid.push_back(cumul);
    }
    grid_.push_back(grid);
  }
}
Ejemplo n.º 21
0
IMPISD_BEGIN_NAMESPACE

CrossLinkData::CrossLinkData(Floats dist_grid, Floats omega_grid,
                             Floats sigma_grid, double lexp, double don,
                             double doff, int prior_type)
    : Object("Data Structure for CrossLinkMSRestraint %1%") {
  prior_type_ = prior_type;
  lexp_ = lexp;
  bias_ = false;
  // this constructor calculates the marginal likelihood using a theta function
  // to approximate the propensity of the linker

  // Store dist grid
  dist_grid_ = dist_grid;

  // Store omega grid
  omega_grid_ = omega_grid;

  // Store sigma grid
  sigma_grid_ = sigma_grid;

  for (unsigned k = 0; k < sigma_grid_.size(); ++k) {

    double sigma = sigma_grid_[k];

    Floats grid;

    for (unsigned i = 0; i < dist_grid_.size(); ++i) {

      double dist = dist_grid_[i];
      double cumul = 0;

      for (unsigned j = 1; j < omega_grid_.size(); ++j) {

        double omj = omega_grid_[j];
        double omjm1 = omega_grid_[j - 1];

        double dom = omj - omjm1;

        double pj;
        double pjm1;

        if (prior_type_ == 0) {
          pj = get_biased_element(dist, omj * sigma) / omj;
          pjm1 = get_biased_element(dist, omjm1 * sigma) / omjm1;
        } else {
          pj = get_biased_element(dist, omj) * get_omega_prior(omj, sigma);
          pjm1 =
              get_biased_element(dist, omjm1) * get_omega_prior(omjm1, sigma);
        }
        cumul += (pj + pjm1) / 2.0 * dom;
      }

      // switching cumul to zero between don and doff
      if (dist > doff) {
        cumul = 0.;
      }
      if (dist > don && dist <= doff) {
        cumul *= pow(doff * doff - dist * dist, 2) *
                 (doff * doff + 2. * dist * dist - 3. * don * don) /
                 pow(doff * doff - don * don, 3);
      }

      grid.push_back(cumul);
    }
    grid_.push_back(grid);
  }
}
Ejemplo n.º 22
0
IMPCNMULTIFIT_BEGIN_NAMESPACE

Floats get_rmsd_for_models(const std::string param_filename,
                           const std::string trans_filename,
                           const std::string ref_filename, int start_model,
                           int end_model) {
  std::string protein_filename, surface_filename;
  int cn_symm_deg;

  std::cout << "============= parameters ============" << std::endl;
  std::cout << "params filename : " << param_filename << std::endl;
  std::cout << "trans filename : " << trans_filename << std::endl;
  std::cout << "ref filename : " << ref_filename << std::endl;
  std::cout << "start index to rmsd : " << start_model << std::endl;
  std::cout << "end index to rmsd : " << end_model << std::endl;
  std::cout << "=====================================" << std::endl;

  internal::Parameters params(param_filename.c_str());
  protein_filename = params.get_unit_pdb_fn();
  cn_symm_deg = params.get_cn_symm();

  IMP_NEW(Model, mdl, ());
  atom::Hierarchy asmb_ref;
  atom::Hierarchies mhs;
  // read the monomer
  core::XYZs model_xyzs;
  for (int i = 0; i < cn_symm_deg; i++) {
    atom::Hierarchy h =
        atom::read_pdb(protein_filename, mdl, new atom::CAlphaPDBSelector());
    atom::Chain c = atom::get_chain(
        atom::Residue(atom::get_residue(atom::Atom(core::get_leaves(h)[0]))));
    c.set_id(std::string(1, char(65 + i)));
    atom::add_radii(h);
    atom::create_rigid_body(h);
    mhs.push_back(h);
    Particles leaves = core::get_leaves(h);
    for (Particles::iterator it = leaves.begin(); it != leaves.end();
         it++) {
      model_xyzs.push_back(core::XYZ(*it));
    }
  }
  // read the transformations
  multifit::FittingSolutionRecords recs =
      multifit::read_fitting_solutions(trans_filename.c_str());
  // read the reference structure
  asmb_ref = atom::read_pdb(ref_filename, mdl, new atom::CAlphaPDBSelector());
  atom::Hierarchies ref_chains =
      atom::Hierarchies(atom::get_by_type(asmb_ref, atom::CHAIN_TYPE));
  std::cout << "number of records:" << recs.size() << std::endl;
  Floats rmsd;
  std::ofstream out;
  out.open("rmsd.output");
  if (end_model < 0 || end_model >= static_cast<int>(recs.size())) {
    end_model = recs.size() - 1;
  }

  for (int i = start_model; i >= 0 && i <= end_model; ++i) {
    algebra::Transformation3D t1 = recs[i].get_dock_transformation();
    algebra::Transformation3D t2 = recs[i].get_fit_transformation();
    algebra::Transformation3D t2_inv = t1.get_inverse();
    transform_cn_assembly(mhs, t1);
    for (unsigned int j = 0; j < model_xyzs.size(); j++) {
      model_xyzs[j]
          .set_coordinates(t2.get_transformed(model_xyzs[j].get_coordinates()));
    }
    std::cout << mhs.size() << "," << ref_chains.size() << std::endl;
    Float cn_rmsd = get_cn_rmsd(mhs, ref_chains);
    out << " trans:" << i << " rmsd: " << cn_rmsd
        << " cc: " << 1. - recs[i].get_fitting_score() << std::endl;
    rmsd.push_back(cn_rmsd);
    for (unsigned int j = 0; j < model_xyzs.size(); j++) {
      model_xyzs[j].set_coordinates(
          t2_inv.get_transformed(model_xyzs[j].get_coordinates()));
    }
    /*      std::stringstream ss;
    ss<<"asmb_"<<i<<".pdb";
    atom::write_pdb(mhs,ss.str());*/
    transform_cn_assembly(mhs, t1.get_inverse());
  }

  out.close();
  return rmsd;
}
Floats GaussianProcessInterpolation::get_data_mean() const {
  Floats ret;
  IMP_Eigen::VectorXd I(get_I());
  for (unsigned i = 0; i < M_; i++) ret.push_back(I(i));
  return ret;
}
IMP_Eigen::MatrixXd
GaussianProcessInterpolation::get_posterior_covariance_hessian(Floats x) const {
  const_cast<GaussianProcessInterpolation *>(this)->update_flags_covariance();
  // get how many and which particles are optimized
  unsigned mnum = get_number_of_m_particles();
  std::vector<bool> mopt;
  unsigned mnum_opt = 0;
  for (unsigned i = 0; i < mnum; i++) {
    mopt.push_back(get_m_particle_is_optimized(i));
    if (mopt.back()) mnum_opt++;
  }
  unsigned Onum = get_number_of_Omega_particles();
  std::vector<bool> Oopt;
  unsigned Onum_opt = 0;
  for (unsigned i = 0; i < Onum; i++) {
    Oopt.push_back(get_Omega_particle_is_optimized(i));
    if (Oopt.back()) Onum_opt++;
  }
  // total number of optimized particles
  unsigned num_opt = mnum_opt + Onum_opt;
  // whether sigma is optimized
  unsigned sigma_opt = Oopt[0] ? 1 : 0;
  // cov_opt: number of optimized covariance particles without counting sigma
  unsigned cov_opt = Onum_opt - sigma_opt;

  // init matrix and fill with zeros at mean particle's indices
  // dprior_cov(q,q)/(dsigma d.) is also zero
  IMP_Eigen::MatrixXd ret(IMP_Eigen::MatrixXd::Zero(num_opt, num_opt));
  // build vector of dcov(q,q)/dp1dp2 with p1 and p2 covariance particles
  FloatsList xv;
  xv.push_back(x);
  FloatsList tmplist;
  for (unsigned pa = 0; pa < Onum; ++pa) {
    if (!Oopt[pa]) continue;  // skip not optimized particles
    if (pa == 0) continue;    // skip sigma even when it is optimized
    Floats tmp;
    for (unsigned pb = pa; pb < Onum; ++pb) {
      if (!Oopt[pb]) continue;  // skip not optimized particles
      // sigma has already been skipped
      tmp.push_back(covariance_function_->get_second_derivative_matrix(
          pa - 1, pb - 1, xv)(0, 0));
    }
    tmplist.push_back(tmp);
  }
  for (unsigned pa_opt = 0; pa_opt < cov_opt; pa_opt++)
    for (unsigned pb_opt = pa_opt; pb_opt < cov_opt; pb_opt++)
      ret.bottomRightCorner(cov_opt, cov_opt)(pa_opt, pb_opt) =
          tmplist[pa_opt][pb_opt - pa_opt];

  // compute and store w(q) derivatives (skip mean particles)
  IMP_Eigen::MatrixXd dwqdp(M_, Onum_opt);
  for (unsigned i = 0, j = 0; i < Onum; i++)
    if (Oopt[i]) dwqdp.col(j++) = get_wx_vector_derivative(x, i + mnum);
  // add d2cov/(dw(q)_k * dw(q)_l) * dw(q)^k/dp_i * dw(q)^l/dp_j
  ret.bottomRightCorner(cov_opt, cov_opt).noalias() +=
      dwqdp.rightCols(cov_opt).transpose() * get_d2cov_dwq_dwq() *
      dwqdp.rightCols(cov_opt);

  // compute and store Omega derivatives (skip mean particles)
  std::vector<IMP_Eigen::MatrixXd> dOmdp;
  for (unsigned i = 0; i < Onum; i++) {
    if (Oopt[i]) dOmdp.push_back(get_Omega_derivative(i));
  }
  // add d2cov/(dOm_kl * dOm_mn) * dOm^kl/dp_i * dOm^mn/dp_j
  std::vector<std::vector<IMP_Eigen::MatrixXd> > d2covdo;
  for (unsigned m = 0; m < M_; m++) {
    std::vector<IMP_Eigen::MatrixXd> tmp;
    for (unsigned n = 0; n < M_; n++) tmp.push_back(get_d2cov_dOm_dOm(x, m, n));
    d2covdo.push_back(tmp);
  }

  for (unsigned i = 0; i < Onum_opt; i++) {
    IMP_Eigen::MatrixXd tmp(M_, M_);
    for (unsigned m = 0; m < M_; ++m)
      for (unsigned n = 0; n < M_; ++n)
        tmp(m, n) = (d2covdo[m][n].transpose() * dOmdp[i]).trace();
    for (unsigned j = i; j < Onum_opt; j++)
      ret.bottomRightCorner(Onum_opt, Onum_opt)(i, j) +=
          (dOmdp[j].transpose() * tmp).trace();
  }
  for (unsigned i = 0; i < d2covdo.size(); i++) d2covdo[i].clear();
  d2covdo.clear();

  // compute cross-term
  std::vector<IMP_Eigen::MatrixXd> d2covdwdo;
  for (unsigned k = 0; k < M_; k++)
    d2covdwdo.push_back(get_d2cov_dwq_dOm(x, k));
  // compute derivative contribution into temporary
  IMP_Eigen::MatrixXd tmpH(Onum_opt, Onum_opt);

  for (unsigned i = 0; i < Onum_opt; i++) {
    IMP_Eigen::VectorXd tmp(M_);
    for (unsigned k = 0; k < M_; k++)
      tmp(k) = (d2covdwdo[k].transpose() * dOmdp[i]).trace();
    for (unsigned j = 0; j < Onum_opt; j++)
      tmpH(i, j) = dwqdp.col(j).transpose() * tmp;
  }
  ret.bottomRightCorner(Onum_opt, Onum_opt) += tmpH + tmpH.transpose();

  // deallocate unused stuff
  // tmpH.resize(0,0);
  d2covdwdo.clear();
  dOmdp.clear();
  // dwqdp.resize(0,0);

  // dcov/dw_k * d2w^k/(dp_i dp_j)
  IMP_Eigen::VectorXd dcwq(get_dcov_dwq(x));
  for (unsigned i = 0; i < cov_opt; i++)
    for (unsigned j = i; j < cov_opt; j++)
      ret.bottomRightCorner(cov_opt, cov_opt)(i, j) +=
          dcwq.transpose() *
          get_wx_vector_second_derivative(x, mnum + 1 + i, mnum + 1 + j);
  // dcwq.resize(0,0);

  // dcov/dOm_kl * d2Om^kl/(dp_i dp_j), zero when p_i or p_j is sigma or mean
  IMP_Eigen::MatrixXd dcOm(get_dcov_dOm(x));
  for (unsigned i = 0; i < cov_opt; i++)
    for (unsigned j = i; j < cov_opt; j++)
      ret.bottomRightCorner(cov_opt, cov_opt)(i, j) +=
          (dcOm.transpose() * get_Omega_second_derivative(i + 1, j + 1))
              .trace();
  // dcOm.resize(0,0);

  // return as symmetric matrix
  for (unsigned i = mnum_opt; i < num_opt; ++i)
    for (unsigned j = mnum_opt + 1; j < num_opt; ++j) ret(j, i) = ret(i, j);

  return ret;
}