diff --git a/src/capabilities/optimiser/OptimiseDipoleScaling.h b/src/capabilities/optimiser/OptimiseDipoleScaling.h index a7353c5..f1cfc14 100644 --- a/src/capabilities/optimiser/OptimiseDipoleScaling.h +++ b/src/capabilities/optimiser/OptimiseDipoleScaling.h @@ -20,24 +20,15 @@ #pragma once #include -#include #include #include -#include "src/capabilities/optimiser/LevMarDocking.h" -#include "src/core/elements.h" #include "src/core/global.h" #include "src/core/molecule.h" -#include "src/core/pseudoff.h" -#include "src/tools/geometry.h" template - -// Implement argmin x: F(x) = sum_i^N (y_i - f_i(x))**2 -// f_i(x) = sum_j (x*q_j*r_j), N... number of confomere -// r_j=[ [xyz]_1, [xyz]_2, ..., [xyz]_m] m... number of atoms/parameter struct TFunctor { typedef _Scalar Scalar; enum { @@ -50,51 +41,48 @@ struct TFunctor { int m_inputs, m_values; - inline TFunctor(int inputs, int values) + TFunctor(int inputs, int values) : m_inputs(inputs) , m_values(values) - { - } + {} int inputs() const { return m_inputs; } int values() const { return m_values; } }; struct OptDipoleFunctor : TFunctor { - inline OptDipoleFunctor(int inputs, int values) + OptDipoleFunctor(int inputs, int values) : TFunctor(inputs, values) , no_parameter(inputs) - , no_points(values) - { + , no_points(values) { } - inline ~OptDipoleFunctor() = default; - inline int operator()(const Vector& scaling, Eigen::VectorXd& fvec) const - { + ~OptDipoleFunctor() = default; + int operator()(const Vector& scaling, Eigen::VectorXd& fvec) const { + // calculation of residuals for (int i = 0; i < m_conformers.size(); ++i) { - auto conf = m_conformers.at(i); - fvec(i) = (conf.getDipole() - conf.CalculateDipoleMoment(scaling)).norm(); + const auto& conf = m_conformers.at(i); + fvec(i) = conf.getDipole().norm() - conf.CalculateDipoleMoment(scaling).norm(); } - return 0; } int no_parameter; int no_points; std::vector m_conformers; + bool m_bond; int inputs() const { return no_parameter; } int values() const { return no_points; } }; -struct OptDipoleFunctorNumericalDiff : Eigen::NumericalDiff { -}; +struct OptDipoleFunctorNumericalDiff : Eigen::NumericalDiff {}; -inline Vector OptimiseDipoleScaling(const std::vector& conformers, Vector scaling) -{ +inline Vector OptimiseDipoleScaling(const std::vector& conformers, Vector scaling, const bool bond = false) { - OptDipoleFunctor functor(6, conformers.size()); + OptDipoleFunctor functor(2, conformers.size()); functor.m_conformers = conformers; - Eigen::NumericalDiff numDiff(functor); - Eigen::LevenbergMarquardt> lm(numDiff); + functor.m_bond = bond; + Eigen::NumericalDiff numDiff(functor); + Eigen::LevenbergMarquardt lm(numDiff); /* lm.parameters.factor = config["LevMar_Factor"].toInt(); //step bound for the diagonal shift, is this related to damping parameter, lambda? @@ -107,13 +95,13 @@ inline Vector OptimiseDipoleScaling(const std::vector& conformers, Vec Eigen::LevenbergMarquardtSpace::Status status = lm.minimizeInit(scaling); - int MaxIter = 3000; + constexpr int MaxIter = 3000; Vector old_param = scaling; for (int iter = 0; iter < MaxIter; ++iter) { status = lm.minimizeOneStep(scaling); - if ((old_param - scaling).norm() < 1e-5) + if ((old_param - scaling).norm() < 1e-6) break; old_param = scaling; @@ -122,36 +110,29 @@ inline Vector OptimiseDipoleScaling(const std::vector& conformers, Vec return scaling; } -inline Matrix DipoleScalingCalculation(const std::vector& conformers) +inline Vector DipoleScalingCalculation(const std::vector& conformers) { - std::vector y; - std::vector F; - auto para_size = conformers[0].AtomCount(); - auto conformer_size = conformers.size(); - Matrix FTF(para_size, para_size); - Vector FTy(para_size); - for (const auto& conformer : conformers) { - y.push_back(conformer.getDipole()); // TODO Einheit überprüfen - F.push_back(conformer.ChargeDistribution()); - } - - for (int i = 0; i < para_size; ++i) { + const auto para_size = conformers[0].AtomCount(); + const auto conformer_size = conformers.size(); + Matrix F(3*conformer_size,para_size); // Geometry multiplied with partial Charge + Matrix y(3*conformer_size,1); //Dipoles + Matrix FTF = Matrix::Zero(para_size, para_size); + Matrix FTy = Matrix::Zero(para_size, 1); + for (int i = 0; i < conformer_size; ++i) { + y(3*i,0) = conformers[i].getDipole()[0]; + y(3*i+1,0) = conformers[i].getDipole()[1]; + y(3*i+2,0) = conformers[i].getDipole()[2]; + const auto& f = conformers[i].ChargeDistribution(); for (int j = 0; j < para_size; ++j) { - for (auto& k : F) - FTF(i, j) += k(i, 0) * k(j, 0) + k(i, 1) * k(j, 1) + k(i, 2) * k(j, 2); + F(3*i,j) = f(j,0); + F(3*i+1,j) = f(j,1); + F(3*i+2,j) = f(j,2); } } - - for (int j = 0; j < para_size; ++j) { - for (int i = 0; i < conformer_size; ++i) { - FTy(j) += y[i](0) * F[i](j, 0) + y[i](1) * F[i](j, 1) + y[i](2) * F[i](j, 2); - } - } - - Matrix Theta(para_size, 1); - - Theta = FTF.inverse() * FTy; - - // inv(F.t@F)@(F.t@y); + const Vector Theta = (F.transpose()*F).colPivHouseholderQr().solve(F.transpose()*y); + //const Matrix H = (F*(F.transpose()*F).inverse()*F.transpose()).diagonal(); + //std::cout << "diag(H) x y z:" << std::endl; + //for (int i = 0; i < H.rows()/3; ++i) + // std::cout << H(3*i,0) << " " << H(3*i+1,0) << " " << H(3*i+2,0) << " " << std::endl; return Theta; } \ No newline at end of file diff --git a/src/capabilities/simplemd.cpp b/src/capabilities/simplemd.cpp index 30d15d1..f6052a3 100644 --- a/src/capabilities/simplemd.cpp +++ b/src/capabilities/simplemd.cpp @@ -68,7 +68,7 @@ BiasThread::~BiasThread() int BiasThread::execute() { - if (m_biased_structures.size() == 0) + if (m_biased_structures.empty()) return 0; m_current_bias = 0; m_counter = 0; @@ -141,7 +141,7 @@ std::vector BiasThread::getBias() const return bias; } -SimpleMD::SimpleMD(const json& controller, bool silent) +SimpleMD::SimpleMD(const json& controller, const bool silent) : CurcumaMethod(CurcumaMDJson, controller, silent) { UpdateController(controller); @@ -150,8 +150,8 @@ SimpleMD::SimpleMD(const json& controller, bool silent) SimpleMD::~SimpleMD() { - for (int i = 0; i < m_unique_structures.size(); ++i) - delete m_unique_structures[i]; + for (const auto & m_unique_structure : m_unique_structures) + delete m_unique_structure; // delete m_bias_pool; } @@ -173,10 +173,10 @@ void SimpleMD::LoadControlJson() m_print = Json2KeyWord(m_defaults, "print"); m_max_top_diff = Json2KeyWord(m_defaults, "MaxTopoDiff"); m_seed = Json2KeyWord(m_defaults, "seed"); - m_threads = Json2KeyWord(m_defaults, "threads"); + m_threads = Json2KeyWord(m_defaults, "threads"); m_rmsd = Json2KeyWord(m_defaults, "rmsd"); - m_hmass = Json2KeyWord(m_defaults, "hmass"); + m_hmass = Json2KeyWord(m_defaults, "hmass"); m_impuls = Json2KeyWord(m_defaults, "impuls"); m_impuls_scaling = Json2KeyWord(m_defaults, "impuls_scaling"); @@ -188,7 +188,6 @@ void SimpleMD::LoadControlJson() m_coupling = Json2KeyWord(m_defaults, "coupling"); m_anderson = Json2KeyWord(m_defaults, "anderson"); - m_threads = Json2KeyWord(m_defaults, "threads"); if (m_coupling < m_dT) m_coupling = m_dT; @@ -211,6 +210,7 @@ void SimpleMD::LoadControlJson() m_writerestart = Json2KeyWord(m_defaults, "writerestart"); m_respa = Json2KeyWord(m_defaults, "respa"); m_dipole = Json2KeyWord(m_defaults, "dipole"); + m_scaling_json = Json2KeyWord(m_defaults, "scaling_json"); m_writeXYZ = Json2KeyWord(m_defaults, "writeXYZ"); m_writeinit = Json2KeyWord(m_defaults, "writeinit"); @@ -256,14 +256,14 @@ void SimpleMD::LoadControlJson() std::cout << "Energy Calculator will NOT be set up for each step! Fast energy calculation! This is the default way and should not be changed unless the energy and gradient calculation are unstable (happens with GFN2 and solvation)." << std::endl; } - if (Json2KeyWord(m_defaults, "wall").compare("spheric") == 0) { - if (Json2KeyWord(m_defaults, "wall_type").compare("logfermi") == 0) { + if (Json2KeyWord(m_defaults, "wall") == "spheric") { + if (Json2KeyWord(m_defaults, "wall_type") == "logfermi") { m_wall_type = 1; WallPotential = [=](double* grad) -> double { this->m_wall_potential = this->ApplySphericLogFermiWalls(grad); return m_wall_potential; }; - } else if (Json2KeyWord(m_defaults, "wall_type").compare("harmonic") == 0) { + } else if (Json2KeyWord(m_defaults, "wall_type") == "harmonic") { m_wall_type = 1; WallPotential = [=](double* grad) -> double { this->m_wall_potential = this->ApplySphericHarmonicWalls(grad); @@ -275,14 +275,14 @@ void SimpleMD::LoadControlJson() } std::cout << "Setting up spherical potential" << std::endl; - } else if (Json2KeyWord(m_defaults, "wall").compare("rect") == 0) { - if (Json2KeyWord(m_defaults, "wall_type").compare("logfermi") == 0) { + } else if (Json2KeyWord(m_defaults, "wall") == "rect") { + if (Json2KeyWord(m_defaults, "wall_type") == "logfermi") { m_wall_type = 2; WallPotential = [=](double* grad) -> double { this->m_wall_potential = this->ApplyRectLogFermiWalls(grad); return m_wall_potential; }; - } else if (Json2KeyWord(m_defaults, "wall_type").compare("harmonic") == 0) { + } else if (Json2KeyWord(m_defaults, "wall_type") == "harmonic") { m_wall_type = 2; WallPotential = [=](double* grad) -> double { this->m_wall_potential = this->ApplyRectHarmonicWalls(grad); @@ -298,7 +298,7 @@ void SimpleMD::LoadControlJson() WallPotential = [=](double* grad) -> double { return 0; }; - m_rm_COM_step = m_rm_COM / m_dT; + m_rm_COM_step = static_cast(m_rm_COM / m_dT); } bool SimpleMD::Initialise() @@ -313,19 +313,19 @@ bool SimpleMD::Initialise() std::cout << "Random seed is " << m_seed << std::endl; gen.seed(m_seed); - if (m_initfile.compare("none") != 0) { + if (m_initfile != "none") { json md; std::ifstream restart_file(m_initfile); try { restart_file >> md; - } catch (nlohmann::json::type_error& e) { + } catch ([[maybe_unused]] nlohmann::json::type_error& e) { throw 404; - } catch (nlohmann::json::parse_error& e) { + } catch ([[maybe_unused]] nlohmann::json::parse_error& e) { throw 404; } LoadRestartInformation(md); - m_restart = true; - } else if (!m_norestart) + + } else if (!m_restart) LoadRestartInformation(); if (m_molecule.AtomCount() == 0) @@ -337,6 +337,34 @@ bool SimpleMD::Initialise() result_file.close(); } m_natoms = m_molecule.AtomCount(); + + m_start_fragments = m_molecule.GetFragments(); + m_scaling_vector_linear = std::vector(m_natoms, 1); + m_scaling_vector_nonlinear = std::vector(m_natoms, 1); + if (m_scaling_json != "none") { + json scaling; + std::ifstream file(m_scaling_json); + try { + file >> scaling; + } catch ([[maybe_unused]] nlohmann::json::type_error& e) { + throw 404; + } catch ([[maybe_unused]] nlohmann::json::parse_error& e) { + throw 404; + } + std::string scaling_vector_linear, scaling_vector_nonlinear; + try { + scaling_vector_linear = scaling["scaling_vector_linear"]; + scaling_vector_nonlinear = scaling["scaling_vector_nonlinear"]; + } catch ([[maybe_unused]] json::type_error& e) { + } + if (!scaling_vector_linear.empty()) { + m_scaling_vector_linear = Tools::String2DoubleVec(scaling_vector_linear, "|"); + } + if (!scaling_vector_nonlinear.empty()) { + m_scaling_vector_nonlinear = Tools::String2DoubleVec(scaling_vector_nonlinear, "|"); + } + } + m_molecule.setCharge(0); if (!m_nocenter) { std::cout << "Move stucture to the origin ... " << std::endl; @@ -431,7 +459,7 @@ bool SimpleMD::Initialise() m_xi.resize(m_chain_length, 0.0); m_Q.resize(m_chain_length, 100); // Setze eine geeignete Masse für jede Kette for (int i = 0; i < m_chain_length; ++i) { - m_xi[i] = pow(10.0, double(i)) - 1; + m_xi[i] = pow(10.0, static_cast(i)) - 1; m_Q[i] = pow(10, i) * kb_Eh * m_T0 * m_dof * 100; std::cout << m_xi[i] << " " << m_Q[i] << std::endl; } @@ -463,7 +491,7 @@ bool SimpleMD::Initialise() config["silent"] = true; config["reorder"] = false; for (int i = 0; i < m_threads; ++i) { - BiasThread* thread = new BiasThread(m_rmsd_mtd_molecule, config); + auto* thread = new BiasThread(m_rmsd_mtd_molecule, config); thread->setDT(m_rmsd_DT); thread->setk(m_k_rmsd); thread->setalpha(m_alpha_rmsd); @@ -487,7 +515,7 @@ bool SimpleMD::Initialise() } m_bias_structure_count = index; } else { - if (m_rmsd_ref_file.compare("none") != 0) { + if (m_rmsd_ref_file != "none") { std::cout << "Reading structure files from " << m_rmsd_ref_file << std::endl; int index = 0; @@ -523,7 +551,7 @@ void SimpleMD::InitConstrainedBonds() std::pair indicies(i, j); std::pair minmax(m_molecule.CalculateDistance(i, j) * m_molecule.CalculateDistance(i, j), m_molecule.CalculateDistance(i, j) * m_molecule.CalculateDistance(i, j)); std::pair, double> bond(indicies, m_molecule.CalculateDistance(i, j) * m_molecule.CalculateDistance(i, j)); - m_bond_constrained.push_back(std::pair, double>(bond)); + m_bond_constrained.emplace_back(bond); // std::cout << i << " " << j << " " << bond.second << std::endl; } @@ -752,8 +780,8 @@ nlohmann::json SimpleMD::WriteRestartInformation() restart["counter"] = m_bias_structure_count; restart["rmsd_atoms"] = m_rmsd_atoms; std::vector bias(m_bias_structure_count); - for (int i = 0; i < m_bias_threads.size(); ++i) { - for (const auto& stored_bias : m_bias_threads[i]->getBias()) { + for (const auto & m_bias_thread : m_bias_threads) { + for (const auto& stored_bias : m_bias_thread->getBias()) { bias[stored_bias["index"]] = stored_bias; } } @@ -777,10 +805,10 @@ bool SimpleMD::LoadRestartInformation() json restart; try { file >> restart; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { error++; continue; - } catch (json::parse_error& e) { + } catch ([[maybe_unused]] json::parse_error& e) { error++; continue; } @@ -788,7 +816,7 @@ bool SimpleMD::LoadRestartInformation() json md; try { md = restart[MethodName()[0]]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { error++; continue; } @@ -803,133 +831,133 @@ bool SimpleMD::LoadRestartInformation(const json& state) try { m_method = state["method"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_dT = state["dT"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_maxtime = state["MaxTime"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_rmrottrans = state["rmrottrans"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_nocenter = state["nocenter"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_COM = state["COM"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_T0 = state["T"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_currentStep = state["currentStep"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_aver_Epot = state["average_Epot"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_aver_Ekin = state["average_Ekin"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_aver_Etot = state["average_Etot"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_aver_Temp = state["average_T"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_average_virial_correction = state["average_Virial"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_average_wall_potential = state["average_Wall"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_coupling = state["coupling"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_respa = state["respa"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_eta = state["eta"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_thermostat = state["thermostat"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { geometry = state["geometry"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { velocities = state["velocities"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { xi = state["xi"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { Q = state["Q"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_mtd = state["mtd"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_rattle = state["rattle"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_rattle_tolerance = state["rattle_tolerance"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_rattle_maxiter = state["rattle_maxiter"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_rattle_dynamic_tol = state["rattle_dynamic_tol"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_rattle_dynamic_tol_iter = state["rattle_dynamic_tol_iter"]; - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } try { m_rmsd_mtd = state["rmsd_mtd"]; @@ -944,25 +972,25 @@ bool SimpleMD::LoadRestartInformation(const json& state) m_rmsd_ref_file = state["rmsd_ref_file"]; m_bias_json = state["bias"]; } - } catch (json::type_error& e) { + } catch ([[maybe_unused]] json::type_error& e) { } - if (geometry.size()) { + if (!geometry.empty()) { m_current_geometry = Tools::String2DoubleVec(geometry, "|"); } - if (velocities.size()) { + if (!velocities.empty()) { m_velocities = Tools::String2DoubleVec(velocities, "|"); } - if (xi.size()) { + if (!xi.empty()) { m_xi = Tools::String2DoubleVec(xi, "|"); } - if (Q.size()) { + if (!Q.empty()) { m_Q = Tools::String2DoubleVec(Q, "|"); } - m_restart = geometry.size() && velocities.size(); + m_restart = !geometry.empty() && !velocities.empty(); return true; } @@ -972,28 +1000,28 @@ void SimpleMD::start() if (m_initialised == false) return; bool aborted = false; - auto unix_timestamp = std::chrono::seconds(std::time(NULL)); + auto unix_timestamp = std::chrono::seconds(std::time(nullptr)); m_unix_started = std::chrono::milliseconds(unix_timestamp).count(); - double* gradient = new double[3 * m_natoms]; + auto* gradient = new double[3 * m_natoms]; std::vector states; for (int i = 0; i < 3 * m_natoms; ++i) { gradient[i] = 0; } - if (m_thermostat.compare("csvr") == 0) { + if (m_thermostat == "csvr") { fmt::print(fg(fmt::color::green) | fmt::emphasis::bold, "\nUsing Canonical sampling through velocity rescaling (CSVR) Thermostat\nJ. Chem. Phys. 126, 014101 (2007) - DOI: 10.1063/1.2408420\n\n"); - ThermostatFunction = std::bind(&SimpleMD::CSVR, this); - } else if (m_thermostat.compare("berendson") == 0) { + ThermostatFunction = [this] { CSVR(); }; + } else if (m_thermostat == "berendson") { fmt::print(fg(fmt::color::green) | fmt::emphasis::bold, "\nUsing Berendson Thermostat\nJ. Chem. Phys. 81, 3684 (1984) - DOI: 10.1063/1.448118\n\n"); - ThermostatFunction = std::bind(&SimpleMD::Berendson, this); - } else if (m_thermostat.compare("anderson") == 0) { + ThermostatFunction = [this] { Berendson(); }; + } else if (m_thermostat == "anderson") { fmt::print(fg(fmt::color::green) | fmt::emphasis::bold, "\nUsing Anderson Thermostat\n ... \n\n"); - ThermostatFunction = std::bind(&SimpleMD::Anderson, this); - } else if (m_thermostat.compare("nosehover") == 0) { + ThermostatFunction = [this] { Anderson(); }; + } else if (m_thermostat == "nosehover") { fmt::print(fg(fmt::color::green) | fmt::emphasis::bold, "\nUsing Nosé-Hoover-Chain Thermostat\n ... \n\n"); - ThermostatFunction = std::bind(&SimpleMD::NoseHover, this); + ThermostatFunction = [this] { NoseHover(); }; } else { - ThermostatFunction = std::bind(&SimpleMD::None, this); + ThermostatFunction = [this] { None(); }; std::cout << "No Thermostat applied\n" << std::endl; } @@ -1076,7 +1104,7 @@ void SimpleMD::start() PrintStatus(); /* Start MD Lopp here */ - for (; m_currentStep < m_maxtime;) { + while (m_currentStep < m_maxtime) { auto step0 = std::chrono::system_clock::now(); if (CheckStop() == true) { @@ -1115,15 +1143,38 @@ void SimpleMD::start() } } -/////////// Dipole calc - - + /////////// Dipole + if (m_dipole && m_method == "gfn2") { + //linear Dipoles + auto curr_dipoles_lin = m_molecule.CalculateDipoleMoments(m_scaling_vector_linear, m_start_fragments); + std::cout << m_scaling_vector_linear[0] << std::endl; + std::ofstream file; + file.open(Basename() + "_dipole_linear.out", std::ios_base::app); + Position d = {0,0,0}; + for (const auto& dipole_lin : curr_dipoles_lin) { + d += dipole_lin; + file << dipole_lin[0] << " " << dipole_lin[1] << " " << dipole_lin[2] << " " << dipole_lin.norm() << ", "; + } + file << d[0] << " " << d[1] << " " << d[2] << ", " << m_molecule.getDipole()[0] << " " << m_molecule.getDipole()[1] << " " << m_molecule.getDipole()[2] << std::endl; + file.close(); + //nonlinear Dipoles + auto curr_dipoles_nlin = m_molecule.CalculateDipoleMoments(m_scaling_vector_nonlinear, m_start_fragments); + std::cout << m_scaling_vector_nonlinear[0] << std::endl; + std::ofstream file2; + file2.open(Basename() + "_dipole_nonlinear.out", std::ios_base::app); + Position sum = {0,0,0}; + for (const auto& dipole_nlin : curr_dipoles_nlin) { + sum += dipole_nlin; + file2 << dipole_nlin[0] << " " << dipole_nlin[1] << " " << dipole_nlin[2] << " " << dipole_nlin.norm() <<", "; + } + file2 << sum[0] << " " << sum[1] << " " << sum[2] << ", " << m_molecule.getDipole()[0] << " " << m_molecule.getDipole()[1] << " " << m_molecule.getDipole()[2] << std::endl; + file2.close(); + } + //////////// Dipole -/////////// Dipole calc if (m_step % m_dump == 0) { - bool write = WriteGeometry(); - if (write) { + if (bool write = WriteGeometry()) { states.push_back(WriteRestartInformation()); m_current_rescue = 0; } else if (!write && m_rescue && states.size() > (1 - m_current_rescue)) { @@ -1168,12 +1219,12 @@ void SimpleMD::start() } if (m_writerestart > -1 && m_step % m_writerestart == 0) { - std::ofstream restart_file("curcuma_step_" + std::to_string(int(m_step * m_dT)) + ".json"); - nlohmann::json restart; + std::ofstream restart_file("curcuma_step_" + std::to_string(static_cast(m_step * m_dT)) + ".json"); + json restart; restart[MethodName()[0]] = WriteRestartInformation(); restart_file << restart << std::endl; } - if ((m_step && int(m_step * m_dT) % m_print == 0)) { + if ((m_step && static_cast(m_step * m_dT) % m_print == 0)) { m_Etot = m_Epot + m_Ekin; PrintStatus(); m_time_step = 0; @@ -1198,19 +1249,16 @@ void SimpleMD::start() m_step++; m_currentStep += m_dT; m_time_step += std::chrono::duration_cast(std::chrono::system_clock::now() - step0).count(); - } + } //MD Loop end here PrintStatus(); - if (m_thermostat.compare("csvr") == 0) + if (m_thermostat == "csvr") std::cout << "Exchange with heat bath " << m_Ekin_exchange << "Eh" << std::endl; if (m_dipole) { - /* + double dipole = 0.0; - for( auto d : m_collected_dipole) - dipole += d; - dipole /= m_collected_dipole.size(); - std::cout << dipole*2.5418 << " average dipole in Debye and " << dipole*2.5418*3.3356e-30 << " Cm" << std::endl; - */ - std::cout << "Calculated averaged dipole moment " << m_aver_dipol * 2.5418 << " Debye and " << m_aver_dipol * 2.5418 * 3.3356 << " Cm [e-30]" << std::endl; + //std::cout << dipole*2.5418 << " average dipole in Debye and " << dipole*2.5418*3.3356e-30 << " Cm" << std::endl; + + std::cout << "Calculated averaged dipole moment " << m_aver_dipol_linear * 2.5418 << " Debye and " << m_aver_dipol_linear * 2.5418 * 3.3356 << " Cm [e-30]" << std::endl; } #ifdef USE_Plumed @@ -1223,7 +1271,7 @@ void SimpleMD::start() for (int i = 0; i < m_bias_threads.size(); ++i) { auto structures = m_bias_threads[i]->getBiasStructure(); for (int j = 0; j < structures.size(); ++j) { - std::cout << structures[j].rmsd_reference << "\t" << structures[j].energy << "\t" << structures[j].counter / double(m_colvar_incr) * 100 << std::endl; + std::cout << structures[j].rmsd_reference << "\t" << structures[j].energy << "\t" << structures[j].counter / static_cast(m_colvar_incr) * 100 << std::endl; m_rmsd_mtd_molecule.setGeometry(structures[j].geometry); m_rmsd_mtd_molecule.setEnergy(structures[j].energy); @@ -1246,7 +1294,7 @@ void SimpleMD::start() void SimpleMD::AdjustRattleTolerance() { - m_aver_rattle_Temp /= double(m_rattle_counter); + m_aver_rattle_Temp /= static_cast(m_rattle_counter); // std::pair pair(m_rattle_tolerance, m_aver_Temp); @@ -1343,7 +1391,7 @@ void SimpleMD::Rattle(double* grad) * updated velocities of the second atom (minus instead of plus) */ TriggerWriteRestart(); - double* coord = new double[3 * m_natoms]; + auto* coord = new double[3 * m_natoms]; double m_dT_inverse = 1 / m_dT; std::vector moved(m_natoms, 0); bool move = false; @@ -1555,17 +1603,17 @@ void SimpleMD::ApplyRMSDMTD(double* grad) colvarfile.close(); } if (m_threads == 1 || m_bias_structure_count == 1) { - for (int i = 0; i < m_bias_threads.size(); ++i) { - m_bias_threads[i]->setCurrentGeometry(current_geometry, m_currentStep); - m_bias_threads[i]->start(); - current_bias += m_bias_threads[i]->BiasEnergy(); + for (auto & m_bias_thread : m_bias_threads) { + m_bias_thread->setCurrentGeometry(current_geometry, m_currentStep); + m_bias_thread->start(); + current_bias += m_bias_thread->BiasEnergy(); for (int j = 0; j < m_rmsd_indicies.size(); ++j) { - grad[3 * m_rmsd_indicies[j] + 0] += m_bias_threads[i]->Gradient()(j, 0); - grad[3 * m_rmsd_indicies[j] + 1] += m_bias_threads[i]->Gradient()(j, 1); - grad[3 * m_rmsd_indicies[j] + 2] += m_bias_threads[i]->Gradient()(j, 2); + grad[3 * m_rmsd_indicies[j] + 0] += m_bias_thread->Gradient()(j, 0); + grad[3 * m_rmsd_indicies[j] + 1] += m_bias_thread->Gradient()(j, 1); + grad[3 * m_rmsd_indicies[j] + 2] += m_bias_thread->Gradient()(j, 2); } - m_colvar_incr += m_bias_threads[i]->Counter(); - m_loop_time += m_bias_threads[i]->Time(); + m_colvar_incr += m_bias_thread->Counter(); + m_loop_time += m_bias_thread->Time(); } } else { if (m_bias_structure_count < m_threads) { @@ -1573,8 +1621,8 @@ void SimpleMD::ApplyRMSDMTD(double* grad) m_bias_threads[i]->setCurrentGeometry(current_geometry, m_currentStep); } } else { - for (int i = 0; i < m_bias_threads.size(); ++i) { - m_bias_threads[i]->setCurrentGeometry(current_geometry, m_currentStep); + for (auto & m_bias_thread : m_bias_threads) { + m_bias_thread->setCurrentGeometry(current_geometry, m_currentStep); } } @@ -1583,18 +1631,18 @@ void SimpleMD::ApplyRMSDMTD(double* grad) m_bias_pool->StartAndWait(); m_bias_pool->setWakeUp(m_bias_pool->WakeUp() / 2); - for (int i = 0; i < m_bias_threads.size(); ++i) { - if (m_bias_threads[i]->Return() == 1) { + for (auto & m_bias_thread : m_bias_threads) { + if (m_bias_thread->Return() == 1) { - current_bias += m_bias_threads[i]->BiasEnergy(); + current_bias += m_bias_thread->BiasEnergy(); for (int j = 0; j < m_rmsd_indicies.size(); ++j) { - grad[3 * m_rmsd_indicies[j] + 0] += m_bias_threads[i]->Gradient()(j, 0); - grad[3 * m_rmsd_indicies[j] + 1] += m_bias_threads[i]->Gradient()(j, 1); - grad[3 * m_rmsd_indicies[j] + 2] += m_bias_threads[i]->Gradient()(j, 2); + grad[3 * m_rmsd_indicies[j] + 0] += m_bias_thread->Gradient()(j, 0); + grad[3 * m_rmsd_indicies[j] + 1] += m_bias_thread->Gradient()(j, 1); + grad[3 * m_rmsd_indicies[j] + 2] += m_bias_thread->Gradient()(j, 2); } - m_colvar_incr += m_bias_threads[i]->Counter(); + m_colvar_incr += m_bias_thread->Counter(); } - m_loop_time += m_bias_threads[i]->Time(); + m_loop_time += m_bias_thread->Time(); } m_bias_pool->Reset(); } @@ -1798,9 +1846,9 @@ void SimpleMD::RemoveRotations(std::vector& velo) std::vector> fragments = m_molecule.GetFragments(); // std::cout << fragments.size() << std::endl; - for (int f = 0; f < fragments.size(); ++f) { - for (int i : fragments[f]) { - double m = m_mass[i]; + for (auto & fragment : fragments) { + for (const int i : fragment) { + const double m = m_mass[i]; mass += m; pos(0) += m * m_current_geometry[3 * i + 0]; pos(1) += m * m_current_geometry[3 * i + 1]; @@ -1815,21 +1863,21 @@ void SimpleMD::RemoveRotations(std::vector& velo) pos(2) /= mass; Geometry matrix = Geometry::Zero(3, 3); - for (int i : fragments[f]) { - double m = m_mass[i]; + for (const int i : fragment) { + const double m = m_mass[i]; geom(i, 0) -= pos(0); geom(i, 1) -= pos(1); geom(i, 2) -= pos(2); - double x = geom(i, 0); - double y = geom(i, 1); - double z = geom(i, 2); + const double x = geom(i, 0); + const double y = geom(i, 1); + const double z = geom(i, 2); angom(0) += m_mass[i] * (geom(i, 1) * velo[3 * i + 2] - geom(i, 2) * velo[3 * i + 1]); angom(1) += m_mass[i] * (geom(i, 2) * velo[3 * i + 0] - geom(i, 0) * velo[3 * i + 2]); angom(2) += m_mass[i] * (geom(i, 0) * velo[3 * i + 1] - geom(i, 1) * velo[3 * i + 0]); - double x2 = x * x; - double y2 = y * y; - double z2 = z * z; + const double x2 = x * x; + const double y2 = y * y; + const double z2 = z * z; matrix(0, 0) += m * (y2 + z2); matrix(1, 1) += m * (x2 + z2); matrix(2, 2) += m * (x2 + y2); @@ -1844,13 +1892,13 @@ void SimpleMD::RemoveRotations(std::vector& velo) Position omega = matrix.inverse() * angom; Position rlm = { 0, 0, 0 }, ram = { 0, 0, 0 }; - for (int i : fragments[f]) { + for (const int i : fragment) { rlm(0) = rlm(0) + m_mass[i] * velo[3 * i + 0]; rlm(1) = rlm(1) + m_mass[i] * velo[3 * i + 1]; rlm(2) = rlm(2) + m_mass[i] * velo[3 * i + 2]; } - for (int i : fragments[f]) { + for (const int i : fragment) { ram(0) = (omega(1) * geom(i, 2) - omega(2) * geom(i, 1)); ram(1) = (omega(2) * geom(i, 0) - omega(0) * geom(i, 2)); ram(2) = (omega(0) * geom(i, 1) - omega(1) * geom(i, 0)); @@ -1937,13 +1985,12 @@ void SimpleMD::RemoveRotation(std::vector& velo) void SimpleMD::PrintStatus() const { - auto unix_timestamp = std::chrono::seconds(std::time(NULL)); + const auto unix_timestamp = std::chrono::seconds(std::time(NULL)); - int current = std::chrono::milliseconds(unix_timestamp).count(); - double duration = (current - m_unix_started) / (1000.0 * double(m_currentStep)); + const int current = std::chrono::milliseconds(unix_timestamp).count(); + const double duration = (current - m_unix_started) / (1000.0 * static_cast(m_currentStep)); double remaining; - double tmp = (m_maxtime - m_currentStep) * duration / 60; - if (tmp >= 1) + if (const double tmp = (m_maxtime - m_currentStep) * duration / 60; tmp >= 1) remaining = tmp; else remaining = (m_maxtime - m_currentStep) * duration; @@ -1960,7 +2007,7 @@ void SimpleMD::PrintStatus() const #ifdef GCC if (m_dipole) std::cout << fmt::format("{1: ^{0}f} {2: ^{0}f} {3: ^{0}f} {4: ^{0}f} {5: ^{0}f} {6: ^{0}f} {7: ^{0}f} {8: ^{0}f} {9: ^{0}f} {10: ^{0}f} {11: ^{0}f} {12: ^{0}f} {13: ^{0}f} {14: ^{0}f} {15: ^{0}f} {16: ^{0}f}\n", 15, - m_currentStep / 1000, m_Epot, m_aver_Epot, m_Ekin, m_aver_Ekin, m_Etot, m_aver_Etot, m_T, m_aver_Temp, m_wall_potential, m_average_wall_potential, m_aver_dipol * 2.5418 * 3.3356, m_virial_correction, m_average_virial_correction, remaining, m_time_step / 1000.0); + m_currentStep / 1000, m_Epot, m_aver_Epot, m_Ekin, m_aver_Ekin, m_Etot, m_aver_Etot, m_T, m_aver_Temp, m_wall_potential, m_average_wall_potential, m_aver_dipol_linear * 2.5418 * 3.3356, m_virial_correction, m_average_virial_correction, remaining, m_time_step / 1000.0); else std::cout << fmt::format("{1: ^{0}f} {2: ^{0}f} {3: ^{0}f} {4: ^{0}f} {5: ^{0}f} {6: ^{0}f} {7: ^{0}f} {8: ^{0}f} {9: ^{0}f} {10: ^{0}f} {11: ^{0}f} {12: ^{0}f} {13: ^{0}f} {14: ^{0}f} {15: ^{0}f}\n", 15, m_currentStep / 1000, m_Epot, m_aver_Epot, m_Ekin, m_aver_Ekin, m_Etot, m_aver_Etot, m_T, m_aver_Temp, m_wall_potential, m_average_wall_potential, m_virial_correction, m_average_virial_correction, remaining, m_time_step / 1000.0); @@ -1972,7 +2019,7 @@ void SimpleMD::PrintStatus() const //std::cout << m_mtd_time << " " << m_loop_time << std::endl; } -void SimpleMD::PrintMatrix(const double* matrix) +void SimpleMD::PrintMatrix(const double* matrix) const { std::cout << "Print Matrix" << std::endl; for (int i = 0; i < m_natoms; ++i) { @@ -1987,12 +2034,11 @@ double SimpleMD::CleanEnergy(double* grad) interface.setMolecule(m_molecule); interface.updateGeometry(m_current_geometry); - double Energy = interface.CalculateEnergy(true); + const double Energy = interface.CalculateEnergy(true); interface.getGradient(grad); - if (m_dipole) { - auto dipole = interface.Dipole(); - m_curr_dipole = sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]); - m_collected_dipole.push_back(sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2])); + if (m_dipole && m_method == "gfn2") { + m_molecule.setDipole(interface.Dipole()*au);//in eA + m_molecule.setPartialCharges(interface.Charges()); } return Energy; } @@ -2001,12 +2047,11 @@ double SimpleMD::FastEnergy(double* grad) { m_interface->updateGeometry(m_current_geometry); - double Energy = m_interface->CalculateEnergy(true); + const double Energy = m_interface->CalculateEnergy(true); m_interface->getGradient(grad); - if (m_dipole) { - auto dipole = m_interface->Dipole(); - m_curr_dipole = sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]); - m_collected_dipole.push_back(sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2])); + if (m_dipole && m_method == "gfn2") { + m_molecule.setDipole(m_interface->Dipole()*au);// in eA + m_molecule.setPartialCharges(m_interface->Charges()); } return Energy; } @@ -2029,7 +2074,7 @@ void SimpleMD::AverageQuantities() m_aver_Ekin = (m_Ekin + (m_currentStep)*m_aver_Ekin) / (m_currentStep + 1); m_aver_Etot = (m_Etot + (m_currentStep)*m_aver_Etot) / (m_currentStep + 1); if (m_dipole) { - m_aver_dipol = (m_curr_dipole + (m_currentStep)*m_aver_dipol) / (m_currentStep + 1); + //m_aver_dipol = (m_curr_dipoles + (m_currentStep)*m_aver_dipol) / (m_currentStep + 1); } m_average_wall_potential = (m_wall_potential + (m_currentStep)*m_average_wall_potential) / (m_currentStep + 1); m_average_virial_correction = (m_virial_correction + (m_currentStep)*m_average_virial_correction) / (m_currentStep + 1); @@ -2084,7 +2129,7 @@ void SimpleMD::CSVR() static std::default_random_engine rd{}; static std::mt19937 gen{ rd() }; static std::normal_distribution<> d{ 0, 1 }; - static std::chi_squared_distribution dchi{ m_dof }; + static std::chi_squared_distribution dchi{ static_cast(m_dof) }; double R = d(gen); double SNf = dchi(gen); diff --git a/src/capabilities/simplemd.h b/src/capabilities/simplemd.h index bde0e7e..9af4c5b 100644 --- a/src/capabilities/simplemd.h +++ b/src/capabilities/simplemd.h @@ -1,5 +1,5 @@ /* - * + * * Copyright (C) 2023 - 2024 Conrad Hübler * * This program is free software: you can redistribute it and/or modify @@ -156,8 +156,8 @@ static json CurcumaMDJson{ { "rattle_dynamic_tol_iter", 100 }, { "thermostat", "csvr" }, // can be csvr (default), berendson, none, anderson or nosehover { "respa", 1 }, - { "threads", 1 }, { "dipole", false }, + { "scaling_json", "none" }, { "seed", 1 }, { "cleanenergy", false }, { "wall", "none" }, // can be spheric or rect @@ -245,7 +245,7 @@ class SimpleMD : public CurcumaMethod { double FastEnergy(double* grad); double CleanEnergy(double* grad); - void PrintMatrix(const double* matrix); + void PrintMatrix(const double* matrix) const; bool WriteGeometry(); void Verlet(double* grad); @@ -292,17 +292,18 @@ class SimpleMD : public CurcumaMethod { int m_natoms = 0; int m_dump = 1; - double m_T = 0, m_Epot = 0, m_aver_Epot = 0, m_Ekin = 0, m_aver_Ekin = 0, m_Etot = 0, m_aver_Etot = 0, m_aver_dipol = 0, m_curr_dipole = 0; + double m_T = 0, m_Epot = 0, m_aver_Epot = 0, m_Ekin = 0, m_aver_Ekin = 0, m_Etot = 0, m_aver_Etot = 0, m_aver_dipol_linear = 0; double m_rm_COM = 100; int m_rm_COM_step = -1; int m_hmass = 1; double m_single_step = 1; double m_dT = 0.5, m_currentStep = 0, m_maxtime = 1000; int m_spin = 0, m_charge = 0, m_print = 100; - double m_T0 = 298.13, m_aver_Temp = 0, m_aver_rattle_Temp = 0, m_rmsd = 1.5; + double m_T0 = 298.15, m_aver_Temp = 0, m_aver_rattle_Temp = 0, m_rmsd = 1.5; double m_x0 = 0, m_y0 = 0, m_z0 = 0; double m_Ekin_exchange = 0.0; - std::vector m_current_geometry, m_mass, m_velocities, m_gradient, m_rmass, m_virial, m_gradient_bias; + std::vector m_current_geometry, m_mass, m_velocities, m_gradient, m_rmass, m_virial, m_gradient_bias, m_scaling_vector_linear, m_scaling_vector_nonlinear; + std::vector m_curr_dipoles; std::vector m_atomtype; Molecule m_molecule, m_reference, m_target, m_rmsd_mtd_molecule; bool m_initialised = false, m_restart = false, m_writeUnique = true, m_opt = false, m_rescue = false, m_writeXYZ = true, m_writeinit = false, m_norestart = false; @@ -314,7 +315,8 @@ class SimpleMD : public CurcumaMethod { RMSDTraj* m_unqiue; const std::vector m_used_mass; std::vector m_rmsd_indicies; - std::vector > m_rmsd_fragments; + std::vector > m_rmsd_fragments, m_start_fragments; + std::vector m_bias_structures; std::vector m_biased_structures; @@ -351,7 +353,7 @@ class SimpleMD : public CurcumaMethod { std::vector m_collected_dipole; Matrix m_topo_initial; std::vector m_unique_structures; - std::string m_method = "UFF", m_initfile = "none", m_thermostat = "csvr", m_plumed, m_rmsd_ref_file, m_rmsd_atoms = "-1"; + std::string m_method = "UFF", m_initfile = "none", m_thermostat = "csvr", m_plumed, m_rmsd_ref_file, m_rmsd_atoms = "-1", m_scaling_json = "none"; bool m_unstable = false; bool m_dipole = false; bool m_clean_energy = false; diff --git a/src/core/global.h b/src/core/global.h index 1746ce4..52aa487 100644 --- a/src/core/global.h +++ b/src/core/global.h @@ -32,7 +32,7 @@ using json = nlohmann::json; const double pi = 3.14159265359; -const double au = 0.52917721092; +const double au = 0.52917721092; // Angstrom const double amu2au = 1822.8884850; const double kb_Eh = 3.166811e-6; // Hartree const double kb_SI = 1.380649e-23; // SI diff --git a/src/core/molecule.cpp b/src/core/molecule.cpp index 6aac8ae..393cb72 100644 --- a/src/core/molecule.cpp +++ b/src/core/molecule.cpp @@ -696,14 +696,31 @@ void Molecule::LoadMolecule(const Mol* molecule) m_bonds = molecule->m_bonds; } -Molecule Molecule::getFragmentMolecule(int fragment) const +Molecule Molecule::getFragmentMolecule(const int fragment) const { - // Lets make that one day faster, but not today ... + // Let's make that one day faster, but not today ... + // TODO inherit some more properties ... Molecule result; + std::vector pCharges; auto atoms = GetFragments()[fragment]; - for (auto atom : atoms) { + for (const auto atom : atoms) { result.addPair(Atom(atom)); + pCharges.push_back(m_charges[atom]); } + result.setPartialCharges(pCharges); + return result; +} +Molecule Molecule::getFragmentMolecule(const std::vector& atoms) const +{ + // Let's make that one day faster, but not today ... + // TODO inherit some more properties ... + Molecule result; + std::vector pCharges; + for (const auto atom : atoms) { + result.addPair(Atom(atom)); + pCharges.push_back(m_charges[atom]); + } + result.setPartialCharges(pCharges); return result; } Geometry Molecule::getGeometry(bool protons) const @@ -900,48 +917,82 @@ Eigen::Vector3d Molecule::COM(bool protons, int fragment) return com; } -std::vector Molecule::CalculateDipoleMoments(const std::vector& scaling) const -{ // calc classic dipole moment of the system with partial charges +std::vector Molecule::CalculateDipoleMoments(const std::vector& scaling, const std::vector>& fragments) const +{ // calc classic dipole moments of the every fragment with partial charges std::vector dipole_moments; - if (m_charges.size() != m_geometry.rows()) { std::cout << "No partial charges available" << std::endl; return dipole_moments; } - // calc center of mass and dipole for every fragment - for (int f = 0; f < GetFragments().size(); ++f) { - Position pos = { 0, 0, 0 }, dipole = { 0, 0, 0 }; - double mass = 0; - // calc center of mass of the molecule - for (int i : m_fragments[f]) { - double m = Elements::AtomicMass[m_atoms[i]]; - mass += m; - pos(0) += m * m_geometry(i, 0); - pos(1) += m * m_geometry(i, 1); - pos(2) += m * m_geometry(i, 2); + if (!fragments.empty()) { + for (int i = 0; i < fragments.size(); ++i) { + std::vector frag_scaling = {}; + for (int j = 0; j < fragments[i].size(); ++j) { + if (scaling.size() > j) + frag_scaling.push_back(scaling[j]); + else + frag_scaling.push_back(1.0); + } + Molecule mol = getFragmentMolecule(fragments[i]); + dipole_moments.push_back(mol.CalculateDipoleMoment(frag_scaling)); } - pos(0) /= mass; - pos(1) /= mass; - pos(2) /= mass; - // calc dipole moment with scalar - for (int i : m_fragments[f]) { - double scale = 1; - if (scaling.size() > i) - scale = scaling[i]; - dipole(0) += m_charges[i] * (m_geometry(i, 0) - pos(0)) * scale; - dipole(1) += m_charges[i] * (m_geometry(i, 1) - pos(1)) * scale; - dipole(2) += m_charges[i] * (m_geometry(i, 2) - pos(2)) * scale; - // std::cout << scale << " "; + } + else { + for (int i = 0; i < GetFragments().size(); ++i) { + std::vector frag_scaling = {}; + for (int j = 0; j < m_fragments[i].size(); ++j) { + if (scaling.size() > j) + frag_scaling.push_back(scaling[j]); + else + frag_scaling.push_back(1.0); + } + Molecule mol = getFragmentMolecule(i); + dipole_moments.push_back(mol.CalculateDipoleMoment(frag_scaling)); } - // std::cout << std::endl; - dipole_moments.push_back(dipole); } return dipole_moments; } -Position Molecule::CalculateDipoleMoment(const Vector& scaling) const +Position Molecule::CalculateDipoleMoment(const Vector& scaling, const bool bond) const +{ // dec and init + Position pos = { 0, 0, 0 }, dipole = { 0, 0, 0 }; + if (m_charges.size() != m_geometry.rows()) { + std::cout << "No partial charges available" << std::endl; + return dipole; + } + // calc center of geometry + pos = Centroid(); + if constexpr (false) + pos = MassCentroid(); + + // calc of the dipole moment with scalar + for (int i = 0; i < m_geometry.rows(); ++i) { + double scale = 1; + if (scaling.size() > i) + scale = scaling[i]; + dipole(0) += m_charges[i] * (m_geometry(i, 0) - pos(0)) * scale; + dipole(1) += m_charges[i] * (m_geometry(i, 1) - pos(1)) * scale; + dipole(2) += m_charges[i] * (m_geometry(i, 2) - pos(2)) * scale; + if (bond) { + for (int j = 0; j < m_geometry.rows(); ++j) { + if (i == j) + continue; + double revr = 1 / (m_geometry.row(i) - m_geometry.row(j)).norm(); + // std::cout << m_charges[i] *revr * scale << " "; + + dipole(0) -= m_charges[i] * revr * scale; + dipole(1) -= m_charges[i] * revr * scale; + dipole(2) -= m_charges[i] * revr * scale; + } + // std::cout << scale << " "; + } + } + // std::cout << std::endl; + return dipole; +} + +Position Molecule::CalculateDipoleMoment(const std::vector& scaling, const bool bond) const { // dec and init - double mass = 0; Position pos = { 0, 0, 0 }, dipole = { 0, 0, 0 }; if (m_charges.size() != m_geometry.rows()) { @@ -949,7 +1000,9 @@ Position Molecule::CalculateDipoleMoment(const Vector& scaling) const return dipole; } // calc center of mass - pos = MassCentroid(); + pos = Centroid(); + if constexpr (false) + pos = MassCentroid(); // calc of the dipole moment with scalar for (int i = 0; i < m_geometry.rows(); ++i) { @@ -959,20 +1012,19 @@ Position Molecule::CalculateDipoleMoment(const Vector& scaling) const dipole(0) += m_charges[i] * (m_geometry(i, 0) - pos(0)) * scale; dipole(1) += m_charges[i] * (m_geometry(i, 1) - pos(1)) * scale; dipole(2) += m_charges[i] * (m_geometry(i, 2) - pos(2)) * scale; - for (int j = 0; j < m_geometry.rows(); ++j) { - if (i == j) - continue; - double scale = 3; - if (scaling.size() > i) - scale = scaling[i]; - double revr = 1 / (m_geometry.row(i) - m_geometry.row(j)).norm(); - // std::cout << m_charges[i] *revr * scale << " "; - - dipole(0) -= m_charges[i] * revr * scale; - dipole(1) -= m_charges[i] * revr * scale; - dipole(2) -= m_charges[i] * revr * scale; + if (bond) { + for (int j = 0; j < m_geometry.rows(); ++j) { + if (i == j) + continue; + double revr = 1 / (m_geometry.row(i) - m_geometry.row(j)).norm(); + // std::cout << m_charges[i] *revr * scale << " "; + + dipole(0) -= m_charges[i] * revr * scale; + dipole(1) -= m_charges[i] * revr * scale; + dipole(2) -= m_charges[i] * revr * scale; + } + // std::cout << scale << " "; } - // std::cout << scale << " "; } // std::cout << std::endl; return dipole; @@ -1504,15 +1556,19 @@ std::vector Molecule::GetBox() const Geometry Molecule::ChargeDistribution() const { + Position pos = Centroid(); + if constexpr (false) + pos = MassCentroid(); + Geometry point_charge(m_geometry.rows(), 3); if (m_charges.size() != m_geometry.rows()) { std::cerr << "No partial charges available" << std::endl; return point_charge.setZero(m_geometry.rows(), 3); } for (int i = 0; i < m_charges.size(); ++i) { - point_charge(i, 0) = m_geometry(i, 0) * m_charges[i]; - point_charge(i, 1) = m_geometry(i, 1) * m_charges[i]; - point_charge(i, 2) = m_geometry(i, 2) * m_charges[i]; + point_charge(i, 0) = (m_geometry(i, 0) - pos(0)) * m_charges[i]; + point_charge(i, 1) = (m_geometry(i, 1) - pos(1)) * m_charges[i]; + point_charge(i, 2) = (m_geometry(i, 2) - pos(2)) * m_charges[i]; } return point_charge; } diff --git a/src/core/molecule.h b/src/core/molecule.h index bb9f55e..8006a71 100644 --- a/src/core/molecule.h +++ b/src/core/molecule.h @@ -108,6 +108,7 @@ class Molecule std::vector GetBox() const; Molecule getFragmentMolecule(int fragment) const; + Molecule getFragmentMolecule(const std::vector& atoms) const; double CalculateDistance(int i, int j) const; std::pair GyrationRadius(double hmass = 1, bool hydrogen = true, int fragment = -1); @@ -173,12 +174,13 @@ class Molecule /*! \brief Methode to calculate the dipole moments of single molecules * */ - std::vector CalculateDipoleMoments(const std::vector& scaling = std::vector()) const; + std::vector CalculateDipoleMoments(const std::vector& scaling = std::vector(), const std::vector>& fragments = std::vector>()) const; /*! \brief Methode to calculate the dipole moments of whole structure * unit of dipol is electron times angstron */ - Position CalculateDipoleMoment(const Vector& scaling = Vector()) const; + Position CalculateDipoleMoment(const Vector& scaling = Vector(), bool bond = false) const; + Position CalculateDipoleMoment(const std::vector& scaling = std::vector(), bool bond = false) const; Geometry ChargeDistribution() const; diff --git a/src/main.cpp b/src/main.cpp index 3fe9f09..49b194c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,6 +46,7 @@ #include #include #include + #include #include @@ -223,7 +224,7 @@ int main(int argc, char **argv) { exit(0); } - RMSDDriver* driver = new RMSDDriver(controller, false); + auto* driver = new RMSDDriver(controller, false); driver->setReference(molecule1); driver->setTarget(molecule2); driver->start(); @@ -244,7 +245,7 @@ int main(int argc, char **argv) { exit(1); } - Docking* docking = new Docking(controller, false); + auto* docking = new Docking(controller, false); if (!docking->Initialise()) { docking->printError(); return 0; @@ -286,7 +287,7 @@ int main(int argc, char **argv) { return -1; } std::cout << controller << std::endl; - ConfScan* scan = new ConfScan(controller); + auto* scan = new ConfScan(controller); scan->setFileName(argv[2]); scan->start(); return 0; @@ -297,7 +298,7 @@ int main(int argc, char **argv) { return -1; } - ConfStat* stat = new ConfStat(controller); + auto* stat = new ConfStat(controller); stat->setFileName(argv[2]); stat->start(); return 0; @@ -495,7 +496,7 @@ int main(int argc, char **argv) { Molecule mol1 = Files::LoadFile(argv[2]); Molecule mol2 = Files::LoadFile(argv[3]); - NEBDocking* nebdock = new NEBDocking; + auto* nebdock = new NEBDocking; nebdock->setStructures(mol1, mol2); nebdock->setProtonTransfer(pt); nebdock->Prepare(); @@ -908,7 +909,7 @@ int main(int argc, char **argv) { sum_mass += gyr.second; sqrt_sum += sqrt(gyr.first); sqrt_sum_mass += sqrt(gyr.second); - std::cout << ":: " << gyr.first << " " << sum / double(count) << " " << gyr.second << " " << sum_mass / double(count) << " " << sqrt(gyr.first) << " " << sqrt_sum / double(count) << " " << sqrt(gyr.second) << " " << sqrt_sum_mass / double(count) << std::endl; + std::cout << ":: " << gyr.first << " " << sum / static_cast(count) << " " << gyr.second << " " << sum_mass / static_cast(count) << " " << sqrt(gyr.first) << " " << sqrt_sum / static_cast(count) << " " << sqrt(gyr.second) << " " << sqrt_sum_mass / static_cast(count) << std::endl; count++; } } else if (strcmp(argv[1], "-dipole") == 0) { @@ -916,131 +917,93 @@ int main(int argc, char **argv) { std::cerr << "Please use curcuma to optimise the dipole of molecules as follow:\ncurcuma -dipole molecule.xyz" << std::endl; return 0; } + FileIterator file(argv[2]); - Position target_dipole; - - double target = 0, threshold = 1e-1, initial = 3, dx = 5e-1; // dec - bool target_set = false; - int maxiter = 10; - json blob = controller["dipole"]; // declare blob as json, - if (blob.contains("target")) { - target = blob["target"]; - target_set = true; - } - if (blob.contains("threshold")) { - threshold = blob["threshold"]; - } - if (blob.contains("initial")) { - initial = blob["initial"]; - } - if (blob.contains("maxiter")) { - maxiter = blob["maxiter"]; - } - if (blob.contains("dx")) { - dx = blob["dx"]; - } + auto lm_basename = file.Basename(); + // TODO: Add additional arguments... + // TODO: if -md then do first molecular dynamic to generate some conformers, then fit + // TODO: if -scale then calc dipole with scalingfactor and xtb2 + // TODO: if -methode then change methode + + const json blob = controller["dipole"]; // declare blob as json, const why not used for now - /*std::cout << "Parameter: " << "\n" - << "target " << target << "\n" - << "threshold " << threshold << "\n" - << "initial " << initial << "\n" - << "maxiter " << maxiter << "\n" - << "dx " << dx << "\n" - << std::endl;*/ std::vector conformers; - Molecule mol; while (!file.AtEnd()) { // calculation and output dipole moment - mol = file.Next(); // load Molecule - mol.Center(false); - - EnergyCalculator interface("gfn2", blob); // set method to gfn2-xtb and give - interface.setMolecule(mol); // set molecule for calc - interface.CalculateEnergy(false, true); // calc energy and charges and dipole moment - - mol.setPartialCharges(interface.Charges()); // calc Partial Charges and give it to mol - auto charges = interface.Charges(); // dec and init charges - mol.setDipole(interface.Dipole() * au); - auto dipole_moment = interface.Dipole() * au; // get dipole moment from gfn2-xtb methode in au - - /*std::cout << mol.AtomCount() << "\n" - << "Dipole " - << dipole_moment[0] << " " - << dipole_moment[1] << " " - << dipole_moment[2] << " " - << std::endl; - - for (int i = 0; i < charges.size(); ++i ){ // Output partial charges from gfn2-xtb methode - std::string col = mol.Atom2String(i); - col.pop_back(); - std::cout << col; - std::cout << " "; - std::cout << charges[i] << "\n"; - } - std::cout << std::endl;*/ - + Molecule mol = file.Next(); // load Molecule + mol.Center(false); //sets the Centroid to the origin + EnergyCalculator interface("gfn2", blob); // set method to gfn2-xtb + interface.setMolecule(mol); // set molecule + interface.CalculateEnergy(false, true); // calc energy and Wave function + mol.setPartialCharges(interface.Charges()); // calc partial Charges and set it to mol + mol.setDipole(interface.Dipole() * au); //calc dipole moments and set it to mol in eA conformers.push_back(mol); - mol.appendDipoleFile(file.Basename() + ".dip"); - - /*if (!target_set) { // calc target if not set - target = dipole_moment.norm(); - target_dipole = dipole_moment; - }*/ - /*std::cout << "Target dipole moment [eA, ea or D?]: " - << target << "\n" - << target_dipole[0] << ", " << target_dipole[1] << ", " << target_dipole[2] << "\n" - << std::endl; - - auto dipoles = mol.CalculateDipoleMoments();//calc Dipole for every Molecule with partial charges - for (const auto& dipole : dipoles) { - std::cout << std::endl - << "Dipole moment for single molecule [eA]: " << dipole.norm() << "\n" - << dipole[0] << ", " << dipole[1] << ", " << dipole[2] << "\n" - << std::endl; - }*/ - /*auto dipole = mol.CalculateDipoleMoment();//calc Dipole for whole system with partial charges - std::cout << std::endl - << "Dipole moment for whole structure [eA]: " << dipole.norm() << "\n" - << dipole[0] << ", " << dipole[1] << ", " << dipole[2] << "\n" - << std::endl; - std::cout << std::endl; - */ - - /* - auto result = OptimiseDipoleScaling(&conformers, initial); - std::cout << "Final dipole moment [eA]: " << result.first.norm() << "\n" - << result.first[0] << ", " << result.first[1] << ", " << result.first[2] << std::endl; - std::cout << std::endl; - std::cout << std::endl; - - std::cout << "Fitted scalar:\n"; - - double sum = 0; - - for (int i = 0; i < result.second.size(); ++i ) { //(auto i : result.second) - sum += result.second[i]; - std::cout << mol.Atom2String(i).substr(0, 1) - << i + 1 << ": " - << result.second[i] << "\n"; - } - std::cout << std::endl; - std::cout << "mean of scalar: " << sum / mol.AtomCount();*/ - } - Vector scaling(mol.AtomCount()); - for (int i = 0; i < mol.AtomCount(); ++i) { - scaling(i) = 1; } - auto result = OptimiseDipoleScaling(conformers, scaling); - std::cout << "LM-Scaler:\n" - << result << "\n" + Molecule mol = conformers.at(0); // maybe molecule in ground state + //Calculation of the scaling vector linear and nonlinear + const auto linear_vector = DipoleScalingCalculation(conformers); //linear + const auto nonlinear_vector = OptimiseDipoleScaling(conformers, linear_vector); //nonlinear + // output scaling vector as JSON + std::vector vec_linear_scaling(linear_vector.data(), linear_vector.data() + linear_vector.rows() * linear_vector.cols()); + std::vector vec_nonlinear_scaling(nonlinear_vector.data(), nonlinear_vector.data() + nonlinear_vector.rows() * nonlinear_vector.cols()); + json scaling_vector; + scaling_vector["scaling_vector_linear"] = Tools::DoubleVector2String(vec_linear_scaling); + scaling_vector["scaling_vector_nonlinear"] = Tools::DoubleVector2String(vec_nonlinear_scaling); + std::ofstream out(lm_basename + "_scaling_vector.json"); + out << scaling_vector << std::endl; + + double mean_dipole_gfn2 = 0; + double mean_dipole_nonlinear = 0; + double mean_dipole_linear = 0; + double r2_lin = 0; + double r2_nlin = 0; + double r2_lin_diffofnorm = 0; + double r2_nlin_diffofnorm = 0; + //output Dipole moments + Calculation of Mean Dipole + std::ofstream file_dipole; + file_dipole.open(lm_basename + "_dipole.out", std::ios_base::app); + file_dipole << "linear Dipole (x y z magn.); nonlinear Dipole (x y z magn.); gfn2 Dipoles (x y z magn.)" << std::endl; + for (const auto& conf : conformers){ + const auto dipole_lin = conf.CalculateDipoleMoment(vec_linear_scaling); + const auto dipole_nlin = conf.CalculateDipoleMoment(vec_nonlinear_scaling); + const auto dipole_gfn2 = conf.getDipole(); + mean_dipole_linear += dipole_lin.norm()/ conformers.size(); + mean_dipole_nonlinear += dipole_nlin.norm()/ conformers.size(); + mean_dipole_gfn2 += dipole_gfn2.norm()/ conformers.size(); + file_dipole << dipole_lin[0] << " " << dipole_lin[1] << " " << dipole_lin[2] << " " << dipole_lin.norm() << "; "; + file_dipole << dipole_nlin[0] << " " << dipole_nlin[1] << " " << dipole_nlin[2] << " " << dipole_nlin.norm() << "; "; + file_dipole << dipole_gfn2[0] << " " << dipole_gfn2[1] << " " << dipole_gfn2[2] << " " << dipole_gfn2.norm() << std::endl; + const double residual = (conf.CalculateDipoleMoment(linear_vector) - conf.getDipole()).norm(); + r2_lin += residual * residual; + const double residual_1 = (conf.CalculateDipoleMoment(nonlinear_vector) - conf.getDipole()).norm(); + r2_nlin += residual_1 * residual_1; + const double residual_2 = conf.CalculateDipoleMoment(linear_vector).norm() - conf.getDipole().norm(); + r2_lin_diffofnorm += residual_2 * residual_2; + const double residual_3 = conf.CalculateDipoleMoment(nonlinear_vector).norm() - conf.getDipole().norm(); + r2_nlin_diffofnorm += residual_3 * residual_3; + }; + file_dipole.close(); + + std::cout << "\nMean xtb2-Dipole: " << mean_dipole_gfn2 << " [eA], " << mean_dipole_gfn2/0.2082 << " [D]" << std::endl; + std::cout << "Mean linear Dipole: " << mean_dipole_linear << " [eA], " << mean_dipole_linear/0.2082 << " [D]" << std::endl + << "Mean nonlinear Dipole: " << mean_dipole_nonlinear << " [eA], " << mean_dipole_nonlinear/0.2082 << " [D]" << std::endl << std::endl; - Matrix Theta(mol.AtomCount(), 1); - Theta = DipoleScalingCalculation(conformers); - std::cout << "Analytic-Scaler:\n" - << Theta << "\n" + std::cout << "linear Scaling vector:\n" + << linear_vector << "\n" + << "nonlinear Scaling vector:\n" + << nonlinear_vector << "\n" << std::endl; + std::cout << "Square Sum of Residuals of Components:" << std::endl + << "linear: " << r2_lin << std::endl + << "nonlinear " << r2_nlin << std::endl; + std::cout << "Square Sum of Residuals of Magnitudes" << std::endl + << "linear: " << r2_lin_diffofnorm << std::endl + << "nonlinear: " << r2_nlin_diffofnorm << std::endl; + + + } else if (strcmp(argv[1], "-stride") == 0) { if (argc < 4) { @@ -1059,7 +1022,7 @@ int main(int argc, char **argv) { } } else { bool centered = false; - bool hmass = 1; + bool hmass = true; for (std::size_t i = 2; i < argc; ++i) { if (strcmp(argv[i], "-center") == 0) { centered = true;