Gaia / include /gcmc /ncmc.hpp
ObviousSatire
Add C++ source code and build system
be3cca2
Raw
History Blame Contribute Delete
3.05 kB
#ifndef GAIA_GCMC_NCMC_HPP
#define GAIA_GCMC_NCMC_HPP
#include <vector>
#include <cmath>
#include <random>
namespace gaia {
namespace gcmc {
struct Vec3 {
double x, y, z;
Vec3(double x=0, double y=0, double z=0) : x(x), y(y), z(z) {}
};
struct Water {
Vec3 O, H1, H2;
double lambda;
Water(Vec3 pos, double l=0.0) : lambda(l) {
double bond = 0.9572;
double angle = 104.52 * 3.14159 / 180.0;
O = pos;
H1 = Vec3(pos.x + bond * cos(angle/2), pos.y + bond * sin(angle/2), pos.z);
H2 = Vec3(pos.x + bond * cos(-angle/2), pos.y + bond * sin(-angle/2), pos.z);
}
void set_lambda(double l) { lambda = l; }
};
class NCMCWater {
public:
NCMCWater(int n_steps=20, double overlap=2.0) : n_steps(n_steps), overlap(overlap) {}
bool insert(const std::vector<Vec3>& protein, const std::vector<Water>& waters,
const Vec3& pos, double kT) {
const double mu = -6.09;
for (const auto& w : waters) {
double dx = pos.x - w.O.x, dy = pos.y - w.O.y, dz = pos.z - w.O.z;
if (dx*dx + dy*dy + dz*dz < overlap*overlap) return false;
}
for (const auto& atom : protein) {
double dx = pos.x - atom.x, dy = pos.y - atom.y, dz = pos.z - atom.z;
if (dx*dx + dy*dy + dz*dz < 1.0) return false;
}
Water water(pos, 0.0);
double U_init = compute_potential(protein, waters, water);
double work = 0.0;
for (int s = 0; s < n_steps; s++) {
double lambda = (s + 1.0) / n_steps;
water.set_lambda(lambda);
double U_cur = compute_potential(protein, waters, water);
work += U_cur - U_init;
U_init = U_cur;
}
double delta = work - mu;
if (delta < 0 || exp(-delta / kT) > uniform_random()) return true;
return false;
}
private:
double compute_potential(const std::vector<Vec3>& protein,
const std::vector<Water>& waters,
const Water& water) {
double U = 0.0;
for (const auto& atom : protein) {
double dx = water.O.x - atom.x, dy = water.O.y - atom.y, dz = water.O.z - atom.z;
double r2 = dx*dx + dy*dy + dz*dz;
if (r2 < 0.01) continue;
double r6 = r2 * r2 * r2;
U += 4.0 * 0.1 * (1.0/(r6*r6) - 1.0/r6) * water.lambda;
}
for (const auto& atom : protein) {
double dx = water.O.x - atom.x, dy = water.O.y - atom.y, dz = water.O.z - atom.z;
double r = sqrt(dx*dx + dy*dy + dz*dz);
if (r < 0.01) continue;
U += 332.0 * (-0.82) / r * water.lambda;
}
return U;
}
double uniform_random() {
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_real_distribution<double> dist(0.0, 1.0);
return dist(gen);
}
int n_steps;
double overlap;
};
} // namespace gcmc
} // namespace gaia
#endif