source: src/Actions/FragmentationAction/FragmentationAction.cpp@ ac9dc8

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests AutomationFragmentation_failures Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes
Last change on this file since ac9dc8 was 9eb71b3, checked in by Frederik Heber <frederik.heber@…>, 8 years ago

Commented out MemDebug include and Memory::ignore.

  • MemDebug clashes with various allocation operators that use a specific placement in memory. It is so far not possible to wrap new/delete fully. Hence, we stop this effort which so far has forced us to put ever more includes (with clashes) into MemDebug and thereby bloat compilation time.
  • MemDebug does not add that much usefulness which is not also provided by valgrind.
  • Property mode set to 100644
File size: 19.1 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * FragmentationAction.cpp
26 *
27 * Created on: May 9, 2010
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36//#include "CodePatterns/MemDebug.hpp"
37
38#include "Atom/atom.hpp"
39#include "CodePatterns/IteratorAdaptors.hpp"
40#include "CodePatterns/Log.hpp"
41#include "Descriptors/AtomSelectionDescriptor.hpp"
42#include "Descriptors/MoleculeIdDescriptor.hpp"
43#include "Fragmentation/AdaptivityMap.hpp"
44#include "Fragmentation/Exporters/ExportGraph_ToAtomFragments.hpp"
45#include "Fragmentation/Exporters/ExportGraph_ToFiles.hpp"
46#include "Fragmentation/Exporters/ExportGraph_ToJobs.hpp"
47#include "Fragmentation/Exporters/SaturatedBond.hpp"
48#include "Fragmentation/Exporters/SaturatedFragment.hpp"
49#include "Fragmentation/Exporters/SaturationDistanceMaximizer.hpp"
50#include "Fragmentation/Fragmentation.hpp"
51#include "Fragmentation/Graph.hpp"
52#include "Fragmentation/HydrogenSaturation_enum.hpp"
53#include "Fragmentation/Interfragmenter.hpp"
54#include "Fragmentation/KeySetsContainer.hpp"
55#include "Fragmentation/Summation/Containers/FragmentationResultContainer.hpp"
56#include "Graph/AdjacencyList.hpp"
57#include "Graph/BondGraph.hpp"
58#include "Graph/CyclicStructureAnalysis.hpp"
59#include "Graph/DepthFirstSearchAnalysis.hpp"
60#include "Helpers/defs.hpp"
61#include "molecule.hpp"
62#include "World.hpp"
63
64#include <boost/shared_ptr.hpp>
65#include <boost/filesystem.hpp>
66#include <algorithm>
67#include <iostream>
68#include <map>
69#include <string>
70#include <vector>
71
72#include "Actions/FragmentationAction/FragmentationAction.hpp"
73
74using namespace MoleCuilder;
75
76// and construct the stuff
77#include "FragmentationAction.def"
78#include "Action_impl_pre.hpp"
79/** =========== define the function ====================== */
80ActionState::ptr FragmentationFragmentationAction::performCall() {
81 clock_t start,end;
82 int ExitFlag = -1;
83 World &world = World::getInstance();
84
85 // inform about used parameters
86 LOG(0, "STATUS: Fragmenting molecular system with current connection matrix up to "
87 << params.order.get() << " order. ");
88 if (params.types.get().size() != 0)
89 LOG(0, "STATUS: Fragment files begin with "
90 << params.prefix.get() << " and are stored as: "
91 << params.types.get() << "." << std::endl);
92
93 // check for selected atoms
94 if (world.beginAtomSelection() == world.endAtomSelection()) {
95 STATUS("There are no atoms selected for fragmentation.");
96 return Action::failure;
97 }
98
99 // go through all atoms, note down their molecules and group them
100 typedef std::multimap<const molecule *, atom *> clusters_t;
101 typedef std::vector<atomId_t> atomids_t;
102 atomids_t atomids;
103 clusters_t clusters;
104 for (World::AtomSelectionConstIterator iter = world.beginAtomSelection();
105 iter != world.endAtomSelection(); ++iter) {
106 clusters.insert( std::make_pair(iter->second->getMolecule(), iter->second) );
107 atomids.push_back(iter->second->getId());
108 }
109 {
110 std::vector<const molecule *> molecules;
111 molecules.insert( molecules.end(), MapKeyIterator<clusters_t::const_iterator>(clusters.begin()),
112 MapKeyIterator<clusters_t::const_iterator>(clusters.end()) );
113 molecules.erase( std::unique(molecules.begin(), molecules.end()), molecules.end() );
114 LOG(1, "INFO: There are " << molecules.size() << " molecules to consider.");
115 }
116
117 // parse in Adjacency file
118 boost::shared_ptr<AdjacencyList> FileChecker;
119 boost::filesystem::path filename(params.prefix.get() + std::string(ADJACENCYFILE));
120 if (params.ParseStateFiles.get()) {
121 if (boost::filesystem::exists(filename)
122 && boost::filesystem::is_regular_file(filename)) {
123 std::ifstream File;
124 File.open(filename.string().c_str(), ios::out);
125 FileChecker.reset(new AdjacencyList(File));
126 File.close();
127 } else {
128 LOG(1, "INFO: Could not open default adjacency file " << filename.string() << ".");
129 FileChecker.reset(new AdjacencyList);
130 }
131 } else
132 FileChecker.reset(new AdjacencyList);
133
134 // make sure bond degree is correct
135 {
136 BondGraph *BG = World::getInstance().getBondGraph();
137 World::AtomComposite Set = World::getInstance().getAllAtoms(AtomsBySelection());
138 // check whether bond graph is correct
139 if (!BG->checkBondDegree(Set))
140 BG->CorrectBondDegree(Set);
141 else
142 LOG(1, "INFO: Bond degrees all valid, not correcting.");
143 }
144
145 // we parse in the keysets from last time if present
146 Graph StoredGraph;
147 if (params.ParseStateFiles.get()) {
148 StoredGraph.ParseKeySetFile(params.prefix.get());
149 // check parsed graph against the set of atoms
150 {
151 AdaptivityMap *amap = StoredGraph.GraphToAdaptivityMap();
152 bool status = true;
153 for (World::AtomSelectionConstIterator iter = world.beginAtomSelection();
154 iter != world.endAtomSelection(); ++iter) {
155 const atomId_t atomid = iter->second->getId();
156 // skip hydrogens in check if saturation is turned on
157 if ((iter->second->getType()->getAtomicNumber() != 1)
158 || (!params.DoSaturation.get())) {
159 if (amap->count(atomid) == 0) {
160 ELOG(1, "Atom #" << atomid << " not contained in KeySet file. ");
161 status = false;
162 break;
163 }
164 } else if (amap->count(atomid) != 0) {
165 ELOG(1, "Atom #" << atomid << " in KeySet file is a hydrogen, but is now excluded. ");
166 status = false;
167 break;
168 }
169 }
170 delete amap;
171
172 if (!status) {
173 ELOG(1, "KeySetsFile seems to contain leftover from an old fragmentation, hence not using file.");
174 StoredGraph.clear();
175 }
176 }
177 }
178
179 start = clock();
180 // go through all keys (i.e. all molecules)
181 clusters_t::const_iterator advanceiter;
182 Graph TotalGraph;
183 int keysetcounter = 0;
184 for (clusters_t::const_iterator iter = clusters.begin();
185 iter != clusters.end();
186 iter = advanceiter) {
187 // get iterator to past last atom in this molecule
188 const molecule * mol = iter->first;
189 advanceiter = clusters.upper_bound(mol);
190
191 // copy molecule's atoms' ids as parameters to Fragmentation's AtomMask
192 std::vector<atomId_t> mols_atomids;
193 std::transform(iter, advanceiter, std::back_inserter(mols_atomids),
194 boost::bind( &atom::getNr,
195 boost::bind( &clusters_t::value_type::second, _1 ))
196 );
197 LOG(2, "INFO: Fragmenting in molecule " << mol->getName() << " in " << clusters.count(mol)
198 << " atoms, out of " << mol->getAtomCount() << ".");
199 const enum HydrogenTreatment treatment = params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
200 molecule * non_const_mol = World::getInstance().getMolecule(MoleculeById(mol->getId()));
201 Fragmentation Fragmenter(non_const_mol, *FileChecker, treatment);
202
203 // perform fragmentation
204 LOG(0, std::endl << " ========== Fragmentation of molecule " << mol->getName() << " ========================= ");
205 {
206 Graph StoredLocalGraph(StoredGraph.getLocalGraph(mol));
207 const int tempFlag = Fragmenter.FragmentMolecule(mols_atomids, params.order.get(), params.prefix.get(), StoredLocalGraph, params.ParseStateFiles.get());
208 if ((ExitFlag == 2) && (tempFlag != 2))
209 ExitFlag = tempFlag; // if there is one molecule that needs further fragmentation, it overrides others
210 if (ExitFlag == -1)
211 ExitFlag = tempFlag; // if we are the first, we set the standard
212 }
213 if (TotalGraph.empty()) {
214 TotalGraph = Fragmenter.getGraph();
215 keysetcounter = TotalGraph.size();
216 } else
217 TotalGraph.InsertGraph(Fragmenter.getGraph(), keysetcounter);
218
219 }
220 // add full cycles if desired
221 if (params.DoCyclesFull.get()) {
222 // get the BackEdgeStack from somewhere
223 DepthFirstSearchAnalysis DFS;
224 DFS();
225 std::deque<bond::ptr> BackEdgeStack = DFS.getBackEdgeStack();
226 // then we analyse the cycles and get them
227 CyclicStructureAnalysis CycleAnalysis(params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen);
228 CycleAnalysis(&BackEdgeStack);
229 CyclicStructureAnalysis::cycles_t cycles = CycleAnalysis.getAllCycles();
230 // sort them according to KeySet::operator<()
231 std::sort(cycles.begin(), cycles.end());
232 // store all found cycles to file
233 {
234 boost::filesystem::path filename(params.prefix.get() + std::string(CYCLEKEYSETFILE));
235 std::ofstream File;
236 LOG(1, "INFO: Storing cycle keysets to " << filename.string() << ".");
237 File.open(filename.string().c_str(), ios::out);
238 for (CyclicStructureAnalysis::cycles_t::const_iterator iter = cycles.begin();
239 iter != cycles.end(); ++iter) {
240 for (CyclicStructureAnalysis::cycle_t::const_iterator cycleiter = (*iter).begin();
241 cycleiter != (*iter).end(); ++cycleiter) {
242 File << *cycleiter << "\t";
243 }
244 File << "\n";
245 }
246 File.close();
247 }
248 // ... and to result container
249 {
250 KeySetsContainer cyclekeys;
251 for (CyclicStructureAnalysis::cycles_t::const_iterator iter = cycles.begin();
252 iter != cycles.end(); ++iter) {
253 const CyclicStructureAnalysis::cycle_t &cycle = *iter;
254 const size_t order = cycle.size();
255 KeySetsContainer::IntVector temp_cycle(cycle.begin(), cycle.end());
256 cyclekeys.insert(temp_cycle, order);
257 }
258 FragmentationResultContainer::getInstance().addCycles(cyclekeys);
259 }
260 // Create graph and insert into TotalGraph
261 LOG(0, "STATUS: Adding " << cycles.size() << " cycles.");
262 {
263 Graph CycleGraph;
264 for (CyclicStructureAnalysis::cycles_t::const_iterator iter = cycles.begin();
265 iter != cycles.end(); ++iter) {
266 const CyclicStructureAnalysis::cycle_t &currentcycle = *iter;
267 LOG(2, "INFO: Inserting cycle " << currentcycle << ".");
268#ifndef NDEBUG
269 std::pair< Graph::iterator, bool > inserter =
270#endif
271 CycleGraph.insert( std::make_pair(currentcycle, NumberValuePair(1,1.)) );
272 ASSERT( inserter.second,
273 "FragmentationFragmentationAction::performCall() - keyset "
274 +toString(currentcycle)+" inserted twice into CycleGraph.");
275 }
276 TotalGraph.InsertGraph(CycleGraph, keysetcounter);
277 }
278 }
279
280 LOG(0, "STATUS: There are " << TotalGraph.size() << " fragments.");
281
282 {
283 // remove OrderAtSite file
284 std::string line;
285 std::ofstream file;
286 line = params.prefix.get() + ORDERATSITEFILE;
287 file.open(line.c_str(), std::ofstream::out | std::ofstream::trunc);
288 file << "";
289 file.close();
290 }
291
292 // store graph internally
293 AtomFragmentsMap &atomfragments = AtomFragmentsMap::getInstance();
294 atomfragments.clear();
295 atomfragments.insert(TotalGraph);
296
297 // now add interfragments
298 if (params.InterOrder.get() != 0) {
299 LOG(0, "STATUS: Putting fragments together up to order "
300 << params.InterOrder.get() << " and distance of "
301 << params.distance.get() << ".");
302 const enum HydrogenTreatment treatment =
303 params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
304 const double UpperBound = std::max(10., params.distance.get());
305 Interfragmenter fragmenter;
306
307 // check the largest Rcut that causes no additional inter-fragments
308 const double Min_Rcut =
309 fragmenter.findLargestCutoff(params.InterOrder.get(), UpperBound, treatment);
310
311 // if we smear out electronic charges, warn when non-overlapping criterion does not hold
312 if (params.InterOrder.get() < Min_Rcut)
313 ELOG(2, "Inter-order is too low to cause any additional fragments.");
314
315 // then add fragments
316 fragmenter(TotalGraph, params.InterOrder.get(), params.distance.get(), treatment);
317
318 LOG(0, "STATUS: There are now " << TotalGraph.size() << " fragments after interfragmenting.");
319 }
320 // TODO: When insert only adds and replaces if already present, no clear needed
321 atomfragments.clear();
322 atomfragments.insert(TotalGraph);
323
324 // store keysets to file
325 {
326 TotalGraph.StoreKeySetFile(params.prefix.get());
327 }
328
329 // create global saturation positions map
330 SaturatedFragment::GlobalSaturationPositions_t globalsaturationpositions;
331 {
332 // go through each atom
333 for (World::AtomSelectionConstIterator iter = world.beginAtomSelection();
334 iter != world.endAtomSelection(); ++iter) {
335 const atom * const _atom = iter->second;
336
337 // skip hydrogens if treated special
338 const enum HydrogenTreatment treatment = params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
339 if ((treatment == ExcludeHydrogen) && (_atom->getType()->getAtomicNumber() == 1)) {
340 LOG(4, "DEBUG: Skipping hydrogen atom " << *_atom);
341 continue;
342 }
343
344 // get the valence
345 unsigned int NumberOfPoints = _atom->getElement().getNoValenceOrbitals();
346 LOG(3, "DEBUG: There are " << NumberOfPoints
347 << " places to fill in in total for this atom " << *_atom << ".");
348
349 // check whether there are any bonds with degree larger than 1
350 unsigned int SumOfDegrees = 0;
351 bool PresentHigherBonds = false;
352 const BondList &bondlist = _atom->getListOfBonds();
353 for (BondList::const_iterator bonditer = bondlist.begin();
354 bonditer != bondlist.end(); ++bonditer) {
355 SumOfDegrees += (*bonditer)->getDegree();
356 PresentHigherBonds |= (*bonditer)->getDegree() > 1;
357 }
358
359 // check whether there are alphas to maximize the hydrogens distances
360 SaturationDistanceMaximizer::position_bins_t position_bins;
361 {
362 // gather all bonds and convert to SaturatedBonds
363 SaturationDistanceMaximizer::PositionContainers_t CutBonds;
364 for (BondList::const_iterator bonditer = bondlist.begin();
365 bonditer != bondlist.end(); ++bonditer) {
366 CutBonds.push_back(
367 SaturatedBond::ptr(new SaturatedBond(*(bonditer->get()), *_atom) )
368 );
369 }
370 SaturationDistanceMaximizer maximizer(CutBonds);
371 if (PresentHigherBonds) {
372 // then find best alphas
373 maximizer();
374 } else {
375 // if no higher order bonds, we simply gather the scaled positions
376 }
377 position_bins = maximizer.getAllPositionBins();
378 LOG(4, "DEBUG: Positions for atom " << *_atom << " are " << position_bins);
379 }
380
381 // convert into the desired entry in the map
382 SaturatedFragment::SaturationsPositionsPerNeighbor_t positions_per_neighbor;
383 {
384 BondList::const_iterator bonditer = bondlist.begin();
385 SaturationDistanceMaximizer::position_bins_t::const_iterator biniter =
386 position_bins.begin();
387
388 for (;bonditer != bondlist.end(); ++bonditer, ++biniter) {
389 const atom * const OtherAtom = (*bonditer)->GetOtherAtom(_atom);
390 std::pair<
391 SaturatedFragment::SaturationsPositionsPerNeighbor_t::iterator,
392 bool
393 > inserter;
394 // check whether we treat hydrogen special
395 if ((treatment == ExcludeHydrogen) && (OtherAtom->getType()->getAtomicNumber() == 1)) {
396 // if hydrogen, forget rescaled position and use original one
397 inserter =
398 positions_per_neighbor.insert(
399 std::make_pair(
400 OtherAtom->getId(),
401 SaturatedFragment::SaturationsPositions_t(
402 1, OtherAtom->getPosition() - _atom->getPosition())
403 )
404 );
405 } else {
406 inserter =
407 positions_per_neighbor.insert(
408 std::make_pair(
409 OtherAtom->getId(),
410 SaturatedFragment::SaturationsPositions_t(
411 biniter->begin(),
412 biniter->end())
413 )
414 );
415 }
416 // if already pressent, add to this present list
417 ASSERT (inserter.second,
418 "FragmentationAction::performCall() - other atom "
419 +toString(*OtherAtom)+" already present?");
420 }
421 // bonditer follows nicely
422 ASSERT( biniter == position_bins.end(),
423 "FragmentationAction::performCall() - biniter is out of step, it still points at bond "
424 +toString(*biniter)+".");
425 }
426 // and insert
427 globalsaturationpositions.insert(
428 std::make_pair( _atom->getId(),
429 positions_per_neighbor
430 ));
431 }
432 }
433
434 {
435 const enum HydrogenSaturation saturation = params.DoSaturation.get() ? DoSaturate : DontSaturate;
436 const enum HydrogenTreatment treatment = params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
437 if (params.types.get().size() != 0) {
438 // store molecule's fragment to file
439 ExportGraph_ToFiles exporter(TotalGraph, treatment, saturation, globalsaturationpositions);
440 exporter.setPrefix(params.prefix.get());
441 exporter.setOutputTypes(params.types.get());
442 if (!exporter())
443 return Action::failure;
444 } else {
445 // store molecule's fragment in FragmentJobQueue
446 ExportGraph_ToJobs exporter(TotalGraph, treatment, saturation, globalsaturationpositions);
447 exporter.setLevel(params.level.get());
448 exporter.setMaximumMeshWidth(params.max_meshwidth.get());
449 if (!exporter())
450 return Action::failure;
451 }
452 // add full keysets to present keysets in AtomFragmentsMap
453 ExportGraph_ToAtomFragments exporter(TotalGraph, treatment, saturation, globalsaturationpositions);
454 if (!exporter())
455 return Action::failure;
456 }
457 if (!AtomFragmentsMap::getInstance().checkCompleteness()) {
458 ELOG(0, "Something went wrong with placing keysets in AtomFragmentsMap.");
459 return Action::failure;
460 }
461
462 // store Adjacency to file
463 {
464 std::string filename = params.prefix.get() + ADJACENCYFILE;
465 std::ofstream AdjacencyFile;
466 AdjacencyFile.open(filename.c_str(), ios::out);
467 AdjacencyList adjacency(atomids);
468 adjacency.StoreToFile(AdjacencyFile);
469 AdjacencyFile.close();
470 }
471
472 World::getInstance().setExitFlag(ExitFlag);
473 end = clock();
474 LOG(0, "STATUS: Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s.");
475
476 return Action::success;
477}
478
479ActionState::ptr FragmentationFragmentationAction::performUndo(ActionState::ptr _state) {
480 return Action::success;
481}
482
483ActionState::ptr FragmentationFragmentationAction::performRedo(ActionState::ptr _state){
484 return Action::success;
485}
486
487bool FragmentationFragmentationAction::canUndo() {
488 return true;
489}
490
491bool FragmentationFragmentationAction::shouldUndo() {
492 return true;
493}
494/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.