From 25e321f92deb1a7bbcfc214a9ccdddc6b77fe5b3 Mon Sep 17 00:00:00 2001 From: Gerd Gehrisch Date: Fri, 15 Mar 2024 10:42:52 +0100 Subject: [PATCH 1/6] init Signed-off-by: Gerd Gehrisch --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index ae22700..2ab940d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ /* * * Copyright (C) 2019 - 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 From e578365b28368bce00d1c47f77fd7df27e76a16b Mon Sep 17 00:00:00 2001 From: Gerd Gehrisch Date: Thu, 4 Apr 2024 17:36:08 +0200 Subject: [PATCH 2/6] Some Changes, add Documentary and bug fixes --- CMakeLists.txt | 4 +- .../optimiser/OptimiseDipoleScaling.h | 4 +- src/core/energycalculator.cpp | 1 + src/core/molecule.cpp | 4 +- src/core/molecule.h | 17 ++- src/main.cpp | 122 +++++++++++------- 6 files changed, 102 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbaf67c..8e59a38 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/optimiser/OptimiseDipoleScaling.h b/src/capabilities/optimiser/OptimiseDipoleScaling.h index d7929bd..b77cd56 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 diff --git a/src/core/energycalculator.cpp b/src/core/energycalculator.cpp index 1238b2e..4d56841 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" diff --git a/src/core/molecule.cpp b/src/core/molecule.cpp index f1704b3..2a67c70 100644 --- a/src/core/molecule.cpp +++ b/src/core/molecule.cpp @@ -895,7 +895,7 @@ 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()) { @@ -906,6 +906,7 @@ std::vector Molecule::CalculateDipoleMoments(const std::vector 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,6 +917,7 @@ 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; if (scaling.size() > i) diff --git a/src/core/molecule.h b/src/core/molecule.h index b0cede4..aa978e9 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; @@ -141,7 +144,14 @@ class Molecule 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; + + /*! \brief Methode to calculate the dipole moments of whole structure + * + */ Position CalculateDipoleMoment(const std::vector& scaling = std::vector()) const; std::vector BoundHydrogens(int atom, double scaling = 1.5) const; @@ -162,6 +172,11 @@ 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; std::string Header() const; diff --git a/src/main.cpp b/src/main.cpp index 8351bf1..9726538 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,16 @@ 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]); - double target = 0, threshold = 1e-1, initial = 3; + double target = 0, threshold = 1e-1, initial = 3; //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; @@ -910,35 +928,51 @@ int main(int argc, char **argv) { maxiter = blob["maxiter"]; } - 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) + while (!file.AtEnd()) { // calculation and output dipole moment + Molecule mol = file.Next(); // load Molecule? + EnergyCalculator interface("gfn2", blob); // calc Energy with gfn2? + 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 + auto charges = interface.Charges(); //dec and init charges + + std::cout << "Charges of the atoms: " << std::endl; + + for (int i = 0; i < charges.size(); ++i ){ // Output partial charges from gfn2-xtb methode + std::cout << mol.Atom2String(i); + std::cout << "Charge: " << charges[i] << "\n"; + } + std::cout << std::endl; + + std::vector dipole_moment = interface.Dipole(); // get dipole moment from gfn2-xtb methode + + if (!target_set) // calc target if not 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 << "Target dipole moment: " << target << std::endl; // abs value of the dipole moment + auto dipoles = mol.CalculateDipoleMoments();//calc Dipole for every Molecule + 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; + << "Dipole moment for single molecule x,y,z:abs " << 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(); + auto dipole = mol.CalculateDipoleMoment();//calc Dipole for whole system 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 " << dipole[0] << " " << dipole[1] << " " << dipole[2] << " : " << sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]) * 2.5418 << 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 * 2.5418 << std::endl; std::cout << "Final dipole moment " << result.first << std::endl; for (auto i : result.second) std::cout << i << " "; std::cout << std::endl; } + } else { bool centered = false; for (std::size_t i = 2; i < argc; ++i) { From cae160453cfcc30660f69d6e72dbac4d218832bc Mon Sep 17 00:00:00 2001 From: Gerd Gehrisch Date: Thu, 11 Apr 2024 17:25:24 +0200 Subject: [PATCH 3/6] Some Changes in OptimiseDipoleScaling --- src/capabilities/curcumaopt.cpp | 4 +- .../optimiser/OptimiseDipoleScaling.h | 49 +++++++------ src/capabilities/simplemd.cpp | 4 +- src/core/energycalculator.cpp | 11 ++- src/core/energycalculator.h | 5 +- src/core/molecule.cpp | 10 +-- src/core/molecule.h | 24 ++++++- src/main.cpp | 69 +++++++++++++------ 8 files changed, 120 insertions(+), 56 deletions(-) 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 b77cd56..a9159d6 100644 --- a/src/capabilities/optimiser/OptimiseDipoleScaling.h +++ b/src/capabilities/optimiser/OptimiseDipoleScaling.h @@ -43,38 +43,38 @@ using namespace LBFGSpp; class LBFGSDipoleInterface { public: - LBFGSDipoleInterface(int n_) + explicit LBFGSDipoleInterface(int n_) { } double operator()(const VectorXd& x, VectorXd& grad) { - double fx = 0.0; - double dx = 5e-1; + double fx; + double dx = m_dx; std::vector scaling(x.size()); for (int i = 0; i < scaling.size(); ++i) { scaling[i] = x(i); } 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); + auto dipole = dipole_vector.norm(); + fx = std::abs((m_dipole.norm() - dipole_vector.norm())); // 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] << " "; + 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; + double dipolep = dipole_vector.norm(); 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; + double dipolem = dipole_vector.norm(); 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); + std::cout << std::endl; + // m_smaller = std::abs(fx); m_parameter = x; return fx; } @@ -85,8 +85,8 @@ class LBFGSDipoleInterface { m_molecule = molecule; } - double m_dipole; - double m_smaller = 1; + Position m_dipole; + double m_dx = 5e-1; private: int m_atoms = 0; @@ -94,20 +94,21 @@ class LBFGSDipoleInterface { const Molecule* m_molecule; }; -inline std::pair> OptimiseScaling(const Molecule* molecule, double dipole, double initial, double threshold, int maxiter) +inline std::pair> OptimiseScaling(const Molecule* molecule, Position dipole, double initial, double threshold, int maxiter, double dx) { - Vector parameter(molecule->AtomCount()); + Vector parameter(molecule->AtomCount()); //dec parameter as array and init size of parameter to size of atoms for (int i = 0; i < molecule->AtomCount(); ++i) - parameter(i) = initial; + parameter(i) = initial; //init every parameter as initial - Vector old_param = parameter; + //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.m_dipole = dipole; + fun.m_dx = dx; fun.setMolecule(molecule); int iteration = 0; // std::cout << parameter.transpose() << std::endl; @@ -115,14 +116,20 @@ inline std::pair> OptimiseScaling(const Molecule* mo int converged = solver.InitializeSingleSteps(fun, parameter, fx); for (iteration = 1; iteration <= maxiter && fx > threshold; ++iteration) { - solver.SingleStep(fun, parameter, fx); - std::cout << "Iteration: " << iteration << " Difference: " << fx << std::endl; + try { + solver.SingleStep(fun, parameter, fx); + std::cout << "Iteration: " << iteration << " Difference: " << fx << std::endl; + } + catch (const std::logic_error& e) { + std::cerr << e.what(); + } + } std::vector scaling(parameter.size()); for (int i = 0; i < scaling.size(); ++i) scaling[i] = parameter(i); 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]); + dipole = dipole_vector; - return std::pair>(dipole, scaling); + return std::pair>(dipole, scaling); } diff --git a/src/capabilities/simplemd.cpp b/src/capabilities/simplemd.cpp index 4162330..55a70d0 100644 --- a/src/capabilities/simplemd.cpp +++ b/src/capabilities/simplemd.cpp @@ -1248,7 +1248,7 @@ double SimpleMD::CleanEnergy(const double* coord, 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])); } @@ -1262,7 +1262,7 @@ double SimpleMD::FastEnergy(const double* coord, 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 4d56841..1cb9983 100644 --- a/src/core/energycalculator.cpp +++ b/src/core/energycalculator.cpp @@ -53,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>{ {} }; @@ -75,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(); @@ -440,7 +445,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 2a67c70..cd6c6ad 100644 --- a/src/core/molecule.cpp +++ b/src/core/molecule.cpp @@ -902,7 +902,7 @@ std::vector Molecule::CalculateDipoleMoments(const std::vector std::cout << "No partial charges available" << std::endl; return dipole_moments; } - + //calc center od 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; @@ -919,7 +919,7 @@ std::vector Molecule::CalculateDipoleMoments(const std::vector 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; @@ -934,7 +934,7 @@ std::vector Molecule::CalculateDipoleMoments(const std::vector } Position Molecule::CalculateDipoleMoment(const std::vector& scaling) const -{ +{ //dec and init double mass = 0; Position pos = { 0, 0, 0 }, dipole = { 0, 0, 0 }; @@ -942,6 +942,7 @@ Position Molecule::CalculateDipoleMoment(const std::vector& scaling) con std::cout << "No partial charges available" << std::endl; return dipole; } + //calc center of mass for (int i = 0; i < m_geometry.rows(); ++i) { double m = Elements::AtomicMass[m_atoms[i]]; mass += m; @@ -952,8 +953,9 @@ Position Molecule::CalculateDipoleMoment(const std::vector& scaling) con pos(0) /= mass; pos(1) /= mass; pos(2) /= mass; + //calc of the dipole moment with scalar 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; diff --git a/src/core/molecule.h b/src/core/molecule.h index aa978e9..2985aa4 100644 --- a/src/core/molecule.h +++ b/src/core/molecule.h @@ -129,8 +129,23 @@ class Molecule 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 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; @@ -150,7 +165,7 @@ class Molecule std::vector CalculateDipoleMoments(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 std::vector& scaling = std::vector()) const; @@ -178,6 +193,10 @@ class Molecule * 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(); @@ -195,6 +214,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; } diff --git a/src/main.cpp b/src/main.cpp index 9726538..cf3858f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -909,8 +909,9 @@ int main(int argc, char **argv) { return 0; } FileIterator file(argv[2]); + Position target_dipole; - double target = 0, threshold = 1e-1, initial = 3; //dec + 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, @@ -927,50 +928,76 @@ int main(int argc, char **argv) { if (blob.contains("maxiter")) { maxiter = blob["maxiter"]; } + if (blob.contains("dx")) { + dx = blob["dx"]; + } + + std::cout << "Parameter: " << "\n" + << "target " << target << "\n" + << "threshold " << threshold << "\n" + << "initial " << initial << "\n" + << "maxiter " << maxiter << "\n" + << "dx " << dx << "\n" + << std::endl; while (!file.AtEnd()) { // calculation and output dipole moment - Molecule mol = file.Next(); // load Molecule? - EnergyCalculator interface("gfn2", blob); // calc Energy with gfn2? + Molecule mol = file.Next(); // load Molecule + 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 + mol.setPartialCharges(interface.Charges()); // calc Partial Charges and give it to mol auto charges = interface.Charges(); //dec and init charges - std::cout << "Charges of the atoms: " << std::endl; + std::cout << "Charges of the atoms [e]: " << std::endl; for (int i = 0; i < charges.size(); ++i ){ // Output partial charges from gfn2-xtb methode - std::cout << mol.Atom2String(i); - std::cout << "Charge: " << charges[i] << "\n"; + std::cout << mol.Atom2String(i).substr(0,1); + std::cout << i+1 << ": "; + std::cout << charges[i] << "\n"; } std::cout << std::endl; - std::vector dipole_moment = interface.Dipole(); // get dipole moment from gfn2-xtb methode + auto dipole_moment = interface.Dipole(); // get dipole moment from gfn2-xtb methode - if (!target_set) // calc target if not set + if (!target_set) { // calc target if not set target = sqrt(dipole_moment[0] * dipole_moment[0] + dipole_moment[1] * dipole_moment[1] + dipole_moment[2] * dipole_moment[2]); + target_dipole = dipole_moment; + } + std::cout << "Target dipole moment [eA? or ea?]: " << target << std::endl; // abs value of the dipole moment - std::cout << "Target dipole moment: " << target << std::endl; // abs value of the dipole moment - auto dipoles = mol.CalculateDipoleMoments();//calc Dipole for every Molecule - + auto dipoles = mol.CalculateDipoleMoments();//calc Dipole for every Molecule with partial charges for (const auto& dipole : dipoles) { std::cout << std::endl - << std::endl - << "Dipole moment for single molecule x,y,z:abs " << 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 single molecule [eA]" //<< 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();//calc Dipole for whole system + auto dipole = mol.CalculateDipoleMoment();//calc Dipole for whole system with partial charges std::cout << std::endl - << std::endl - << "Dipole moment 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[0] << " " << dipole[1] << " " << dipole[2] + << " : " << sqrt(dipole[0] * dipole[0] + dipole[1] * dipole[1] + dipole[2] * dipole[2]) * 2.5418 << std::endl; std::cout << std::endl; - auto result = OptimiseScaling(&mol, target, initial, threshold, maxiter); + auto result = OptimiseScaling(&mol, target_dipole, initial, threshold, maxiter, dx); // std::cout << "Final dipole moment " << result.first * 2.5418 << std::endl; - std::cout << "Final dipole moment " << result.first << std::endl; + std::cout << "Final dipole moment [eA]" << result.first[0] << " " << result.first[1] << " " << result.first[2] << " " << std::endl; + std::cout << "Norm: " << result.first.norm() << 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(); } } else { From ad30ea7a858d0031a243db640f5b3ca27b267ed0 Mon Sep 17 00:00:00 2001 From: Gerd Gehrisch Date: Tue, 14 May 2024 00:06:43 +0200 Subject: [PATCH 4/6] Implement Levenberg-Marquardt for Dipole Optimization --- .../optimiser/OptimiseDipoleScaling.h | 160 ++++++++---------- src/core/molecule.cpp | 33 ++-- src/core/molecule.h | 21 ++- src/main.cpp | 63 ++++--- 4 files changed, 156 insertions(+), 121 deletions(-) diff --git a/src/capabilities/optimiser/OptimiseDipoleScaling.h b/src/capabilities/optimiser/OptimiseDipoleScaling.h index a9159d6..3562c6c 100644 --- a/src/capabilities/optimiser/OptimiseDipoleScaling.h +++ b/src/capabilities/optimiser/OptimiseDipoleScaling.h @@ -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,104 +33,91 @@ #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: - explicit 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() {} + inline int operator()(const Vector& scaling, Eigen::VectorXd& fvec) const { - double fx; - double dx = m_dx; - 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); - auto dipole = dipole_vector.norm(); - fx = std::abs((m_dipole.norm() - dipole_vector.norm())); - // 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 = dipole_vector.norm(); - scaling[i] -= 2 * dx; - dipole_vector = m_molecule->CalculateDipoleMoment(scaling); - double dipolem = dipole_vector.norm(); - - 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; + return 0; } + int no_parameter; + int no_points; + std::vector m_conformers; - Vector Parameter() const { return m_parameter; } - void setMolecule(const Molecule* molecule) - { - m_molecule = molecule; - } - - Position m_dipole; - double m_dx = 5e-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, Position dipole, double initial, double threshold, int maxiter, double dx) +inline Vector OptimiseDipoleScaling(const std::vector& conformers, Vector scaling) { - Vector parameter(molecule->AtomCount()); //dec parameter as array and init size of parameter to size of atoms - for (int i = 0; i < molecule->AtomCount(); ++i) - parameter(i) = initial; //init every parameter as 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; - fun.m_dx = dx; - fun.setMolecule(molecule); - int iteration = 0; - // std::cout << parameter.transpose() << std::endl; - double fx; - int converged = solver.InitializeSingleSteps(fun, parameter, fx); - - for (iteration = 1; iteration <= maxiter && fx > threshold; ++iteration) { - try { - solver.SingleStep(fun, parameter, fx); - std::cout << "Iteration: " << iteration << " Difference: " << fx << std::endl; - } - catch (const std::logic_error& e) { - std::cerr << e.what(); - } + 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; } - std::vector scaling(parameter.size()); - for (int i = 0; i < scaling.size(); ++i) - scaling[i] = parameter(i); - auto dipole_vector = molecule->CalculateDipoleMoment(scaling); - dipole = dipole_vector; - - return std::pair>(dipole, scaling); -} + + return scaling; +} \ No newline at end of file diff --git a/src/core/molecule.cpp b/src/core/molecule.cpp index cd6c6ad..9f99eaf 100644 --- a/src/core/molecule.cpp +++ b/src/core/molecule.cpp @@ -869,7 +869,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; @@ -902,7 +902,7 @@ std::vector Molecule::CalculateDipoleMoments(const std::vector std::cout << "No partial charges available" << std::endl; return dipole_moments; } - //calc center od mass and dipole for every fragment + //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; @@ -933,7 +933,7 @@ 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; @@ -943,16 +943,8 @@ Position Molecule::CalculateDipoleMoment(const std::vector& scaling) con return dipole; } //calc center of mass - 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; + pos = MassCentroid(); + //calc of the dipole moment with scalar for (int i = 0; i < m_geometry.rows(); ++i) { double scale = 1; @@ -1079,6 +1071,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; diff --git a/src/core/molecule.h b/src/core/molecule.h index 2985aa4..826a1f5 100644 --- a/src/core/molecule.h +++ b/src/core/molecule.h @@ -126,6 +126,10 @@ 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); @@ -141,7 +145,7 @@ class Molecule */ std::vector Atoms() const { return m_atoms; } - /*! \brief Methode to get atom number from index + /*! \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 @@ -156,6 +160,9 @@ 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; @@ -167,7 +174,7 @@ class Molecule /*! \brief Methode to calculate the dipole moments of whole structure * unit of dipol is electron times angstron */ - Position CalculateDipoleMoment(const std::vector& scaling = std::vector()) const; + Position CalculateDipoleMoment(const Vector& scaling = Vector()) const; std::vector BoundHydrogens(int atom, double scaling = 1.5) const; std::map> getConnectivtiy(double scaling = 1.5, int latest = -1) const; @@ -240,6 +247,9 @@ class Molecule return m_persistentImage; } + /*! Methode to translate the coord to the centroid + * + */ void Center(bool mass = false); std::pair DistanceMatrix() const; @@ -250,6 +260,12 @@ 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: @@ -271,6 +287,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 cf3858f..03c688f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -932,57 +932,78 @@ int main(int argc, char **argv) { dx = blob["dx"]; } - std::cout << "Parameter: " << "\n" + /*std::cout << "Parameter: " << "\n" << "target " << target << "\n" << "threshold " << threshold << "\n" << "initial " << initial << "\n" << "maxiter " << maxiter << "\n" << "dx " << dx << "\n" - << std::endl; + << std::endl;*/ + std::vector conformers; + Molecule mol; while (!file.AtEnd()) { // calculation and output dipole moment Molecule mol = file.Next(); // load Molecule + mol.Center(true); 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()); + auto dipole_moment = interface.Dipole(); // get dipole moment from gfn2-xtb methode - std::cout << "Charges of the atoms [e]: " << std::endl; + 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::cout << mol.Atom2String(i).substr(0,1); - std::cout << i+1 << ": "; + std::string col = mol.Atom2String(i); + col.pop_back(); + std::cout << col; + std::cout << " "; std::cout << charges[i] << "\n"; } std::cout << std::endl; - auto dipole_moment = interface.Dipole(); // get dipole moment from gfn2-xtb methode + conformers.push_back(mol); + + + - if (!target_set) { // calc target if not set - target = sqrt(dipole_moment[0] * dipole_moment[0] + dipole_moment[1] * dipole_moment[1] + dipole_moment[2] * dipole_moment[2]); + //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? or ea?]: " << target << std::endl; // abs value of the 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[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 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[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_dipole, initial, threshold, maxiter, dx); - // std::cout << "Final dipole moment " << result.first * 2.5418 << std::endl; - std::cout << "Final dipole moment [eA]" << result.first[0] << " " << result.first[1] << " " << result.first[2] << " " << std::endl; - std::cout << "Norm: " << result.first.norm() << 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; @@ -997,8 +1018,10 @@ int main(int argc, char **argv) { << result.second[i] << "\n"; } std::cout << std::endl; - std::cout << "mean of scalar: " << sum / mol.AtomCount(); + std::cout << "mean of scalar: " << sum / mol.AtomCount();*/ } + Vector scaling = Vector::Zero(mol.AtomCount()); + OptimiseDipoleScaling(conformers, scaling); } else { bool centered = false; From 8331d9b38feb35d5874b0d7b39e00bad3193f9b1 Mon Sep 17 00:00:00 2001 From: Gerd Gehrisch Date: Thu, 30 May 2024 17:05:27 +0200 Subject: [PATCH 5/6] Implement multi linear regression for dipole calculation --- .../optimiser/OptimiseDipoleScaling.h | 39 ++++++++++++++++++- src/core/molecule.cpp | 19 +++++++++ src/core/molecule.h | 3 ++ src/main.cpp | 39 +++++++++++-------- 4 files changed, 83 insertions(+), 17 deletions(-) diff --git a/src/capabilities/optimiser/OptimiseDipoleScaling.h b/src/capabilities/optimiser/OptimiseDipoleScaling.h index 3562c6c..84d3c84 100644 --- a/src/capabilities/optimiser/OptimiseDipoleScaling.h +++ b/src/capabilities/optimiser/OptimiseDipoleScaling.h @@ -67,12 +67,13 @@ struct OptDipoleFunctor : TFunctor { , no_points(values) { } - inline ~OptDipoleFunctor() {} + inline ~OptDipoleFunctor() = default; inline int operator()(const Vector& scaling, Eigen::VectorXd& fvec) const { for (int i = 0; i < m_conformers.size(); ++i ){ auto conf = m_conformers.at(i); fvec(i) = (conf.getDipole() - conf.CalculateDipoleMoment(scaling)).norm() ; + } return 0; @@ -120,4 +121,40 @@ inline Vector OptimiseDipoleScaling(const std::vector& conformers, Vec } 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); + } + } + + 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); + return Theta; } \ No newline at end of file diff --git a/src/core/molecule.cpp b/src/core/molecule.cpp index 9f99eaf..34b813e 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; @@ -1466,3 +1470,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 826a1f5..409f218 100644 --- a/src/core/molecule.h +++ b/src/core/molecule.h @@ -176,6 +176,8 @@ class Molecule */ 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; @@ -268,6 +270,7 @@ class Molecule inline std::vector> Bonds() const { return m_bonds; } + private: void ParseString(const std::string& internal, std::vector& elements); diff --git a/src/main.cpp b/src/main.cpp index 03c688f..cd15f0d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -943,17 +943,17 @@ int main(int argc, char **argv) { std::vector conformers; Molecule mol; while (!file.AtEnd()) { // calculation and output dipole moment - Molecule mol = file.Next(); // load Molecule - mol.Center(true); + 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()); - auto dipole_moment = interface.Dipole(); // get dipole moment from gfn2-xtb methode + 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" + /*std::cout << mol.AtomCount() << "\n" << "Dipole " << dipole_moment[0] << " " << dipole_moment[1] << " " @@ -967,14 +967,11 @@ int main(int argc, char **argv) { std::cout << " "; std::cout << charges[i] << "\n"; } - std::cout << std::endl; - - conformers.push_back(mol); + std::cout << std::endl;*/ - - - //mol.appendDipoleFile(file.Basename() + ".dip"); + conformers.push_back(mol); + mol.appendDipoleFile(file.Basename() + ".dip"); /*if (!target_set) { // calc target if not set @@ -992,15 +989,16 @@ int main(int argc, char **argv) { << "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 + }*/ + /*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; @@ -1020,8 +1018,17 @@ int main(int argc, char **argv) { std::cout << std::endl; std::cout << "mean of scalar: " << sum / mol.AtomCount();*/ } - Vector scaling = Vector::Zero(mol.AtomCount()); - OptimiseDipoleScaling(conformers, scaling); + 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; From e10cec3c866bae584e7175f631762e8e44421c3c Mon Sep 17 00:00:00 2001 From: Gerd Gehrisch Date: Fri, 21 Jun 2024 11:17:49 +0200 Subject: [PATCH 6/6] Fix Pull request --- src/core/energycalculator.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/energycalculator.cpp b/src/core/energycalculator.cpp index 1cb9983..4286641 100644 --- a/src/core/energycalculator.cpp +++ b/src/core/energycalculator.cpp @@ -100,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();