source: src/Actions/FragmentationAction/AddSelectedAtomsAsFragmentAction.cpp

Candidate_v1.7.1 stable v1.7.1
Last change on this file was dce5a3, checked in by Frederik Heber <frederik.heber@…>, 6 weeks ago

Adds AddSelectedAtomsAsFragmentAction.

  • this action allows calculating the energy of an entire molecule without relying on BOSSANOVA/fragmentation. This allows to compute small molecules which are not saturated other well-captured by the fragmentation scheme.
  • DOC: Adds entry in userguide.
  • TEST: Adds regresssion test case.
  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2025 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 * AddSelectedAtomsAsFragmentAction.cpp
25 *
26 * Created on: Nov 20, 2025
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 "Atom/atom.hpp"
38#include "CodePatterns/IteratorAdaptors.hpp"
39#include "CodePatterns/Log.hpp"
40#include "Descriptors/AtomSelectionDescriptor.hpp"
41#include "Descriptors/MoleculeIdDescriptor.hpp"
42#include "Fragmentation/AdaptivityMap.hpp"
43#include "Fragmentation/Exporters/ExportGraph_ToAtomFragments.hpp"
44#include "Fragmentation/Exporters/ExportGraph_ToFiles.hpp"
45#include "Fragmentation/Exporters/ExportGraph_ToJobs.hpp"
46#include "Fragmentation/Exporters/SaturatedBond.hpp"
47#include "Fragmentation/Exporters/SaturatedFragment.hpp"
48#include "Fragmentation/Exporters/SaturationDistanceMaximizer.hpp"
49#include "Fragmentation/Fragmentation.hpp"
50#include "Fragmentation/Graph.hpp"
51#include "Fragmentation/HydrogenSaturation_enum.hpp"
52#include "Fragmentation/Interfragmenter.hpp"
53#include "Fragmentation/KeySetsContainer.hpp"
54#include "Fragmentation/Summation/Containers/FragmentationResultContainer.hpp"
55#include "Graph/AdjacencyList.hpp"
56#include "Graph/BondGraph.hpp"
57#include "Graph/CyclicStructureAnalysis.hpp"
58#include "Graph/DepthFirstSearchAnalysis.hpp"
59#include "Helpers/defs.hpp"
60#include "molecule.hpp"
61#include "World.hpp"
62
63#include <boost/shared_ptr.hpp>
64#include <boost/filesystem.hpp>
65#include <algorithm>
66#include <iostream>
67#include <map>
68#include <string>
69#include <vector>
70
71#include "Actions/FragmentationAction/AddSelectedAtomsAsFragmentAction.hpp"
72
73using namespace MoleCuilder;
74
75// and construct the stuff
76#include "AddSelectedAtomsAsFragmentAction.def"
77#include "Action_impl_pre.hpp"
78/** =========== define the function ====================== */
79ActionState::ptr FragmentationAddSelectedAtomsAsFragmentAction::performCall() {
80 clock_t start,end;
81 int ExitFlag = -1;
82 World &world = World::getInstance();
83
84 // inform about used parameters
85 LOG(0, "STATUS: Adding currently selected atoms as one fragment ");
86 if (params.types.get().size() != 0)
87 LOG(0, "STATUS: Fragment files begin with "
88 << params.prefix.get() << " and are stored as: "
89 << params.types.get() << "." << std::endl);
90
91 // check for selected atoms
92 if (world.beginAtomSelection() == world.endAtomSelection()) {
93 STATUS("There are no atoms selected for storing as a single fragment.");
94 return Action::failure;
95 }
96
97 // go through all atoms, note down their molecules and group them
98 typedef std::multimap<const molecule *, atom *> clusters_t;
99 typedef std::vector<atomId_t> atomids_t;
100 atomids_t atomids;
101 clusters_t clusters;
102 for (World::AtomSelectionConstIterator iter = world.beginAtomSelection();
103 iter != world.endAtomSelection(); ++iter) {
104 clusters.insert( std::make_pair(iter->second->getMolecule(), iter->second) );
105 atomids.push_back(iter->second->getId());
106 }
107 {
108 std::vector<const molecule *> molecules;
109 molecules.insert( molecules.end(), MapKeyIterator<clusters_t::const_iterator>(clusters.begin()),
110 MapKeyIterator<clusters_t::const_iterator>(clusters.end()) );
111 molecules.erase( std::unique(molecules.begin(), molecules.end()), molecules.end() );
112 LOG(1, "INFO: There are " << molecules.size() << " molecules among the selected atoms to consider.");
113 }
114
115 // go through all keys (i.e. all molecules)
116 clusters_t::const_iterator advanceiter;
117 Graph TotalGraph;
118 int keysetcounter = 0;
119 for (clusters_t::const_iterator iter = clusters.begin();
120 iter != clusters.end();
121 iter = advanceiter) {
122 // get iterator to past last atom in this molecule
123 const molecule * mol = iter->first;
124 advanceiter = clusters.upper_bound(mol);
125
126 /**
127 * The "cluster" sorts the atoms into one set per molecule (from lower_bound to upper_bound
128 * as \a *mol is same key for all these atoms).
129 * Hence, we just need to convert this set of atoms into a KeySet and turn it into a Graph.
130 */
131 KeySet mols_atomids;
132 std::transform(iter, advanceiter, std::inserter(mols_atomids, mols_atomids.end()),
133 boost::bind( &atom::getId,
134 boost::bind( &clusters_t::value_type::second, _1 ))
135 );
136 Graph MoleculeGraph;
137 MoleculeGraph.insert( make_pair(mols_atomids, NumberValuePair(1, 1.)) );
138
139 if (TotalGraph.empty()) {
140 TotalGraph = MoleculeGraph;
141 keysetcounter = TotalGraph.size();
142 } else
143 TotalGraph.InsertGraph(MoleculeGraph, keysetcounter);
144
145 }
146 LOG(0, "STATUS: There are " << TotalGraph.size() << " fragments.");
147
148 {
149 // remove OrderAtSite file
150 std::string line;
151 std::ofstream file;
152 line = params.prefix.get() + ORDERATSITEFILE;
153 file.open(line.c_str(), std::ofstream::out | std::ofstream::trunc);
154 file << "";
155 file.close();
156 }
157
158 // store graph internally
159 AtomFragmentsMap &atomfragments = AtomFragmentsMap::getInstance();
160 atomfragments.clear();
161 atomfragments.insert(TotalGraph);
162
163 // store keysets to file
164 {
165 TotalGraph.StoreKeySetFile(params.prefix.get());
166 }
167
168 {
169 const enum HydrogenSaturation saturation = DontSaturate;
170 const enum HydrogenTreatment treatment = IncludeHydrogen;
171 const SaturatedFragment::GlobalSaturationPositions_t empty_globalsaturationpositions;
172 if (params.types.get().size() != 0) {
173 // store molecule's fragment to file
174 ExportGraph_ToFiles exporter(TotalGraph, treatment, saturation, empty_globalsaturationpositions);
175 exporter.setPrefix(params.prefix.get());
176 exporter.setOutputTypes(params.types.get());
177 if (!exporter())
178 return Action::failure;
179 } else {
180 // store molecule's fragment in FragmentJobQueue
181 ExportGraph_ToJobs exporter(TotalGraph, treatment, saturation, empty_globalsaturationpositions);
182 exporter.setLevel(params.level.get());
183 exporter.setMaximumMeshWidth(params.max_meshwidth.get());
184 if (!exporter())
185 return Action::failure;
186 }
187 // add full keysets to present keysets in AtomFragmentsMap
188 ExportGraph_ToAtomFragments exporter(TotalGraph, treatment, saturation, empty_globalsaturationpositions);
189 if (!exporter())
190 return Action::failure;
191 }
192 if (!AtomFragmentsMap::getInstance().checkCompleteness()) {
193 ELOG(0, "Something went wrong with placing keysets in AtomFragmentsMap.");
194 return Action::failure;
195 }
196
197 // store Adjacency to file
198 {
199 std::string filename = params.prefix.get() + ADJACENCYFILE;
200 std::ofstream AdjacencyFile;
201 AdjacencyFile.open(filename.c_str(), ios::out);
202 AdjacencyList adjacency(atomids);
203 adjacency.StoreToFile(AdjacencyFile);
204 AdjacencyFile.close();
205 }
206
207 return Action::success;
208}
209
210ActionState::ptr FragmentationAddSelectedAtomsAsFragmentAction::performUndo(ActionState::ptr _state) {
211 return Action::success;
212}
213
214ActionState::ptr FragmentationAddSelectedAtomsAsFragmentAction::performRedo(ActionState::ptr _state){
215 return Action::success;
216}
217
218bool FragmentationAddSelectedAtomsAsFragmentAction::canUndo() {
219 return true;
220}
221
222bool FragmentationAddSelectedAtomsAsFragmentAction::shouldUndo() {
223 return true;
224}
225/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.