diff --git a/CMakeLists.txt b/CMakeLists.txt index f975206..9a97337 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,6 +176,7 @@ set(curcuma_core_SRC add_executable(curcuma src/main.cpp + src/core/forcefieldgenerator.h src/core/forcefieldgenerator.cpp ) diff --git a/src/core/eigen_uff.cpp b/src/core/eigen_uff.cpp index c051874..f06dfc0 100644 --- a/src/core/eigen_uff.cpp +++ b/src/core/eigen_uff.cpp @@ -84,7 +84,7 @@ double UFFThread::Distance(double x1, double x2, double y1, double y2, double z1 double UFFThread::BondEnergy(double distance, double r, double kij, double D_ij) { - double energy = (0.25 * kij * (distance - r) * (distance - r)) * m_final_factor * m_bond_scaling; + double energy = (0.5 * kij * (distance - r) * (distance - r)) * m_final_factor * m_bond_scaling; if (isnan(energy)) return 0; else @@ -106,7 +106,7 @@ double UFFThread::CalculateBondStretching() Matrix derivate; double r0 = BondStretching(x, y, derivate, m_CalculateGradient); - energy += (0.25 * bond.kij * (r0 - bond.r0) * (r0 - bond.r0)) * m_final_factor * m_bond_scaling; + energy += (0.5 * bond.kij * (r0 - bond.r0) * (r0 - bond.r0)) * m_final_factor * m_bond_scaling; if (m_CalculateGradient) { if (m_calc_gradient == 0) { double diff = (bond.kij) * (r0 - bond.r0) * m_final_factor * m_bond_scaling; @@ -167,7 +167,7 @@ double UFFThread::CalculateAngleBending() Matrix derivate; double costheta = AngleBending(atom_i, atom_j, atom_k, derivate, m_CalculateGradient); double e = (angle.kijk * (angle.C0 + angle.C1 * costheta + angle.C2 * (2 * costheta * costheta - 1))) * m_final_factor * m_angle_scaling; - + energy += e; if (m_CalculateGradient) { if (m_calc_gradient == 0) { double sintheta = sin(acos(costheta)); @@ -396,7 +396,6 @@ double UFFThread::FullInversion(const int& i, const int& j, const int& k, const Eigen::Vector3d atom_j = Position(j); Eigen::Vector3d atom_k = Position(k); Eigen::Vector3d atom_l = Position(l); - energy += Inversion(atom_i, atom_j, atom_k, atom_l, d_forceConstant, C0, C1, C2); if (m_CalculateGradient) { if (m_calc_gradient == 0) { diff --git a/src/core/energycalculator.cpp b/src/core/energycalculator.cpp index 6a2e73c..20a8b96 100644 --- a/src/core/energycalculator.cpp +++ b/src/core/energycalculator.cpp @@ -232,7 +232,10 @@ void EnergyCalculator::setMolecule(const Molecule& molecule) ff.setMolecule(molecule); ff.Generate(); json parameters = ff.getParameter(); + // std::ofstream parameterfile("uff.json"); + // parameterfile << parameters; m_forcefield->setParameter(parameters); + m_forcefield->setAtomCount(molecule.AtomCount()); // m_forcefield->setMolecule(atoms, geom); // m_forcefield->Initialise(); @@ -396,6 +399,7 @@ void EnergyCalculator::CalculateFF(bool gradient, bool verbose) m_energy = m_forcefield->Calculate(gradient, verbose); if (gradient) { m_gradient = m_forcefield->Gradient(); + // m_gradient = m_forcefield->NumGrad(); } } diff --git a/src/core/forcefield.cpp b/src/core/forcefield.cpp index 98ee264..27be36a 100644 --- a/src/core/forcefield.cpp +++ b/src/core/forcefield.cpp @@ -30,6 +30,7 @@ ForceField::ForceField(const json& controller) { m_threadpool = new CxxThreadPool(); m_threadpool->setProgressBar(CxxThreadPool::ProgressBarType::None); + m_threads = 16; } void ForceField::UpdateGeometry(const Matrix& geometry) @@ -194,6 +195,29 @@ void ForceField::AutoRanges() thread->addEQ(m_EQs[j]); } } + +Eigen::MatrixXd ForceField::NumGrad() +{ + Eigen::MatrixXd gradient = Eigen::MatrixXd::Zero(m_natoms, 3); + + double dx = 1e-6; // m_d; + // bool g = m_CalculateGradient; + // m_CalculateGradient = false; + double E1, E2; + for (int i = 0; i < m_natoms; ++i) { + for (int j = 0; j < 3; ++j) { + m_geometry(i, j) += dx; + E1 = Calculate(false, false); + m_geometry(i, j) -= 2 * dx; + E2 = Calculate(false, false); + gradient(i, j) = (E1 - E2) / (2 * dx); + m_geometry(i, j) += dx; + } + } + // m_CalculateGradient = g; + return gradient; +} + double ForceField::Calculate(bool gradient, bool verbose) { m_gradient = Eigen::MatrixXd::Zero(m_geometry.rows(), 3); @@ -225,19 +249,19 @@ double ForceField::Calculate(bool gradient, bool verbose) inversion_energy += m_stored_threads[i]->InversionEnergy(); vdw_energy += m_stored_threads[i]->VdWEnergy(); rep_energy += m_stored_threads[i]->RepEnergy(); - eq_energy += m_stored_threads[i]->RepEnergy(); + // eq_energy += m_stored_threads[i]->RepEnergy(); m_gradient += m_stored_threads[i]->Gradient(); } - energy = bond_energy + angle_energy + dihedral_energy + inversion_energy + vdw_energy; + energy = bond_energy + angle_energy + dihedral_energy + inversion_energy + vdw_energy + rep_energy + eq_energy; if (verbose) { std::cout << "Total energy " << energy << " Eh. Sum of " << std::endl << "Bond Energy " << bond_energy << " Eh" << std::endl << "Angle Energy " << angle_energy << " Eh" << std::endl << "Dihedral Energy " << dihedral_energy << " Eh" << std::endl << "Inversion Energy " << inversion_energy << " Eh" << std::endl - << "Nonbonded Energy " << vdw_energy << " Eh" << std::endl + << "Nonbonded Energy " << vdw_energy + rep_energy << " Eh" << std::endl << "D3 Energy " << d3_energy << " Eh" << std::endl << "D4 Energy " << d4_energy << " Eh" << std::endl << "HBondCorrection " << h4_energy << " Eh" << std::endl diff --git a/src/core/forcefield.h b/src/core/forcefield.h index 9059643..7818ccc 100644 --- a/src/core/forcefield.h +++ b/src/core/forcefield.h @@ -53,6 +53,7 @@ class ForceField { ForceField(const json& controller); ~ForceField(); + inline void setAtomCount(int atom) { m_natoms = atom; } void UpdateGeometry(const Matrix& geometry); inline void UpdateGeometry(const double* coord); inline void UpdateGeometry(const std::vector>& geometry); @@ -63,6 +64,7 @@ class ForceField { void setParameter(const json& parameter); void setParameterFile(const std::string& file); + Eigen::MatrixXd NumGrad(); private: void AutoRanges(); diff --git a/src/core/forcefieldfunctions.h b/src/core/forcefieldfunctions.h index 24f2689..342145d 100644 --- a/src/core/forcefieldfunctions.h +++ b/src/core/forcefieldfunctions.h @@ -19,6 +19,7 @@ #pragma once +#include "src/core/global.h" #include "src/core/qmdff_par.h" #include "src/core/uff_par.h" @@ -69,7 +70,7 @@ inline Eigen::Vector3d NormalVector(const Eigen::Vector3d& i, const Eigen::Vecto { return (j - i).cross(j - k); } -/* + inline double Dihedral(const Eigen::Vector3d& i, const Eigen::Vector3d& j, const Eigen::Vector3d& k, const Eigen::Vector3d& l, double V, double n, double phi0) { Eigen::Vector3d nijk = NormalVector(i, j, k); @@ -80,12 +81,12 @@ inline double Dihedral(const Eigen::Vector3d& i, const Eigen::Vector3d& j, const Eigen::Vector3d ji = j - i; double sign = (-1 * ji).dot(njkl) < 0 ? -1 : 1; double phi = pi + sign * acos(dotpr / (n_ijk * n_jkl)); - double energy = (1 / 2.0 * V * (1 - cos(n * phi0) * cos(n * phi))) * m_final_factor * m_dihedral_scaling; - if (isnan(energy)) + double energy = (1 / 2.0 * V * (1 - cos(n * phi0) * cos(n * phi))); + if (std::isnan(energy)) return 0; else return energy; -} */ +} } namespace QMDFF { diff --git a/src/core/forcefieldgenerator.cpp b/src/core/forcefieldgenerator.cpp index 6d7c86f..2169ca6 100644 --- a/src/core/forcefieldgenerator.cpp +++ b/src/core/forcefieldgenerator.cpp @@ -99,7 +99,7 @@ void ForceFieldGenerator::Generate(const std::vector>& forme } AssignUffAtomTypes(); // if (m_rings) - m_identified_rings = Topology::FindRings(m_stored_bonds, m_atom_types.size()); + // m_identified_rings = Topology::FindRings(m_stored_bonds, m_atom_types.size()); setBonds(bonds); @@ -143,7 +143,7 @@ void ForceFieldGenerator::setBonds(const TContainer& bonds) else bond_order = 1; double r0_ij = UFFBondRestLength(bond[0], bond[1], bond_order); - uffbond["r_ij"] = r0_ij; + uffbond["r0_ij"] = r0_ij; double cZi = UFFParameters[m_atom_types[bond[0]]][cZ]; double cZj = UFFParameters[m_atom_types[bond[1]]][cZ]; uffbond["fc"] = 0.5 * m_uff_bond_force * cZi * cZj / (r0_ij * r0_ij * r0_ij); @@ -160,8 +160,8 @@ void ForceFieldGenerator::setBonds(const TContainer& bonds) if (t == j) continue; json uffangle = AngleJson; - uffangle["i"] = i; - uffangle["j"] = std::min(t, j); + uffangle["j"] = i; + uffangle["i"] = std::min(t, j); uffangle["k"] = std::max(j, t); // angels.insert({ std::min(t, j), i, std::max(j, t) }); @@ -177,9 +177,9 @@ void ForceFieldGenerator::setBonds(const TContainer& bonds) if (t == i) continue; json uffangle = AngleJson; - uffangle["i"] = i; - uffangle["j"] = std::min(t, j); - uffangle["k"] = std::max(j, t); + uffangle["j"] = j; + uffangle["i"] = std::min(t, i); + uffangle["k"] = std::max(i, t); if (std::find(m_angles.begin(), m_angles.end(), uffangle) == m_angles.end()) m_angles.push_back(uffangle); @@ -192,9 +192,9 @@ void ForceFieldGenerator::setBonds(const TContainer& bonds) if (k == i || k == j || k == l || i == j || i == l || j == l) continue; json uffdihedral = DihedralJson; - uffdihedral["i"] = i; - uffdihedral["j"] = j; - uffdihedral["k"] = k; + uffdihedral["i"] = k; + uffdihedral["j"] = i; + uffdihedral["k"] = j; uffdihedral["l"] = l; if (std::find(m_dihedrals.begin(), m_dihedrals.end(), uffdihedral) == m_dihedrals.end()) { m_dihedrals.push_back(uffdihedral); @@ -340,16 +340,16 @@ void ForceFieldGenerator::setInversions() double C2 = 0.0; double f = pi / 180.0; double kijkl = 0; - if (6 <= m_atom_types[i] && m_atom_types[i] <= 8) { + if (6 <= m_molecule.Atoms()[i] && m_molecule.Atoms()[i] <= 8) { C0 = 1.0; C1 = -1.0; C2 = 0.0; kijkl = 6; - if (m_atom_types[j] == 8 || m_atom_types[k] == 8 || m_atom_types[l] == 8) + if (m_molecule.Atoms()[j] == 8 || m_molecule.Atoms()[k] == 8 || m_molecule.Atoms()[l] == 8) kijkl = 50; } else { double w0 = pi / 180.0; - switch (m_atom_types[i]) { + switch (m_molecule.Atoms()[i]) { // if the central atom is phosphorous case 15: w0 *= 84.4339; @@ -701,9 +701,13 @@ void ForceFieldGenerator::writeUFFFile(const std::string& file) const json ForceFieldGenerator::Bonds() const { json bonds; + int index = 0; + for (int i = 0; i < m_bonds.size(); ++i) { - if (m_bonds[i]["type"] != 0) - bonds[i] = m_bonds[i]; + if (m_bonds[i]["type"] != 0) { + bonds[index] = m_bonds[i]; + index++; + } } return bonds; } @@ -711,10 +715,13 @@ json ForceFieldGenerator::Bonds() const json ForceFieldGenerator::Angles() const { json angles; + int index = 0; for (int i = 0; i < m_angles.size(); ++i) { - if (m_angles[i]["type"] != 0) - angles[i] = m_angles[i]; + if (m_angles[i]["type"] != 0) { + angles[index] = m_angles[i]; + index++; + } } return angles; } @@ -722,9 +729,13 @@ json ForceFieldGenerator::Angles() const json ForceFieldGenerator::Dihedrals() const { json dihedrals; + int index = 0; + for (int i = 0; i < m_dihedrals.size(); ++i) { - if (m_dihedrals[i]["type"] != 0) - dihedrals[i] = m_dihedrals[i]; + if (m_dihedrals[i]["type"] != 0) { + dihedrals[index] = m_dihedrals[i]; + index++; + } } return dihedrals; } @@ -732,9 +743,12 @@ json ForceFieldGenerator::Dihedrals() const json ForceFieldGenerator::Inversions() const { json inversions; + int index = 0; for (int i = 0; i < m_inversions.size(); ++i) { - if (m_inversions[i]["type"] != 0) - inversions[i] = m_inversions[i]; + if (m_inversions[i]["type"] != 0 && m_inversions[i]["fc"] != 0) { + inversions[index] = m_inversions[i]; + index++; + } } return inversions; } @@ -742,9 +756,13 @@ json ForceFieldGenerator::Inversions() const json ForceFieldGenerator::vdWs() const { json vdws; + int index = 0; + for (int i = 0; i < m_vdws.size(); ++i) { - if (m_vdws[i]["type"] != 0) - vdws[i] = m_vdws[i]; + if (m_vdws[i]["type"] != 0) { + vdws[index] = m_vdws[i]; + index++; + } } return vdws; } diff --git a/src/core/forcefieldgenerator.h b/src/core/forcefieldgenerator.h index a2a995c..bb58980 100644 --- a/src/core/forcefieldgenerator.h +++ b/src/core/forcefieldgenerator.h @@ -133,7 +133,7 @@ class ForceFieldGenerator { std::vector m_atom_types, m_coordination; std::vector> m_ignored_vdw; std::vector m_bonds, m_angles, m_dihedrals, m_inversions, m_vdws, m_eqs; - double m_uff_bond_force = 1, m_uff_angle_force = 1, m_scaling = 1.4; + double m_uff_bond_force = 664.12, m_uff_angle_force = 664.12, m_scaling = 1.4; double m_au = 1; int m_ff_type = 1; diff --git a/src/core/forcefieldthread.cpp b/src/core/forcefieldthread.cpp index f0d8103..2331ae0 100644 --- a/src/core/forcefieldthread.cpp +++ b/src/core/forcefieldthread.cpp @@ -135,15 +135,13 @@ void ForceFieldThread::CalculateUFFAngleContribution() Matrix derivate; double costheta = UFF::AngleBending(i, j, k, derivate, m_calculate_gradient); m_angle_energy += (angle.fc * (angle.C0 + angle.C1 * costheta + angle.C2 * (2 * costheta * costheta - 1))) * m_final_factor * m_angle_scaling; - + // std::cout << (angle.fc * (angle.C0 + angle.C1 * costheta + angle.C2 * (2 * costheta * costheta - 1))) * m_final_factor * m_angle_scaling << " "; if (m_calculate_gradient) { - if (m_calc_gradient == 0) { - double sintheta = sin(acos(costheta)); - double dEdtheta = -angle.fc * sintheta * (angle.C1 + 4 * angle.C2 * costheta) * m_final_factor * m_angle_scaling; - m_gradient.row(angle.i) += dEdtheta * derivate.row(0); - m_gradient.row(angle.j) += dEdtheta * derivate.row(1); - m_gradient.row(angle.k) += dEdtheta * derivate.row(2); - } + double sintheta = sin(acos(costheta)); + double dEdtheta = -angle.fc * sintheta * (angle.C1 + 4 * angle.C2 * costheta) * m_final_factor * m_angle_scaling; + m_gradient.row(angle.i) += dEdtheta * derivate.row(0); + m_gradient.row(angle.j) += dEdtheta * derivate.row(1); + m_gradient.row(angle.k) += dEdtheta * derivate.row(2); } } } @@ -159,7 +157,9 @@ void ForceFieldThread::CalculateUFFDihedralContribution() Eigen::Vector3d eins = { 1.0, 1.0, 1.0 }; Eigen::Vector3d nijk = UFF::NormalVector(i, j, k); Eigen::Vector3d njkl = UFF::NormalVector(j, k, l); - + Eigen::Vector3d dx = { m_d, 0, 0 }; + Eigen::Vector3d dy = { 0, m_d, 0 }; + Eigen::Vector3d dz = { 0, 0, m_d }; double n_ijk = (nijk).norm(); double n_jkl = (njkl).norm(); double dotpr = nijk.dot(njkl); @@ -168,16 +168,18 @@ void ForceFieldThread::CalculateUFFDihedralContribution() double sign = (-1 * ji).dot(njkl) < 0 ? -1 : 1; double phi = pi + sign * acos(dotpr / (n_ijk * n_jkl)); double sinphi = sin(phi); - double tmp_energy = (1 / 2.0 * dihedral.V * (1 - cos(dihedral.n * dihedral.phi0) * cos(dihedral.n * dihedral.phi0))) * m_final_factor * m_dihedral_scaling; - // Dihedral(i, j, k, l, dihedral.V, dihedral.n, dihedral.phi0) * m_final_factor * m_dihedral_scaling; + double tmp_energy = (1 / 2.0 * dihedral.V * (1 - cos(dihedral.n * dihedral.phi0) * cos(dihedral.n * phi))) * m_final_factor * m_dihedral_scaling; + // std::cout << tmp_energy << ": "; + // m_dihedral_energy +=UFF::Dihedral(i, j, k, l, dihedral.V, dihedral.n, dihedral.phi0) * m_final_factor * m_dihedral_scaling; if (isnan(tmp_energy)) continue; m_dihedral_energy += tmp_energy; if (m_calculate_gradient) { + Eigen::Vector3d kj = k - j; Eigen::Vector3d kl = k - l; double tmp = 0; - double dEdphi = (1 / 2.0 * dihedral.V * dihedral.n * (cos(dihedral.n * dihedral.phi0) * sin(dihedral.n * phi))); + double dEdphi = (1 / 2.0 * dihedral.V * dihedral.n * (cos(dihedral.n * dihedral.phi0) * sin(dihedral.n * phi))) * m_final_factor * m_dihedral_scaling; if (isnan(dEdphi)) continue;