diff --git a/CMakeLists.txt b/CMakeLists.txt index 72533c3..7d92469 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,10 @@ option (USE_XTB "Compile XTB and use as library" OFF) option (USE_TBLITE - "Compile TBLITE and use as library" OFF) + "Compile TBLITE and use as library" ON) option (USE_D3 - "Compile cpp-D4 and use as library" OFF) + "Compile cpp-D4 and use as library" ON) option (USE_D4 "Compile cpp-D4 and use as library" OFF) diff --git a/src/capabilities/curcumaopt.cpp b/src/capabilities/curcumaopt.cpp index 717bb40..6652b5f 100644 --- a/src/capabilities/curcumaopt.cpp +++ b/src/capabilities/curcumaopt.cpp @@ -126,7 +126,7 @@ void CurcumaOpt::ProcessMoleculesSerial(const std::vector& molecules) double energy = interface.CalculateEnergy(true, true); #ifdef USE_TBLITE if (method.compare("gfn2") == 0) { - std::vector dipole = interface.Dipole(); + auto dipole = interface.Dipole(); std::cout << std::endl << std::endl << "Dipole momement (GFN2)" << dipole[0] << " " << dipole[1] << " " << dipole[2] << " : " << sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]) << std::endl; @@ -233,7 +233,7 @@ double CurcumaOpt::SinglePoint(const Molecule* initial, const json& controller, double store = 0; #ifdef USE_TBLITE if (method.compare("gfn2") == 0) { - std::vector dipole = interface.Dipole(); + auto dipole = interface.Dipole(); std::cout << std::endl << std::endl << "Dipole momement (GNF2)" << dipole[0] << " " << dipole[1] << " " << dipole[2] << " : " << sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]) * 2.5418 << std::endl; diff --git a/src/capabilities/optimiser/OptimiseDipoleScaling.h b/src/capabilities/optimiser/OptimiseDipoleScaling.h index 9e9f2c9..a976e9a 100644 --- a/src/capabilities/optimiser/OptimiseDipoleScaling.h +++ b/src/capabilities/optimiser/OptimiseDipoleScaling.h @@ -1,7 +1,7 @@ /* - * + * * Copyright (C) 2023 Conrad Hübler - * + * 2024 Gerd Gehrisch * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -25,6 +25,7 @@ #include +#include "src/capabilities/optimiser/LevMarDocking.h" #include "src/core/elements.h" #include "src/core/global.h" #include "src/core/molecule.h" @@ -32,106 +33,130 @@ #include "src/tools/geometry.h" -#include "json.hpp" -#include -#include - -using json = nlohmann::json; +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 { + InputsAtCompileTime = NX, + ValuesAtCompileTime = NY + }; + typedef Eigen::Matrix InputType; + typedef Eigen::Matrix ValueType; + typedef Eigen::Matrix JacobianType; + + int m_inputs, m_values; + + inline TFunctor(int inputs, int values) + : m_inputs(inputs) + , m_values(values) + { + } -using Eigen::VectorXd; -using namespace LBFGSpp; + int inputs() const { return m_inputs; } + int values() const { return m_values; } +}; -class LBFGSDipoleInterface { -public: - LBFGSDipoleInterface(int n_) +struct OptDipoleFunctor : TFunctor { + inline OptDipoleFunctor(int inputs, int values) + : TFunctor(inputs, values) + , no_parameter(inputs) + , no_points(values) { } - double operator()(const VectorXd& x, VectorXd& grad) + inline ~OptDipoleFunctor() = default; + inline int operator()(const Vector& scaling, Eigen::VectorXd& fvec) const { - double fx = 0.0; - double dx = 5e-1; - std::vector scaling(x.size()); - for (int i = 0; i < scaling.size(); ++i) { - scaling[i] = x(i); - } + for (int i = 0; i < m_conformers.size(); ++i ){ + auto conf = m_conformers.at(i); + fvec(i) = (conf.getDipole() - conf.CalculateDipoleMoment(scaling)).norm() ; - auto dipole_vector = m_molecule->CalculateDipoleMoment(scaling); - double dipole = sqrt(dipole_vector[0] * dipole_vector[0] + dipole_vector[1] * dipole_vector[1] + dipole_vector[2] * dipole_vector[2]) * 2.5418; - fx = std::abs(m_dipole - dipole); - // std::cout << dipole << " " << m_dipole << " "<< fx<< std::endl; - for (int i = 0; i < scaling.size(); ++i) { - // if(std::abs(fx) < std::abs(m_smaller)) - // std::cout << scaling[i] << " "; - scaling[i] += dx; - dipole_vector = m_molecule->CalculateDipoleMoment(scaling); - double dipolep = sqrt(dipole_vector[0] * dipole_vector[0] + dipole_vector[1] * dipole_vector[1] + dipole_vector[2] * dipole_vector[2]) * 2.5418; - scaling[i] -= 2 * dx; - dipole_vector = m_molecule->CalculateDipoleMoment(scaling); - double dipolem = sqrt(dipole_vector[0] * dipole_vector[0] + dipole_vector[1] * dipole_vector[1] + dipole_vector[2] * dipole_vector[2]) * 2.5418; - - grad[i] = (std::abs(dipolep - dipole) - std::abs(dipolem - dipole)) / (2.0 * dx); - scaling[i] += dx; } - // if(std::abs(fx) < std::abs(m_smaller)) - // std::cout << std::endl; - m_smaller = std::abs(fx); - m_parameter = x; - return fx; - } - Vector Parameter() const { return m_parameter; } - void setMolecule(const Molecule* molecule) - { - m_molecule = molecule; + return 0; } + int no_parameter; + int no_points; + std::vector m_conformers; - double m_dipole; - double m_smaller = 1; + int inputs() const { return no_parameter; } + int values() const { return no_points; } +}; -private: - int m_atoms = 0; - Vector m_parameter; - const Molecule* m_molecule; +struct OptDipoleFunctorNumericalDiff : Eigen::NumericalDiff { }; -inline std::pair> OptimiseScaling(const Molecule* molecule, double dipole, double initial, double threshold, int maxiter) +inline Vector OptimiseDipoleScaling(const std::vector& conformers, Vector scaling) { - Vector parameter(molecule->AtomCount()); - for (int i = 0; i < molecule->AtomCount(); ++i) - parameter(i) = initial; - - Vector old_param = parameter; - // std::cout << parameter.transpose() << std::endl; - - LBFGSParam param; - param.epsilon = 1e-5; - LBFGSSolver solver(param); - LBFGSDipoleInterface fun(parameter.size()); - fun.m_dipole = dipole * 2.5418; - fun.setMolecule(molecule); - int iteration = 0; - // std::cout << parameter.transpose() << std::endl; - double fx; - int converged = solver.InitializeSingleSteps(fun, parameter, fx); - bool loop = true; - for (iteration = 1; iteration <= maxiter && fx > threshold && loop; ++iteration) { - try { - solver.SingleStep(fun, parameter, fx); - - } catch (const std::logic_error& error_result) { - loop = false; - } catch (const std::runtime_error& error_result) { - loop = false; + + OptDipoleFunctor functor(6,conformers.size()); + functor.m_conformers = conformers; + 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? + lm.parameters.maxfev = config["LevMar_MaxFEv"].toDouble(); //max number of function evaluations + lm.parameters.xtol = config["LevMar_Xtol"].toDouble(); //tolerance for the norm of the solution vector + lm.parameters.ftol = config["LevMar_Ftol"].toDouble(); //tolerance for the norm of the vector function + lm.parameters.gtol = config["LevMar_Gtol"].toDouble(); // tolerance for the norm of the gradient of the error vector + lm.parameters.epsfcn = config["LevMar_epsfcn"].toDouble(); //error precision + */ + + Eigen::LevenbergMarquardtSpace::Status status = lm.minimizeInit(scaling); + + 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) + break; + + old_param = scaling; + } + + return scaling; + +} + + +inline Matrix 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){ + 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); } - std::cout << "Iteration: " << iteration << " Difference: " << fx << std::endl; } - std::vector scaling(parameter.size()); - for (int i = 0; i < scaling.size(); ++i) { - scaling[i] = parameter(i); - std::cout << scaling[i] << " "; + + 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); + } } - auto dipole_vector = molecule->CalculateDipoleMoment(scaling); - dipole = sqrt(dipole_vector[0] * dipole_vector[0] + dipole_vector[1] * dipole_vector[1] + dipole_vector[2] * dipole_vector[2]); - std::cout << std::endl; - return std::pair>(dipole, scaling); -} + + + Matrix Theta(para_size,1); + + Theta = FTF.inverse() * FTy; + + + //inv(F.t@F)@(F.t@y); + return Theta; +} \ No newline at end of file diff --git a/src/capabilities/simplemd.cpp b/src/capabilities/simplemd.cpp index c862e55..ce7f178 100644 --- a/src/capabilities/simplemd.cpp +++ b/src/capabilities/simplemd.cpp @@ -1339,7 +1339,7 @@ double SimpleMD::CleanEnergy(double* grad) double Energy = interface.CalculateEnergy(true); interface.getGradient(grad); if (m_dipole) { - std::vector dipole = interface.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])); } @@ -1353,7 +1353,7 @@ double SimpleMD::FastEnergy(double* grad) double Energy = m_interface->CalculateEnergy(true); m_interface->getGradient(grad); if (m_dipole) { - std::vector dipole = m_interface->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])); } diff --git a/src/core/energycalculator.cpp b/src/core/energycalculator.cpp index 1238b2e..4286641 100644 --- a/src/core/energycalculator.cpp +++ b/src/core/energycalculator.cpp @@ -30,6 +30,7 @@ namespace fs = std::filesystem; #endif +#include #include #include "forcefieldgenerator.h" @@ -52,7 +53,7 @@ EnergyCalculator::EnergyCalculator(const std::string& method, const json& contro return std::vector{}; }; m_dipole = []() { - return std::vector{}; + return Position{}; }; m_bonds = []() { return std::vector>{ {} }; @@ -74,7 +75,12 @@ EnergyCalculator::EnergyCalculator(const std::string& method, const json& contro return this->m_tblite->Charges(); }; m_dipole = [this]() { - return this->m_tblite->Dipole(); + Position dipole; + dipole(0) = this->m_tblite->Dipole()[0]; + dipole(1) = this->m_tblite->Dipole()[1]; + dipole(2) = this->m_tblite->Dipole()[2]; + + return dipole; }; m_bonds = [this]() { return this->m_tblite->BondOrders(); @@ -94,7 +100,12 @@ EnergyCalculator::EnergyCalculator(const std::string& method, const json& contro return this->m_xtb->Charges(); }; m_dipole = [this]() { - return this->m_xtb->Dipole(); + Position dipole; + dipole(0) = this->m_xtb->Dipole()[0]; + dipole(1) = this->m_xtb->Dipole()[1]; + dipole(2) = this->m_xtb->Dipole()[2]; + + return dipole; }; m_bonds = [this]() { return this->m_xtb->BondOrders(); @@ -439,7 +450,7 @@ std::vector EnergyCalculator::Charges() const return m_charges(); } -std::vector EnergyCalculator::Dipole() const +Position EnergyCalculator::Dipole() const { return m_dipole(); } diff --git a/src/core/energycalculator.h b/src/core/energycalculator.h index c9f8cdc..0414a99 100644 --- a/src/core/energycalculator.h +++ b/src/core/energycalculator.h @@ -115,7 +115,7 @@ class EnergyCalculator { } std::vector Charges() const; - std::vector Dipole() const; + Position Dipole() const; std::vector> BondOrders() const; @@ -168,7 +168,8 @@ class EnergyCalculator { StringList m_d3_methods = { "d3" }; StringList m_d4_methods = { "d4" }; std::function m_ecengine; - std::function()> m_charges, m_dipole; + std::function()> m_charges; + std::function m_dipole; std::function>()> m_bonds; json m_parameter; std::string m_method, m_param_file; diff --git a/src/core/molecule.cpp b/src/core/molecule.cpp index 2635e44..05481b1 100644 --- a/src/core/molecule.cpp +++ b/src/core/molecule.cpp @@ -52,6 +52,8 @@ Molecule::Molecule(const Molecule& other) { m_geometry = other.m_geometry; m_charge = other.m_charge; + m_charges = other.m_charges; + m_dipole = other.m_dipole; m_fragments = other.m_fragments; m_atoms = other.m_atoms; m_name = other.m_name; @@ -76,6 +78,8 @@ Molecule::Molecule(const Molecule* other) { m_geometry = other->m_geometry; m_charge = other->m_charge; + m_charges = other->m_charges; + m_dipole = other->m_dipole; m_fragments = other->m_fragments; m_atoms = other->m_atoms; m_name = other->m_name; @@ -869,7 +873,7 @@ Position Molecule::MassCentroid(bool protons, int fragment) const Position pos = { 0, 0, 0 }; double mass = 0.0; for (int i = 0; i < m_atoms.size(); ++i) { - pos += Atom(i).second; + pos += Elements::AtomicMass[Atom(i).first] * Atom(i).second; mass += Elements::AtomicMass[Atom(i).first]; } pos /= mass; @@ -895,17 +899,18 @@ Eigen::Vector3d Molecule::COM(bool protons, int fragment) } std::vector Molecule::CalculateDipoleMoments(const std::vector& scaling) const -{ +{//calc classic dipole moment of the system 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; @@ -916,8 +921,9 @@ std::vector Molecule::CalculateDipoleMoments(const std::vector pos(0) /= mass; pos(1) /= mass; pos(2) /= mass; + //calc dipole moment with scalar for (int i : m_fragments[f]) { - double scale = 3; + double scale = 1; if (scaling.size() > i) scale = scaling[i]; dipole(0) += m_charges[i] * (m_geometry(i, 0) - pos(0)) * scale; @@ -931,8 +937,8 @@ std::vector Molecule::CalculateDipoleMoments(const std::vector return dipole_moments; } -Position Molecule::CalculateDipoleMoment(const std::vector& scaling) const -{ +Position Molecule::CalculateDipoleMoment(const Vector& scaling) const +{ //dec and init double mass = 0; Position pos = { 0, 0, 0 }, dipole = { 0, 0, 0 }; @@ -940,18 +946,12 @@ Position Molecule::CalculateDipoleMoment(const std::vector& scaling) con std::cout << "No partial charges available" << std::endl; return dipole; } + //calc center of mass + pos = MassCentroid(); + + //calc of the dipole moment with scalar for (int i = 0; i < m_geometry.rows(); ++i) { - 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); - } - pos(0) /= mass; - pos(1) /= mass; - pos(2) /= mass; - for (int i = 0; i < m_geometry.rows(); ++i) { - double scale = 3; + double scale = 1; if (scaling.size() > i) scale = scaling[i]; dipole(0) += m_charges[i] * (m_geometry(i, 0) - pos(0)) * scale; @@ -1088,6 +1088,21 @@ void Molecule::appendXYZFile(const std::string& filename) const input.close(); } +void Molecule::appendDipoleFile(const std::string& filename) const +{ + std::string output; + output += fmt::format("{}\n", AtomCount()); + output += "Dipole: " + fmt::format("{:f} {:f} {:f}\n", m_dipole[0], m_dipole[1], m_dipole[2]); + for (int i = 0; i < AtomCount(); ++i) { + output += fmt::format("{} {:f} {:f} {:f} {:f}\n", Elements::ElementAbbr[m_atoms[i]].c_str(), m_geometry(i, 0), m_geometry(i, 1), m_geometry(i, 2), m_charges[i]); + } + std::ofstream input; + input.open(filename, std::ios_base::app); + //std::cout << output << std::endl; + input << output; + input.close(); +} + std::string Molecule::XYZString() const { std::string output; @@ -1468,3 +1483,18 @@ std::vector Molecule::GetBox() const box.push_back(z_max - z_min); return box; } + +Geometry Molecule::ChargeDistribution() const +{ + 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]; + } + return point_charge; +} diff --git a/src/core/molecule.h b/src/core/molecule.h index b0cede4..409f218 100644 --- a/src/core/molecule.h +++ b/src/core/molecule.h @@ -1,7 +1,7 @@ /* * * Copyright (C) 2019 - 2022 Conrad Hübler - * + * 2024 Gerd Gehrisch * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -110,6 +110,9 @@ class Molecule double CalculateDistance(int i, int j) const; std::pair GyrationRadius(bool hydrogen = true, int fragment = -1); + /*! \brief Methode to get the geometry of the molecule as array of vectors + * + */ Geometry getGeometry(const IntPair& pair, bool protons = true) const; Geometry getGeometry(std::vector atoms, bool protons = true) const; Geometry getGeometryByFragment(int fragment, bool protons = true) const; @@ -123,11 +126,30 @@ class Molecule bool setGeometryByFragment(const Geometry& geometry, int fragment, bool protons = true); Position Centroid(bool hydrogen = true, int fragment = -1) const; + + /*! \brief Method to calc the center of Mass + * + */ Position MassCentroid(bool hydrogen = true, int fragment = -1) const; Eigen::Vector3d COM(bool hydrogen = true, int fragment = -1); + /*! \brief Methode to get number of atoms + * + * @return size of the atoms + */ inline std::size_t AtomCount() const { return m_atoms.size(); } + + /*! \brief Methode to get array of all the atoms + * + * @return array of the atomnumber + */ std::vector Atoms() const { return m_atoms; } + + /*! \brief Methode to get atom number and XYZ from index + * + * @param i: index of the atom + * @return pair of atom number and the xyz position + */ std::pair Atom(int i) const; void writeXYZFile(const std::string& filename) const; @@ -138,11 +160,23 @@ class Molecule void appendXYZFile(const std::string& filename) const; inline void appendXYZFile() const { appendXYZFile(Name() + ".xyz"); } + void appendDipoleFile(const std::string& filename) const; + inline void appendDipoleFile() const { appendDipoleFile(Name() + ".dip"); } + std::string XYZString() const; std::string XYZString(const std::vector &order) const; + /*! \brief Methode to calculate the dipole moments of single molecules + * + */ std::vector CalculateDipoleMoments(const std::vector& scaling = std::vector()) const; - Position CalculateDipoleMoment(const std::vector& scaling = 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; + + Geometry ChargeDistribution() const; std::vector BoundHydrogens(int atom, double scaling = 1.5) const; std::map> getConnectivtiy(double scaling = 1.5, int latest = -1) const; @@ -162,7 +196,16 @@ class Molecule inline std::string Name() const { return m_name; } + /*! \brief Methode to get the atom name with position + * + * Input i is the number of the atom, + * Output is a string as in .xyz file + * */ std::string Atom2String(int i) const; + + /*! \brief Methode to get the header of the xyz file + * + * */ std::string Header() const; void CalculateRotationalConstants(); @@ -180,6 +223,9 @@ class Molecule Matrix HydrogenBondMatrix(int f1, int f2); void writeXYZFragments(const std::string& basename) const; + /*! no use at the moment + * + */ int Check() const; inline void setSpin(int spin) { m_spin = spin; } @@ -203,6 +249,9 @@ class Molecule return m_persistentImage; } + /*! Methode to translate the coord to the centroid + * + */ void Center(bool mass = false); std::pair DistanceMatrix() const; @@ -213,8 +262,15 @@ class Molecule void setPartialCharges(const std::vector& charges) { m_charges = charges; } + inline std::vector getPartialCharges() const { return m_charges; } + + void setDipole(const Position& dipole) {m_dipole = dipole; } + + inline Position getDipole() const { return m_dipole; } + inline std::vector> Bonds() const { return m_bonds; } + private: void ParseString(const std::string& internal, std::vector& elements); @@ -234,6 +290,7 @@ class Molecule void InitialiseEmptyGeometry(int atoms); int m_charge = 0, m_spin = 0; + Position m_dipole; Geometry m_geometry; std::vector m_atoms; std::vector m_charges; diff --git a/src/main.cpp b/src/main.cpp index 8351bf1..cd15f0d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,10 +42,11 @@ #include "src/capabilities/optimiser/OptimiseDipoleScaling.h" -#include -#include #include +#include #include +#include +#include #include #ifdef C17 @@ -176,15 +177,15 @@ int main(int argc, char **argv) { << "-centroid * Calculate centroid of specific atoms/fragments *" << std::endl; exit(1); } - if(argc >= 2) + else { json controller = CLI2Json(argc, argv); if(strcmp(argv[1], "-rmsd") == 0) { - if (argc < 2) { - std::cerr << "Please use curcuma for rmsd calcultion as follows\ncurcuma -rmsd A.xyz B.xyz" << std::endl; - std::cerr << "Please use curcuma for rmsd calcultion as follows\ncurcuma -rmsd AB.xyz" << std::endl; + if (argc < 3) { + std::cerr << "Please use curcuma for rmsd calculation as follows\ncurcuma -rmsd A.xyz B.xyz" << std::endl; + std::cerr << "Please use curcuma for rmsd calculation as follows\ncurcuma -rmsd AB.xyz" << std::endl; std::cerr << "Additonal arguments are:" << std::endl; std::cerr << "-reorder **** Force reordering of structure!" << std::endl; @@ -235,6 +236,7 @@ int main(int argc, char **argv) { std::cout << Tools::Vector2String(driver->ReorderRules()) << std::endl; delete driver; exit(0); + } else if (strcmp(argv[1], "-dock") == 0) { if (argc < 4) { std::cerr << "Please use curcuma for docking as follows\ncurcuma -dock -host A.xyz -guest B.xyz -Step_x 10 -Step_y 10 -Step_z 10" << std::endl; @@ -242,13 +244,14 @@ int main(int argc, char **argv) { } Docking* docking = new Docking(controller, false); - if (docking->Initialise() == false) { + if (!docking->Initialise()) { docking->printError(); return 0; } docking->start(); + } else if (strcmp(argv[1], "-hbonds") == 0) { - if(argc != 6) + if(argc < 6) { std::cerr << "Please use curcuma for hydrogen bond analysis as follows\ncurcuma -hbonds A.xyz index_donor index_proton index_acceptor" << std::endl; return -1; @@ -260,12 +263,12 @@ int main(int argc, char **argv) { if (std::string(argv[1]).find("-hbonds") != std::string::npos) { Distance(mol, argv); } - } else { + } else { mol.print_geom(); std::cout << std::endl << std::endl; std::cout << mol.getGeometry() << std::endl; - } + } } } else if (strcmp(argv[1], "-confscan") == 0) { if (argc < 3) { @@ -287,6 +290,7 @@ int main(int argc, char **argv) { scan->setFileName(argv[2]); scan->start(); return 0; + } else if (strcmp(argv[1], "-confstat") == 0) { if (argc < 3) { std::cerr << "Please use curcuma for conformation statistics as follows\ncurcuma -confstat conffile.xyz" << std::endl; @@ -297,24 +301,26 @@ int main(int argc, char **argv) { stat->setFileName(argv[2]); stat->start(); return 0; + } else if (strcmp(argv[1], "-led") == 0) { - if (argc < 2) { + if (argc < 3) { std::cerr << "Please use curcuma for fragment assignment as follows:\ncurcuma -led input.xyz" << std::endl; return 0; } Molecule mol1 = Files::LoadFile(argv[2]); - if (mol1.Atoms().size()) + if (!mol1.Atoms().empty()) mol1.printFragmente(); + } else if (strcmp(argv[1], "-hmap") == 0) { - if (argc < 2) { + if (argc < 3) { std::cerr << "Please use curcuma for hydrogen bond mapping as follows:\ncurcuma -hmap trajectory.xyz" << std::endl; return 0; } std::vector> pairs, elements; - if (argc >= 3) { + if (argc > 3) { for (std::size_t i = 3; i < argc; ++i) { if (strcmp(argv[i], "-pair") == 0) { if (i + 2 < argc) { @@ -322,12 +328,12 @@ int main(int argc, char **argv) { int first = std::stoi(argv[i + 1]) - 1; int second = std::stoi(argv[i + 2]) - 1; ++i; - pairs.push_back(std::pair(first, second)); + pairs.emplace_back(first, second); } else { int first = Elements::String2Element(argv[i + 1]); int second = Elements::String2Element(argv[i + 2]); ++i; - elements.push_back(std::pair(first, second)); + elements.emplace_back(first, second); } } } @@ -340,7 +346,7 @@ int main(int argc, char **argv) { if (Tools::isInt(numbers[0]) && Tools::isInt(numbers[1])) { int first = std::stoi(numbers[0]) - 1; int second = std::stoi(numbers[1]) - 1; - pairs.push_back(std::pair(first, second)); + pairs.emplace_back(first, second); } } } @@ -357,6 +363,7 @@ int main(int argc, char **argv) { mapper.addElementPair(pair); mapper.FindPairs(); + } else if (strcmp(argv[1], "-nci") == 0) { if (argc < 4) { std::cerr << "Please use curcuma to post-process two RDG vs rho plots from NCIPLOT as follows:\ncurcuma -nci file1.dat file2.dat" << std::endl; @@ -373,7 +380,7 @@ int main(int argc, char **argv) { analyse.start(); } else if (strcmp(argv[1], "-opt") == 0) { - if (argc < 2) { + if (argc < 3) { std::cerr << "Please use curcuma for optimisation as follows:\ncurcuma -opt input.xyz" << std::endl; return 0; } @@ -381,8 +388,9 @@ int main(int argc, char **argv) { opt.setFileName(argv[2]); opt.start(); return 0; + } else if (strcmp(argv[1], "-sp") == 0) { - if (argc < 2) { + if (argc < 3) { std::cerr << "Please use curcuma for energy calculation as follows:\ncurcuma -opt input.xyz" << std::endl; return 0; } @@ -393,6 +401,7 @@ int main(int argc, char **argv) { opt.setFileName(argv[2]); opt.start(); return 0; + } else if (strcmp(argv[1], "-block") == 0) { if (argc < 3) { std::cerr << "Please use curcuma to split a file with many structures (trajectories) into several smaller:\ncurcuma block input.xyz X" << std::endl; @@ -421,8 +430,9 @@ int main(int argc, char **argv) { } return 0; + } else if (strcmp(argv[1], "-md") == 0) { - if (argc < 2) { + if (argc < 3) { std::cerr << "Please use curcuma for molecular dynamics simulation as follows:\ncurcuma -md input.xyz" << std::endl; return 0; } @@ -439,8 +449,9 @@ int main(int argc, char **argv) { */ md.Initialise(); md.start(); + } else if (strcmp(argv[1], "-confsearch") == 0) { - if (argc < 2) { + if (argc < 3) { std::cerr << "Please use curcuma for conformational search as follows:\ncurcuma -confsearch input.xyz" << std::endl; return 0; } @@ -448,8 +459,9 @@ int main(int argc, char **argv) { ConfSearch confsearch(controller, false); confsearch.setFile(argv[2]); confsearch.start(); + } else if (strcmp(argv[1], "-rmsdtraj") == 0) { - if (argc <= 2) { + if (argc < 3) { std::cerr << "Please use curcuma for rmsd analysis of trajectories as follows:\ncurcuma -rmsdtraj input.xyz" << std::endl; std::cerr << "Additonal arguments are:" << std::endl; std::cerr << "-write **** Write unique conformers!" << std::endl; @@ -488,6 +500,7 @@ int main(int argc, char **argv) { nebdock->setProtonTransfer(pt); nebdock->Prepare(); delete nebdock; + } else if (strcmp(argv[1], "-centroid") == 0) { if (argc < 3) { std::cerr << "Please use curcuma for centroid calculation of user definable fragments:\ncurcuma -centroid first.xyz" << std::endl; @@ -508,7 +521,7 @@ int main(int argc, char **argv) { std::cout << i << " "; std::cout << std::endl; } - if (frag_list.size() && atom_list.size()) { + if (!frag_list.empty() && !atom_list.empty()) { std::cout << "Having both, fragments and atoms, added is for now mutale exclusive. Might be changed someday ..."; exit(1); } @@ -541,7 +554,7 @@ int main(int argc, char **argv) { } } */ - if (frag_list.size()) { + if (!frag_list.empty()) { std::cout << "Using fragment of atoms :"; for (int atom : frag_list) std::cout << atom + 1 << " "; @@ -553,7 +566,7 @@ int main(int argc, char **argv) { FileIterator file(argv[2]); while (!file.AtEnd()) { Molecule mol = file.Next(); - if (frag_list.size()) { + if (!frag_list.empty()) { result_file << GeometryTools::Centroid(mol.getGeometry(frag_list)).transpose() << std::endl; std::cout << mol.getGeometry(frag_list) << std::endl; } else { @@ -562,7 +575,7 @@ int main(int argc, char **argv) { } } } - if (atom_list.size()) { + if (!atom_list.empty()) { std::ofstream result_file; result_file.open("centroids.dat"); FileIterator file(argv[2]); @@ -574,6 +587,7 @@ int main(int argc, char **argv) { result_file << GeometryTools::Centroid(mol.getGeometry(atom_list)).transpose() << std::endl; } } + } else if (strcmp(argv[1], "-split") == 0) { if (argc < 3) { std::cerr << "Please use curcuma to split supramolecular structures as follows:\ncurcuma -split molecule.xyz" << std::endl; @@ -787,14 +801,14 @@ int main(int argc, char **argv) { input << r.first << " " << r.second << std::endl; } input.close(); - std::cout << "Writing Persitance diagram as " + outfile + "_" + std::to_string(index) + ".PD" << std::endl; + std::cout << "Writing Persistence diagram as " + outfile + "_" + std::to_string(index) + ".PD" << std::endl; input.open(outfile + "_" + std::to_string(index) + ".PD", std::ios::out); input << diagram.generateImage(l); input.close(); } diagram.setDistanceMatrix(vector); { - std::cout << "Writing Persitance Image (EN scaled bond topology) as " + outfile + "_" + std::to_string(index) + ".PI" << std::endl; + std::cout << "Writing Persistence Image (EN scaled bond topology) as " + outfile + "_" + std::to_string(index) + ".PI" << std::endl; auto l = diagram.generateTriples(); input.open(outfile + "_" + std::to_string(index) + ".PI", std::ios::out); input << diagram.generateImage(l); @@ -890,12 +904,17 @@ int main(int argc, char **argv) { count++; } } else if (strcmp(argv[1], "-dipole") == 0) { + if (argc < 3) { + 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; + double target = 0, threshold = 1e-1, initial = 3, dx = 5e-1; //dec bool target_set = false; int maxiter = 10; - json blob = controller["dipole"]; + json blob = controller["dipole"]; //declare blob as json, if (blob.contains("target")) { target = blob["target"]; target_set = true; @@ -909,36 +928,108 @@ int main(int argc, char **argv) { if (blob.contains("maxiter")) { maxiter = blob["maxiter"]; } + if (blob.contains("dx")) { + dx = blob["dx"]; + } - while (!file.AtEnd()) { - Molecule mol = file.Next(); - EnergyCalculator interface("gfn2", blob); - interface.setMolecule(mol); - interface.CalculateEnergy(false, true); - mol.setPartialCharges(interface.Charges()); - std::vector dipole_moment = interface.Dipole(); - if (!target_set) - target = sqrt(dipole_moment[0] * dipole_moment[0] + dipole_moment[1] * dipole_moment[1] + dipole_moment[2] * dipole_moment[2]); - std::cout << "Target dipole moment: " << target << std::endl; - auto dipoles = mol.CalculateDipoleMoments(); + /*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;*/ + + + 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 - << std::endl - << "Dipole momement for single molecule " << dipole[0] << " " << dipole[1] << " " << dipole[2] << " : " << sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]) * 2.5418 << std::endl; - } - auto dipole = mol.CalculateDipoleMoment(); + << "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 - << std::endl - << "Dipole momement for whole structure " << dipole[0] << " " << dipole[1] << " " << dipole[2] << " : " << sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]) * 2.5418 << 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 = OptimiseScaling(&mol, target, initial, threshold, maxiter); - std::cout << "Final dipole moment " << result.first * 2.5418 << std::endl; - std::cout << "Final dipole moment " << result.first << 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; - for (auto i : result.second) - std::cout << i << " "; + 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" << std::endl; + + Matrix Theta(mol.AtomCount(),1); + Theta = DipoleScalingCalculation(conformers); + std::cout << "Analytic-Scaler:\n" << Theta << "\n" << std::endl; + + } else { bool centered = false; for (std::size_t i = 2; i < argc; ++i) {