/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2021 Frederik Heber. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder 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 2 of the License, or * (at your option) any later version. * * MoleCuilder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * StabilityEvaluator.cpp * * Created on: Apr 18, 2021 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif //#include "CodePatterns/MemDebug.hpp" #include "CodePatterns/Log.hpp" #include "StabilityEvaluator.hpp" #include #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "Fragmentation/Homology/HomologyContainer.hpp" #include "Fragmentation/Homology/HomologyGraph.hpp" #include "Fragmentation/KeySet.hpp" #include "molecule.hpp" #include "World.hpp" StabilityEvaluator::StabilityEvaluator(const molecule * _mol): mol(_mol), container(World::getInstance().getHomologies()) { } /** * Graph discovery to find the keyset if we exclude a bond from a connected * graph. */ KeySet discoverKeySetsFromAtomOnExcludedBond( const atom *_startatom, const bond::ptr &_bond) { KeySet result; std::stack atoms_to_visit; atoms_to_visit.push(_startatom); result.insert(_startatom->getId()); while (!atoms_to_visit.empty()) { const atom * Walker = atoms_to_visit.top(); atoms_to_visit.pop(); const BondList& ListOfBonds = Walker->getListOfBonds(); for (BondList::const_iterator bonditer = ListOfBonds.begin(); bonditer != ListOfBonds.end(); ++bonditer) { // exclude the given bond if (*bonditer != _bond) { const atom * OtherAtom = (*bonditer)->GetOtherAtom(Walker); // have we seen the atom already_ if (result.count(OtherAtom->getId()) == 0) { result.insert(OtherAtom->getId()); atoms_to_visit.push(OtherAtom); } } } } return result; } template void insertInto(const N &item, G &_list) { std::pair inserter = _list.insert(std::make_pair(item, (size_t)1)); if (!inserter.second) { ++(inserter.first->second); } } std::string getFormulaFrom(const HomologyGraph &graph) { Formula formula; for (HomologyGraph::nodes_t::const_iterator iter = graph.getNodes().begin(); iter != graph.getNodes().end(); ++iter) for (size_t i=0;i<(*iter).second;++i) formula += (*iter).first.getAtomicNumber(); return formula.toString(); } HomologyGraph createHydrogenMoleculeHomologyGraph() { HomologyGraph::nodes_t nodes; // two hydrogen atoms const FragmentNode node = FragmentNode((atomicNumber_t)1, 1); insertInto(node, nodes); insertInto(node, nodes); // one hydrogen bond/edge HomologyGraph::edges_t edges; const FragmentEdge edge = FragmentEdge((atomicNumber_t)1, (atomicNumber_t)1); insertInto(edge, edges); // and return return HomologyGraph(nodes, edges); } StabilityEvaluator::stabilities_t StabilityEvaluator::operator()() const { stabilities_t stabilities; // gather all non-hydrogen bonds of the molecule typedef std::set bondset_t; bondset_t non_hydrogen_bonds; for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) { const BondList& ListOfBonds = (*iter)->getListOfBonds(); for (BondList::const_iterator bonditer = ListOfBonds.begin(); bonditer != ListOfBonds.end(); ++bonditer) { if ((*bonditer)->HydrogenBond == 0) non_hydrogen_bonds.insert(*bonditer ); } } stabilities.reserve(non_hydrogen_bonds.size()); // create homology graph for full molecule const HomologyGraph fullgraph(mol->getAtomIds()); const std::string fullgraph_formula = mol->getFormula().toString(); const HomologyGraph hydrogengraph = createHydrogenMoleculeHomologyGraph(); // get the energy of the educts const double energy_fullgraph = getLowestEnergyFromHomologyContainer(fullgraph); const double energy_hydrogen_molecule = getLowestEnergyFromHomologyContainer(hydrogengraph); // go through every discovered non-hydrogen bond for (bondset_t::iterator bonditer = non_hydrogen_bonds.begin(); bonditer != non_hydrogen_bonds.end(); ++bonditer) { const bond::ptr &bondptr = (*bonditer); // create stability criterion structure to fill StabilityCriterion criterion; criterion.energy_educts = energy_fullgraph + bondptr->getDegree() * energy_hydrogen_molecule; criterion.formula_educt1 = fullgraph_formula; criterion.formula_educt2 = "H"+toString(bondptr->getDegree()*2); // create graphs for each set const HomologyGraph leftgraph( discoverKeySetsFromAtomOnExcludedBond(bondptr->leftatom, *bonditer) ); const HomologyGraph rightgraph( discoverKeySetsFromAtomOnExcludedBond(bondptr->rightatom, *bonditer) ); // look up energy for each graph in the homology container criterion.energy_products = getLowestEnergyFromHomologyContainer(leftgraph) + getLowestEnergyFromHomologyContainer(rightgraph); criterion.formula_product1 = getFormulaFrom(leftgraph); criterion.formula_product2 = getFormulaFrom(rightgraph); criterion.isStable = criterion.energy_educts < criterion.energy_products; stabilities.push_back(criterion); } return stabilities; } double StabilityEvaluator::getLowestEnergyFromHomologyContainer(const HomologyGraph &nodes_graph) const { HomologyContainer::range_t range = container.getHomologousGraphs(nodes_graph); if (range.first == range.second) { // range is empty, the fragment is unknown ELOG(1, "Cannot find fragment graph " << nodes_graph << " ."); return 0.; } else { // list lowest energy const HomologyContainer::const_iterator lowest_contribution_graph = std::min_element(range.first, range.second, HomologyContainer::compareEnergy); const HomologyContainer::const_iterator highest_contribution_graph = std::max_element(range.first, range.second, HomologyContainer::compareEnergy); LOG(2, "INFO: Fragment graph " << nodes_graph << " has energy contributions from " << lowest_contribution_graph->second.fragmentenergy << " Ht till " << highest_contribution_graph->second.fragmentenergy << " Ht, picking lowest."); return lowest_contribution_graph->second.fragmentenergy; } } void createHomologyGraphFromMolecule() { HomologyGraph::nodes_t graph_nodes; HomologyGraph::edges_t graph_edges; } std::ostream& operator<<(std::ostream &ost, const StabilityEvaluator::StabilityCriterion &_stability) { ost << _stability.formula_educt1 << " + " << _stability.formula_educt2 << " (" << _stability.energy_educts << " Ht) < " << _stability.formula_product1 << " + " << _stability.formula_product2 << " (" << _stability.energy_products << " Ht) ? " << _stability.isStable; return ost; }