| [f5ea10] | 1 | /*
 | 
|---|
 | 2 |  * Project: MoleCuilder
 | 
|---|
 | 3 |  * Description: creates and alters molecular systems
 | 
|---|
 | 4 |  * Copyright (C)  2017 Frederik Heber. All rights reserved.
 | 
|---|
 | 5 |  * 
 | 
|---|
 | 6 |  *
 | 
|---|
 | 7 |  *   This file is part of MoleCuilder.
 | 
|---|
 | 8 |  *
 | 
|---|
 | 9 |  *    MoleCuilder is free software: you can redistribute it and/or modify
 | 
|---|
 | 10 |  *    it under the terms of the GNU General Public License as published by
 | 
|---|
 | 11 |  *    the Free Software Foundation, either version 2 of the License, or
 | 
|---|
 | 12 |  *    (at your option) any later version.
 | 
|---|
 | 13 |  *
 | 
|---|
 | 14 |  *    MoleCuilder is distributed in the hope that it will be useful,
 | 
|---|
 | 15 |  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
 | 16 |  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
 | 17 |  *    GNU General Public License for more details.
 | 
|---|
 | 18 |  *
 | 
|---|
 | 19 |  *    You should have received a copy of the GNU General Public License
 | 
|---|
 | 20 |  *    along with MoleCuilder.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
 | 21 |  */
 | 
|---|
 | 22 | 
 | 
|---|
 | 23 | /*
 | 
|---|
 | 24 |  * ChemicalSpaceEvaluator.cpp
 | 
|---|
 | 25 |  *
 | 
|---|
 | 26 |  *  Created on: Sep 26, 2017
 | 
|---|
 | 27 |  *      Author: heber
 | 
|---|
 | 28 |  */
 | 
|---|
 | 29 | 
 | 
|---|
 | 30 | // include config.h
 | 
|---|
 | 31 | #ifdef HAVE_CONFIG_H
 | 
|---|
 | 32 | #include <config.h>
 | 
|---|
 | 33 | #endif
 | 
|---|
 | 34 | 
 | 
|---|
 | 35 | //#include "CodePatterns/MemDebug.hpp"
 | 
|---|
 | 36 | 
 | 
|---|
 | 37 | #include <iostream>
 | 
|---|
| [99c705] | 38 | #include <list>
 | 
|---|
 | 39 | #include <map>
 | 
|---|
| [f5ea10] | 40 | #include <string>
 | 
|---|
 | 41 | #include <vector>
 | 
|---|
 | 42 | 
 | 
|---|
| [99c705] | 43 | #include <boost/graph/copy.hpp>
 | 
|---|
 | 44 | 
 | 
|---|
| [f5ea10] | 45 | #include "CodePatterns/Log.hpp"
 | 
|---|
 | 46 | 
 | 
|---|
 | 47 | #include "Actions/GraphAction/ChemicalSpaceEvaluatorAction.hpp"
 | 
|---|
 | 48 | 
 | 
|---|
 | 49 | #include "Element/element.hpp"
 | 
|---|
 | 50 | #include "Graph/BoostGraphCreator.hpp"
 | 
|---|
 | 51 | #include "Fragmentation/Homology/HomologyContainer.hpp"
 | 
|---|
 | 52 | #include "FunctionApproximation/Extractors.hpp"
 | 
|---|
 | 53 | #include "World.hpp"
 | 
|---|
 | 54 | 
 | 
|---|
 | 55 | #include <boost/graph/adjacency_list.hpp>
 | 
|---|
 | 56 | 
 | 
|---|
 | 57 | using namespace MoleCuilder;
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 | // and construct the stuff
 | 
|---|
 | 60 | #include "ChemicalSpaceEvaluatorAction.def"
 | 
|---|
 | 61 | #include "Action_impl_pre.hpp"
 | 
|---|
 | 62 | /** =========== define the function ====================== */
 | 
|---|
| [99c705] | 63 | template<class map_t, class key_t>
 | 
|---|
 | 64 | static int getElementFromMap(
 | 
|---|
 | 65 |     const map_t &_map,
 | 
|---|
 | 66 |     const key_t &_keyname)
 | 
|---|
 | 67 | {
 | 
|---|
 | 68 |   typename map_t::const_iterator iter = _map.find(_keyname);
 | 
|---|
 | 69 |   ASSERT( iter != _map.end(),
 | 
|---|
 | 70 |       "getElementFromMap() -  cannot find key "+toString(_keyname)+" in map.");
 | 
|---|
 | 71 |   return iter->second;
 | 
|---|
 | 72 | }
 | 
|---|
 | 73 | 
 | 
|---|
 | 74 | typedef std::pair<BoostGraphCreator::Vertex, BoostGraphCreator::Vertex> edge_by_vertices_t;
 | 
|---|
 | 75 | typedef std::map<edge_by_vertices_t, int> edge_valence_t;
 | 
|---|
 | 76 | typedef std::vector<edge_by_vertices_t> edges_t;
 | 
|---|
 | 77 | typedef std::vector<int> degrees_t;
 | 
|---|
 | 78 | typedef std::list< degrees_t > list_of_edge_degrees_t;
 | 
|---|
 | 79 | typedef std::map< unsigned int, int> type_valence_map_t;
 | 
|---|
 | 80 | typedef std::map< edge_by_vertices_t , size_t> edge_index_t;
 | 
|---|
 | 81 | 
 | 
|---|
 | 82 | static int powerset_edge_degree(
 | 
|---|
 | 83 |     list_of_edge_degrees_t &list_of_edge_degrees,
 | 
|---|
 | 84 |     degrees_t ¤t_degrees,
 | 
|---|
 | 85 |     const size_t remaining_edges,
 | 
|---|
 | 86 |     const size_t current_index,
 | 
|---|
 | 87 |     const edges_t &edges,
 | 
|---|
 | 88 |     const edge_valence_t &edge_valence)
 | 
|---|
 | 89 | {
 | 
|---|
 | 90 |   if (remaining_edges == 0) {
 | 
|---|
 | 91 |     list_of_edge_degrees.push_back(current_degrees);
 | 
|---|
 | 92 |     LOG(3, "DEBUG: Adding [" << current_degrees << "] list of degrees.");
 | 
|---|
 | 93 |     return 1;
 | 
|---|
 | 94 |   } else {
 | 
|---|
 | 95 |     size_t no_combinations = 0;
 | 
|---|
 | 96 |     // get valence
 | 
|---|
 | 97 |     const edge_by_vertices_t &e = edges[current_index];
 | 
|---|
 | 98 |     const int current_max_degree = getElementFromMap<
 | 
|---|
 | 99 |         edge_valence_t,
 | 
|---|
 | 100 |         edge_by_vertices_t>(edge_valence, e);
 | 
|---|
 | 101 |     // create all combinations and recurse
 | 
|---|
 | 102 |     for(current_degrees[current_index] = 1;
 | 
|---|
 | 103 |         current_degrees[current_index] <= current_max_degree;
 | 
|---|
 | 104 |         ++current_degrees[current_index]) {
 | 
|---|
 | 105 |       no_combinations += powerset_edge_degree(
 | 
|---|
 | 106 |           list_of_edge_degrees, current_degrees,
 | 
|---|
 | 107 |           remaining_edges-1, current_index+1,
 | 
|---|
 | 108 |           edges, edge_valence);
 | 
|---|
 | 109 |     }
 | 
|---|
 | 110 |     return no_combinations;
 | 
|---|
 | 111 |   }
 | 
|---|
 | 112 | }
 | 
|---|
 | 113 | 
 | 
|---|
 | 114 | static int getValenceForVertex(
 | 
|---|
 | 115 |     const BoostGraphCreator::name_map_t &name_map,
 | 
|---|
 | 116 |     const Extractors::type_index_lookup_t &type_index_lookup,
 | 
|---|
 | 117 |     const type_valence_map_t &type_valence_map,
 | 
|---|
 | 118 |     const BoostGraphCreator::Vertex &v
 | 
|---|
 | 119 |     )
 | 
|---|
 | 120 | {
 | 
|---|
 | 121 |   const atomId_t atomid_v = boost::get(name_map, v);
 | 
|---|
 | 122 |   const Extractors::type_index_lookup_t::left_const_iterator iter_v = type_index_lookup.left.find(atomid_v);
 | 
|---|
 | 123 |   ASSERT( iter_v != type_index_lookup.left.end(),
 | 
|---|
 | 124 |       "getValenceForVertex() - cannot find "+toString(atomid_v));
 | 
|---|
 | 125 |   const unsigned int elementno_v = iter_v->second;
 | 
|---|
 | 126 |   return getElementFromMap<type_valence_map_t, unsigned int>(type_valence_map, elementno_v);
 | 
|---|
 | 127 | }
 | 
|---|
 | 128 | 
 | 
|---|
 | 129 | static edge_by_vertices_t getEdgeByVertices(
 | 
|---|
 | 130 |     const BoostGraphCreator::Vertex& u,
 | 
|---|
 | 131 |     const BoostGraphCreator::Vertex& v)
 | 
|---|
 | 132 | {
 | 
|---|
 | 133 |   if (u < v)
 | 
|---|
 | 134 |     return std::make_pair(u,v);
 | 
|---|
 | 135 |   else
 | 
|---|
 | 136 |     return std::make_pair(v,u);
 | 
|---|
 | 137 | }
 | 
|---|
 | 138 | 
 | 
|---|
 | 139 | static edge_by_vertices_t getEdgeVerticesByEdge(
 | 
|---|
 | 140 |     const BoostGraphCreator::Edge& e,
 | 
|---|
 | 141 |     const BoostGraphCreator::UndirectedGraph &graph)
 | 
|---|
 | 142 | {
 | 
|---|
 | 143 |   const BoostGraphCreator::Vertex u = source(e, graph);
 | 
|---|
 | 144 |   const BoostGraphCreator::Vertex v = source(e, graph);
 | 
|---|
 | 145 |   return getEdgeByVertices(u,v);
 | 
|---|
 | 146 | }
 | 
|---|
 | 147 | 
 | 
|---|
 | 148 | 
 | 
|---|
 | 149 | struct SaturatedGraph
 | 
|---|
 | 150 | {
 | 
|---|
 | 151 |   //!> states whether each node fulfills the octet rule, i.e. has bonds weight by their degree equal to its valence
 | 
|---|
 | 152 |   bool ValencesAllFulfilled;
 | 
|---|
 | 153 |   //!> graph saturated with additional hydrogens
 | 
|---|
 | 154 |   BoostGraphCreator::UndirectedGraph saturated_graph;
 | 
|---|
 | 155 |   //!> type per edge in the graph
 | 
|---|
 | 156 |   Extractors::type_index_lookup_t type_index_lookup;
 | 
|---|
 | 157 | };
 | 
|---|
 | 158 | 
 | 
|---|
 | 159 | template <class graph_type>
 | 
|---|
 | 160 | static SaturatedGraph saturateGraph(
 | 
|---|
 | 161 |     const graph_type &graph,
 | 
|---|
 | 162 |     const Extractors::nodes_t &nodes,
 | 
|---|
 | 163 |     const BoostGraphCreator::name_map_t &name_map,
 | 
|---|
 | 164 |     const Extractors::type_index_lookup_t &type_index_lookup,
 | 
|---|
 | 165 |     const type_valence_map_t &type_valence_map,
 | 
|---|
 | 166 |     const edge_index_t &edge_index,
 | 
|---|
 | 167 |     const edges_t &edges,
 | 
|---|
 | 168 |     const degrees_t °rees
 | 
|---|
 | 169 | )
 | 
|---|
 | 170 | {
 | 
|---|
 | 171 |   SaturatedGraph newgraph;
 | 
|---|
 | 172 |   boost::copy_graph(graph, newgraph.saturated_graph);
 | 
|---|
 | 173 |   newgraph.ValencesAllFulfilled = true;
 | 
|---|
 | 174 | 
 | 
|---|
 | 175 |   // need to translate type_index_lookup as Extractors::createHomologyKey..() only
 | 
|---|
 | 176 |   // looks at the vertex index, not its name. When extracting the subgraph, we
 | 
|---|
 | 177 |   // might extract node #1, but insert it as new node index #0. Therefore, we have
 | 
|---|
 | 178 |   // to translate all indices in the lookup
 | 
|---|
 | 179 |   const Extractors::index_map_t index_map = boost::get(boost::vertex_index, graph);
 | 
|---|
 | 180 |   {
 | 
|---|
 | 181 |     BoostGraphCreator::vertex_iter vp, vpend;
 | 
|---|
 | 182 |     for (boost::tie(vp, vpend) = vertices(graph); vp != vpend; ++vp) {
 | 
|---|
 | 183 |       BoostGraphCreator::Vertex v = *vp;
 | 
|---|
 | 184 |       const atomId_t vindex = boost::get(name_map, v);
 | 
|---|
 | 185 |       Extractors::type_index_lookup_t::left_const_iterator iter = type_index_lookup.left.find(vindex);
 | 
|---|
 | 186 |       if (iter != type_index_lookup.left.end()) {
 | 
|---|
 | 187 |         const Extractors::node_t nodeid = boost::get(index_map, v);
 | 
|---|
 | 188 |         newgraph.type_index_lookup.left.insert( std::make_pair(nodeid, iter->second) );
 | 
|---|
 | 189 |         LOG(4, "DEBUG: Adding type to index lookup for vertex " << iter->first);
 | 
|---|
 | 190 |       }
 | 
|---|
 | 191 |     }
 | 
|---|
 | 192 |   }
 | 
|---|
 | 193 | 
 | 
|---|
 | 194 |   size_t no_nodes = boost::num_vertices(newgraph.saturated_graph);
 | 
|---|
 | 195 |   // step through every node, sum up its degrees
 | 
|---|
 | 196 |   BoostGraphCreator::vertex_iter vp, vpend;
 | 
|---|
 | 197 |   for (boost::tie(vp, vpend) = vertices(graph); vp != vpend; ++vp) {
 | 
|---|
 | 198 |     BoostGraphCreator::Vertex v = *vp;
 | 
|---|
 | 199 |     const atomId_t vindex = boost::get(name_map, v);
 | 
|---|
 | 200 |     LOG(3, "DEBUG: Current vertex is #" << vindex);
 | 
|---|
 | 201 |     const int max_valence = getValenceForVertex(name_map, type_index_lookup, type_valence_map, v);
 | 
|---|
 | 202 |     int total_valence = 0;
 | 
|---|
 | 203 |     typename boost::graph_traits<graph_type>::out_edge_iterator i, end;
 | 
|---|
 | 204 |     for (boost::tie(i, end) = boost::out_edges(v, graph); i != end; ++i) {
 | 
|---|
 | 205 |       const BoostGraphCreator::Edge &e = *i;
 | 
|---|
 | 206 |       const BoostGraphCreator::Vertex e1 = source(e, graph);
 | 
|---|
 | 207 |       const BoostGraphCreator::Vertex e2 = target(e, graph);
 | 
|---|
 | 208 |       const edge_by_vertices_t edge_by_vertices = getEdgeByVertices(e1,e2);
 | 
|---|
 | 209 |       LOG(3, "DEBUG: Current edge is (" << edge_by_vertices << ")");
 | 
|---|
 | 210 |       const size_t index = getElementFromMap<edge_index_t, edge_by_vertices_t>(
 | 
|---|
 | 211 |           edge_index, edge_by_vertices);
 | 
|---|
 | 212 |       ASSERT( index < edges.size(),
 | 
|---|
 | 213 |           "saturateGraph() - index "+toString(index)+" out of range [0, "
 | 
|---|
 | 214 |           +toString(edges.size())+"]");
 | 
|---|
 | 215 |       total_valence += degrees[index];
 | 
|---|
 | 216 |     }
 | 
|---|
 | 217 |     LOG(3, "DEBUG: Vertex #" << vindex << " has total valence of "
 | 
|---|
 | 218 |         << total_valence << " and " << max_valence << " max valence.");
 | 
|---|
 | 219 |     // add hydrogens till valence is depleted
 | 
|---|
 | 220 |     newgraph.ValencesAllFulfilled &= (total_valence <= max_valence);
 | 
|---|
 | 221 |     for (int remaining_valence = total_valence; remaining_valence < max_valence;
 | 
|---|
 | 222 |         ++remaining_valence) {
 | 
|---|
 | 223 |       // add hydrogen node to this node
 | 
|---|
 | 224 |       LOG(4, "DEBUG: Adding node " << no_nodes << " with type " << Extractors::ParticleType_t(1));
 | 
|---|
 | 225 |       newgraph.type_index_lookup.left.insert(
 | 
|---|
 | 226 |           std::make_pair(no_nodes, Extractors::ParticleType_t(1)));
 | 
|---|
 | 227 |       BoostGraphCreator::Vertex h = boost::add_vertex(no_nodes, newgraph.saturated_graph);
 | 
|---|
 | 228 |       ++no_nodes;
 | 
|---|
 | 229 | 
 | 
|---|
 | 230 |       // add edge to hydrogen
 | 
|---|
 | 231 |       std::pair<BoostGraphCreator::Edge, bool> edge_inserter =
 | 
|---|
 | 232 |           boost::add_edge(v, h, newgraph.saturated_graph);
 | 
|---|
 | 233 |     }
 | 
|---|
 | 234 |     LOG(2, "DEBUG: Added " << (max_valence - total_valence)
 | 
|---|
 | 235 |         << " hydrogens to vertex #" << vindex);
 | 
|---|
 | 236 |   }
 | 
|---|
 | 237 | 
 | 
|---|
 | 238 |   return newgraph;
 | 
|---|
 | 239 | }
 | 
|---|
 | 240 | 
 | 
|---|
 | 241 | template <typename graph_t>
 | 
|---|
 | 242 | BoostGraphCreator::UndirectedGraph extractSubgraph(
 | 
|---|
 | 243 |     const graph_t &_graph,
 | 
|---|
 | 244 |     const Extractors::nodes_t &nodes)
 | 
|---|
 | 245 | {
 | 
|---|
 | 246 |   BoostGraphCreator::UndirectedGraph subgraph;
 | 
|---|
 | 247 |   const Extractors::index_map_t index_map = boost::get(boost::vertex_index, _graph);
 | 
|---|
 | 248 | 
 | 
|---|
 | 249 |   // add nodes
 | 
|---|
 | 250 |   BoostGraphCreator::vertex_iter viter, vend;
 | 
|---|
 | 251 |   for (boost::tie(viter, vend) = boost::vertices(_graph); viter != vend; ++viter) {
 | 
|---|
 | 252 |     const size_t nodeid = boost::get(index_map, *viter);
 | 
|---|
 | 253 |     if (nodes.find(nodeid) != nodes.end()) {
 | 
|---|
 | 254 |       boost::add_vertex(*viter, subgraph);
 | 
|---|
 | 255 |       LOG(4, "DEBUG: Adding node " << *viter << " to subgraph.");
 | 
|---|
 | 256 |     }
 | 
|---|
 | 257 |   }
 | 
|---|
 | 258 | 
 | 
|---|
 | 259 |   // add edges
 | 
|---|
 | 260 |   for (boost::tie(viter, vend) = boost::vertices(_graph); viter != vend; ++viter) {
 | 
|---|
 | 261 |     BoostGraphCreator::UndirectedGraph::in_edge_iterator i, end;
 | 
|---|
 | 262 |     for (boost::tie(i, end) = boost::in_edges(boost::vertex(*viter, _graph), _graph);
 | 
|---|
 | 263 |         i != end; ++i) {
 | 
|---|
 | 264 |       const Extractors::node_t sourceindex = boost::get(index_map, boost::source(*i, _graph));
 | 
|---|
 | 265 |       const Extractors::node_t targetindex = boost::get(index_map, boost::target(*i, _graph));
 | 
|---|
 | 266 |       if ((nodes.find(sourceindex) != nodes.end()) && (nodes.find(targetindex) != nodes.end())
 | 
|---|
 | 267 |           && (sourceindex < targetindex)) {
 | 
|---|
 | 268 |         boost::add_edge(sourceindex, targetindex, subgraph);
 | 
|---|
 | 269 |         LOG(4, "DEBUG: Adding edge " << sourceindex << "<->" << targetindex << " to subgraph.");
 | 
|---|
 | 270 |       }
 | 
|---|
 | 271 |     }
 | 
|---|
 | 272 |   }
 | 
|---|
 | 273 | 
 | 
|---|
 | 274 |   return subgraph;
 | 
|---|
 | 275 | }
 | 
|---|
 | 276 | 
 | 
|---|
 | 277 | 
 | 
|---|
| [f5ea10] | 278 | ActionState::ptr GraphChemicalSpaceEvaluatorAction::performCall() {
 | 
|---|
| [99c705] | 279 |   /// 1. create boost::graph from graph6 string
 | 
|---|
| [f5ea10] | 280 |   BoostGraphCreator BGC;
 | 
|---|
 | 281 |   BGC.createFromGraph6String(params.graph_string.get());
 | 
|---|
 | 282 | 
 | 
|---|
 | 283 |   BoostGraphCreator::UndirectedGraph graph = BGC.get();
 | 
|---|
 | 284 | 
 | 
|---|
 | 285 |   Extractors::index_map_t index_map = boost::get(boost::vertex_index, graph);
 | 
|---|
| [99c705] | 286 |   LOG(1, "INFO: We have " << boost::num_vertices(graph) << " nodes in the fragment graph.");
 | 
|---|
| [f5ea10] | 287 | 
 | 
|---|
| [99c705] | 288 |   /// 2. associate type with a node index
 | 
|---|
| [f5ea10] | 289 |   Extractors::type_index_lookup_t type_index_lookup;
 | 
|---|
 | 290 |   std::vector<unsigned int> elementnumbers;
 | 
|---|
 | 291 |   elementnumbers.reserve(params.graph_elements.get().size());
 | 
|---|
| [99c705] | 292 |   size_t i = 0;
 | 
|---|
| [f5ea10] | 293 |   for (std::vector<const element *>::const_iterator iter = params.graph_elements.get().begin();
 | 
|---|
 | 294 |       iter != params.graph_elements.get().end(); ++iter) {
 | 
|---|
 | 295 |     elementnumbers.push_back((*iter)->getAtomicNumber());
 | 
|---|
| [99c705] | 296 |     LOG(3, "DEBUG: Adding [" << i << ", " << elementnumbers.back() << "] type to index lookup.");
 | 
|---|
| [f5ea10] | 297 |     type_index_lookup.left.insert(
 | 
|---|
| [99c705] | 298 |         std::make_pair(i++, Extractors::ParticleType_t(elementnumbers.back())));
 | 
|---|
 | 299 |   }
 | 
|---|
 | 300 |   if (i != boost::num_vertices(graph)) {
 | 
|---|
 | 301 |     ELOG(1, "Not enough elements given.");
 | 
|---|
 | 302 |     return Action::failure;
 | 
|---|
| [f5ea10] | 303 |   }
 | 
|---|
 | 304 | 
 | 
|---|
| [99c705] | 305 |   /// 3a. get range of valence for each node
 | 
|---|
 | 306 |   type_valence_map_t type_valence_map;
 | 
|---|
 | 307 |   for (std::vector<const element *>::const_iterator iter = params.graph_elements.get().begin();
 | 
|---|
 | 308 |       iter != params.graph_elements.get().end(); ++iter) {
 | 
|---|
 | 309 |     if (type_valence_map.count((*iter)->getAtomicNumber()) == 0) {
 | 
|---|
 | 310 |       LOG(3, "DEBUG: Adding [" << (*iter)->getAtomicNumber()
 | 
|---|
 | 311 |           << ", " << (*iter)->getNoValenceOrbitals() << "] type to valence lookup.");
 | 
|---|
 | 312 |       type_valence_map.insert( std::make_pair(
 | 
|---|
 | 313 |           (*iter)->getAtomicNumber(),
 | 
|---|
 | 314 |           (*iter)->getNoValenceOrbitals()) );
 | 
|---|
 | 315 |     }
 | 
|---|
 | 316 |   }
 | 
|---|
 | 317 | 
 | 
|---|
 | 318 |   // get map for retrieving vertex index for a given vertex
 | 
|---|
 | 319 |   const BoostGraphCreator::name_map_t name_map = boost::get(boost::vertex_name, graph);
 | 
|---|
 | 320 | 
 | 
|---|
 | 321 |   /// 3b. generate range of degree for each edge
 | 
|---|
 | 322 |   edge_valence_t edge_valence;
 | 
|---|
 | 323 |   edges_t edges;
 | 
|---|
 | 324 |   edge_index_t edge_index;
 | 
|---|
 | 325 |   edges.reserve(boost::num_edges(graph));
 | 
|---|
 | 326 |   {
 | 
|---|
 | 327 |     size_t index = 0;
 | 
|---|
 | 328 |     BoostGraphCreator::edge_iter i, end;
 | 
|---|
 | 329 |     for (boost::tie(i, end) = boost::edges(graph); i != end; ++i) {
 | 
|---|
 | 330 |       static int MAX_DEGREE = 3;
 | 
|---|
 | 331 |       const BoostGraphCreator::Edge &e = *i;
 | 
|---|
 | 332 |       /// 4a. place all edges into a vector
 | 
|---|
 | 333 |       const BoostGraphCreator::Vertex u = source(e, graph);
 | 
|---|
 | 334 |       const BoostGraphCreator::Vertex v = target(e, graph);
 | 
|---|
 | 335 |       const edge_by_vertices_t edge_by_vertices = getEdgeByVertices(u,v);
 | 
|---|
 | 336 |       edges.push_back(edge_by_vertices);
 | 
|---|
 | 337 |       edge_index.insert( std::make_pair(
 | 
|---|
 | 338 |           edge_by_vertices, index++) );
 | 
|---|
 | 339 |       const int valence_u = getValenceForVertex(name_map, type_index_lookup, type_valence_map, u);
 | 
|---|
 | 340 |       const int valence_v = getValenceForVertex(name_map, type_index_lookup, type_valence_map, v);
 | 
|---|
 | 341 |       const int max_degree = std::max(1,
 | 
|---|
 | 342 |           std::min(
 | 
|---|
 | 343 |               std::min(valence_u, MAX_DEGREE),
 | 
|---|
 | 344 |               std::min(valence_v, MAX_DEGREE)
 | 
|---|
 | 345 |               ));
 | 
|---|
 | 346 |       edge_valence.insert(
 | 
|---|
 | 347 |           std::make_pair(edge_by_vertices, max_degree)
 | 
|---|
 | 348 |           );
 | 
|---|
 | 349 |       LOG(3, "DEBUG: Adding [" << std::make_pair(u,v) << ", "
 | 
|---|
 | 350 |           << max_degree << "] edge to valence lookup.");
 | 
|---|
 | 351 |     }
 | 
|---|
 | 352 |   }
 | 
|---|
 | 353 | 
 | 
|---|
 | 354 |   /// 4. for each graph with type per node and degree per edge set, add hydrogen nodes and edges
 | 
|---|
 | 355 |   // go through powerset over all edges
 | 
|---|
 | 356 | 
 | 
|---|
 | 357 |   /// 4b. have a recursive function that puts together the powerset over all max_degree
 | 
|---|
 | 358 |   list_of_edge_degrees_t list_of_edge_degrees;
 | 
|---|
 | 359 |   size_t no_combinations = 0;
 | 
|---|
 | 360 |   {
 | 
|---|
 | 361 |     size_t remaining_edges = edges.size();
 | 
|---|
 | 362 |     size_t current_index = 0;
 | 
|---|
 | 363 |     degrees_t current_degrees(edges.size(), 0);
 | 
|---|
 | 364 |     no_combinations = powerset_edge_degree(
 | 
|---|
 | 365 |         list_of_edge_degrees, current_degrees,
 | 
|---|
 | 366 |         remaining_edges, current_index,
 | 
|---|
 | 367 |         edges, edge_valence);
 | 
|---|
 | 368 |   }
 | 
|---|
 | 369 |   LOG(1, "INFO: Added " << no_combinations << " graph degree combinations.");
 | 
|---|
 | 370 | 
 | 
|---|
 | 371 |   /// 5. dissect graph into a list of subgraphs
 | 
|---|
 | 372 |   typedef std::vector<BoostGraphCreator::UndirectedGraph> subgraphs_t;
 | 
|---|
 | 373 |   subgraphs_t allsubgraphs;
 | 
|---|
| [f5ea10] | 374 |   const size_t nodes_in_graph = boost::num_vertices(graph);
 | 
|---|
 | 375 |   LOG(2, "DEBUG: There are " << nodes_in_graph << " nodes in the graph.");
 | 
|---|
 | 376 |   Extractors::set_of_nodes_t set_of_nodes;
 | 
|---|
 | 377 |   for (size_t nodeid = 0; nodeid < nodes_in_graph; ++nodeid) {
 | 
|---|
 | 378 |     const size_t &rootindex = nodeid;
 | 
|---|
 | 379 |     LOG(2, "DEBUG: Current root index is " << rootindex);
 | 
|---|
 | 380 | 
 | 
|---|
 | 381 |     /// 5a. from node in graph (with this index) perform BFS till n-1 (#nodes in binding model)
 | 
|---|
 | 382 |     std::vector<size_t> distances(boost::num_vertices(graph));
 | 
|---|
 | 383 |     boost::breadth_first_search(
 | 
|---|
 | 384 |         graph,
 | 
|---|
 | 385 |         boost::vertex(rootindex, graph),
 | 
|---|
 | 386 |         boost::visitor(Extractors::record_distance(&distances[0])));
 | 
|---|
 | 387 |     LOG(3, "DEBUG: BFS discovered the following distances " << distances);
 | 
|---|
 | 388 | 
 | 
|---|
 | 389 |     /// 5b. and store all node in map with distance to root as key
 | 
|---|
 | 390 |     Extractors::nodes_per_level_t nodes_per_level;
 | 
|---|
 | 391 |     for (size_t i=0;i<distances.size();++i) {
 | 
|---|
 | 392 |       nodes_per_level.insert( std::make_pair(Extractors::level_t(distances[i]), Extractors::node_t(i)) );
 | 
|---|
 | 393 |     }
 | 
|---|
 | 394 |     LOG(3, "DEBUG: Nodes per level are " << nodes_per_level);
 | 
|---|
 | 395 | 
 | 
|---|
| [99c705] | 396 |     /// 5c. construct all possible induced connected subgraphs with this map (see fragmentation)
 | 
|---|
| [f5ea10] | 397 |     Extractors::nodes_t nodes;
 | 
|---|
 | 398 |     // rootindex is always contained
 | 
|---|
 | 399 |     nodes.insert( rootindex );
 | 
|---|
 | 400 |     Extractors::level_t level = 0;
 | 
|---|
 | 401 | 
 | 
|---|
| [99c705] | 402 |     for (size_t i=0;i<nodes_in_graph; ++i)
 | 
|---|
 | 403 |       Extractors::generateAllInducedConnectedSubgraphs(
 | 
|---|
 | 404 |           i, level, nodes, set_of_nodes, nodes_per_level, graph, distances, index_map);
 | 
|---|
| [f5ea10] | 405 |     LOG(2, "DEBUG: We have found " << set_of_nodes.size() << " unique induced, connected subgraphs.");
 | 
|---|
 | 406 |   }
 | 
|---|
 | 407 | 
 | 
|---|
| [99c705] | 408 |   typedef std::vector<
 | 
|---|
 | 409 |       std::pair<
 | 
|---|
 | 410 |           BoostGraphCreator::UndirectedGraph,
 | 
|---|
 | 411 |           degrees_t> > graphs_with_degrees_t;
 | 
|---|
 | 412 | 
 | 
|---|
 | 413 |   // 6. for every combination saturate fragments for lookup and energy contribution summation
 | 
|---|
| [f5ea10] | 414 |   const HomologyContainer &container = World::getInstance().getHomologies();
 | 
|---|
| [99c705] | 415 |   for (list_of_edge_degrees_t::const_iterator degrees_iter = list_of_edge_degrees.begin();
 | 
|---|
 | 416 |       degrees_iter != list_of_edge_degrees.end(); ++degrees_iter) {
 | 
|---|
 | 417 |     const degrees_t ¤t_degrees = *degrees_iter;
 | 
|---|
 | 418 | 
 | 
|---|
 | 419 |     // simply sum up the contributions from all fragments for the total energy
 | 
|---|
 | 420 |     // of this particular combination, given the graph, the element for each node,
 | 
|---|
 | 421 |     // and the bond degrees for each edge
 | 
|---|
 | 422 |     double total_energy = 0.;
 | 
|---|
 | 423 | 
 | 
|---|
 | 424 |     // get fragment
 | 
|---|
 | 425 |     for (Extractors::set_of_nodes_t::const_iterator nodesiter = set_of_nodes.begin();
 | 
|---|
 | 426 |         nodesiter != set_of_nodes.end(); ++nodesiter) {
 | 
|---|
 | 427 |       const Extractors::nodes_t ¤t_nodes = *nodesiter;
 | 
|---|
 | 428 |       LOG(2, "DEBUG: Nodes for graph are " << current_nodes);
 | 
|---|
 | 429 | 
 | 
|---|
 | 430 |       // create subgraph
 | 
|---|
 | 431 |       Extractors::UndirectedGraph newgraph = extractSubgraph(graph, current_nodes);
 | 
|---|
 | 432 | 
 | 
|---|
 | 433 |       const BoostGraphCreator::name_map_t new_name_map =
 | 
|---|
 | 434 |           boost::get(boost::vertex_name, newgraph);
 | 
|---|
 | 435 |       {
 | 
|---|
 | 436 |         BoostGraphCreator::vertex_iter viter, vend;
 | 
|---|
 | 437 |         boost::tie(viter, vend) = boost::vertices(newgraph);
 | 
|---|
 | 438 |         for (; viter != vend; ++viter) {
 | 
|---|
 | 439 |           const atomId_t vindex = boost::get(new_name_map, *viter);
 | 
|---|
 | 440 |           LOG(4, "DEBUG: Copied node has index " << vindex);
 | 
|---|
 | 441 |         }
 | 
|---|
 | 442 |       }
 | 
|---|
 | 443 | 
 | 
|---|
 | 444 |       // saturate subgraph: add to nodes, add to type_index_lookup, index_map
 | 
|---|
 | 445 |         // saturate any leftover valence with hydrogen nodes
 | 
|---|
 | 446 |       SaturatedGraph fullgraph =
 | 
|---|
 | 447 |           saturateGraph(newgraph, current_nodes, new_name_map,
 | 
|---|
 | 448 |               type_index_lookup, type_valence_map, edge_index,
 | 
|---|
 | 449 |               edges, current_degrees);
 | 
|---|
 | 450 | 
 | 
|---|
 | 451 |       // don't add if one of the node's valence cannot be fulfilled
 | 
|---|
 | 452 |       if (!fullgraph.ValencesAllFulfilled)
 | 
|---|
 | 453 |         continue;
 | 
|---|
 | 454 | 
 | 
|---|
 | 455 |       const Extractors::index_map_t subgraph_index_map =
 | 
|---|
 | 456 |           boost::get(boost::vertex_index, fullgraph.saturated_graph);
 | 
|---|
 | 457 |       const BoostGraphCreator::name_map_t subgraph_name_map =
 | 
|---|
 | 458 |           boost::get(boost::vertex_name, fullgraph.saturated_graph);
 | 
|---|
 | 459 | 
 | 
|---|
 | 460 |       Extractors::nodes_t saturated_nodes;
 | 
|---|
 | 461 |       BoostGraphCreator::vertex_iter viter, vend;
 | 
|---|
 | 462 |       boost::tie(viter, vend) = boost::vertices(fullgraph.saturated_graph);
 | 
|---|
 | 463 |       for (; viter != vend; ++viter) {
 | 
|---|
 | 464 |         const Extractors::node_t vindex = boost::get(subgraph_index_map, *viter);
 | 
|---|
 | 465 |         LOG(4, "DEBUG: Adding node index " << vindex << " to saturated nodes list.");
 | 
|---|
 | 466 |         saturated_nodes.insert(vindex);
 | 
|---|
 | 467 |       }
 | 
|---|
 | 468 |       /// convert its nodes into a HomologyGraph using the graph and elements (types for index)
 | 
|---|
 | 469 |       const HomologyGraph nodes_graph =
 | 
|---|
 | 470 |           Extractors::createHomologyGraphFromNodes(
 | 
|---|
 | 471 |               saturated_nodes,
 | 
|---|
 | 472 |               fullgraph.type_index_lookup,
 | 
|---|
 | 473 |               fullgraph.saturated_graph,
 | 
|---|
 | 474 |               subgraph_index_map);
 | 
|---|
 | 475 |       LOG(2, "DEBUG: Looking for graph " << nodes_graph);
 | 
|---|
 | 476 | 
 | 
|---|
 | 477 |       /// Query HomologyContainer for this HomologyGraph.
 | 
|---|
 | 478 |       HomologyContainer::range_t range = container.getHomologousGraphs(nodes_graph);
 | 
|---|
 | 479 | 
 | 
|---|
 | 480 |       if (range.first == range.second) {
 | 
|---|
 | 481 |         // range is empty, the fragment is unknown
 | 
|---|
 | 482 |         ELOG(1, "Cannot find fragment graph " << nodes_graph << " to graph " << elementnumbers);
 | 
|---|
 | 483 |       } else {
 | 
|---|
 | 484 |         // list first energy
 | 
|---|
 | 485 |         LOG(1, "Fragment graph " << nodes_graph << " has contribution " << range.first->second.energy);
 | 
|---|
 | 486 |         total_energy += range.first->second.energy;
 | 
|---|
 | 487 |       }
 | 
|---|
| [f5ea10] | 488 |     }
 | 
|---|
| [99c705] | 489 |     LOG(1, "The graph with degrees " << *degrees_iter << " has a total energy of " << total_energy);
 | 
|---|
| [f5ea10] | 490 |   }
 | 
|---|
 | 491 | 
 | 
|---|
 | 492 |   return Action::success;
 | 
|---|
 | 493 | }
 | 
|---|
 | 494 | 
 | 
|---|
 | 495 | ActionState::ptr GraphChemicalSpaceEvaluatorAction::performUndo(ActionState::ptr _state) {
 | 
|---|
 | 496 |   return Action::success;
 | 
|---|
 | 497 | }
 | 
|---|
 | 498 | 
 | 
|---|
 | 499 | ActionState::ptr GraphChemicalSpaceEvaluatorAction::performRedo(ActionState::ptr _state){
 | 
|---|
 | 500 |   return Action::success;
 | 
|---|
 | 501 | }
 | 
|---|
 | 502 | 
 | 
|---|
 | 503 | bool GraphChemicalSpaceEvaluatorAction::canUndo() {
 | 
|---|
 | 504 |   return true;
 | 
|---|
 | 505 | }
 | 
|---|
 | 506 | 
 | 
|---|
 | 507 | bool GraphChemicalSpaceEvaluatorAction::shouldUndo() {
 | 
|---|
 | 508 |   return true;
 | 
|---|
 | 509 | }
 | 
|---|
 | 510 | /** =========== end of function ====================== */
 | 
|---|