source: src/Actions/FragmentationAction/FragmentationAction.cpp@ 0907ad

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 0907ad was 0763ce, checked in by Frederik Heber <heber@…>, 10 years ago

Added BondGraph::checkBondDegree, FragmentationAction only resets degrees when incorrect.

  • this fixes the bug where the molecular dynamics actions would flip the double bonds in an aromatic ring during the simulation steps because the bond degrees are reset even though the bond graph is present and should be re-used.
  • Property mode set to 100644
File size: 16.3 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 "Fragmentation/Exporters/ExportGraph_ToFiles.hpp"
43#include "Fragmentation/Exporters/ExportGraph_ToJobs.hpp"
44#include "Fragmentation/Exporters/SaturatedBond.hpp"
45#include "Fragmentation/Exporters/SaturatedFragment.hpp"
46#include "Fragmentation/Exporters/SaturationDistanceMaximizer.hpp"
47#include "Fragmentation/Fragmentation.hpp"
48#include "Fragmentation/Graph.hpp"
49#include "Fragmentation/HydrogenSaturation_enum.hpp"
50#include "Fragmentation/Interfragmenter.hpp"
51#include "Fragmentation/KeySetsContainer.hpp"
52#include "Fragmentation/Summation/Containers/FragmentationResultContainer.hpp"
53#include "Graph/AdjacencyList.hpp"
54#include "Graph/BondGraph.hpp"
55#include "Graph/CyclicStructureAnalysis.hpp"
56#include "Graph/DepthFirstSearchAnalysis.hpp"
57#include "Helpers/defs.hpp"
58#include "molecule.hpp"
59#include "World.hpp"
60
61#include <boost/shared_ptr.hpp>
62#include <boost/filesystem.hpp>
63#include <algorithm>
64#include <iostream>
65#include <map>
66#include <string>
67#include <vector>
68
69#include "Actions/FragmentationAction/FragmentationAction.hpp"
70
71using namespace MoleCuilder;
72
73// and construct the stuff
74#include "FragmentationAction.def"
75#include "Action_impl_pre.hpp"
76/** =========== define the function ====================== */
77ActionState::ptr FragmentationFragmentationAction::performCall() {
78 clock_t start,end;
79 int ExitFlag = -1;
80 World &world = World::getInstance();
81
82 // inform about used parameters
83 LOG(0, "STATUS: Fragmenting molecular system with current connection matrix up to "
84 << params.order.get() << " order. ");
85 if (params.types.get().size() != 0)
86 LOG(0, "STATUS: Fragment files begin with "
87 << params.prefix.get() << " and are stored as: "
88 << params.types.get() << "." << std::endl);
89
90 // check for selected atoms
91 if (world.beginAtomSelection() == world.endAtomSelection()) {
92 STATUS("There are no atoms selected for fragmentation.");
93 return Action::failure;
94 }
95
96 // go through all atoms, note down their molecules and group them
97 typedef std::multimap<molecule *, atom *> clusters_t;
98 typedef std::vector<atomId_t> atomids_t;
99 atomids_t atomids;
100 clusters_t clusters;
101 for (World::AtomSelectionConstIterator iter = world.beginAtomSelection();
102 iter != world.endAtomSelection(); ++iter) {
103 clusters.insert( std::make_pair(iter->second->getMolecule(), iter->second) );
104 atomids.push_back(iter->second->getId());
105 }
106 {
107 std::vector<molecule *> molecules;
108 molecules.insert( molecules.end(), MapKeyIterator<clusters_t::const_iterator>(clusters.begin()),
109 MapKeyIterator<clusters_t::const_iterator>(clusters.end()) );
110 molecules.erase( std::unique(molecules.begin(), molecules.end()), molecules.end() );
111 LOG(1, "INFO: There are " << molecules.size() << " molecules to consider.");
112 }
113
114 // parse in Adjacency file
115 boost::shared_ptr<AdjacencyList> FileChecker;
116 boost::filesystem::path filename(params.prefix.get() + std::string(ADJACENCYFILE));
117 if (boost::filesystem::exists(filename) && boost::filesystem::is_regular_file(filename)) {
118 std::ifstream File;
119 File.open(filename.string().c_str(), ios::out);
120 FileChecker.reset(new AdjacencyList(File));
121 File.close();
122 } else {
123 LOG(1, "INFO: Could not open default adjacency file " << filename.string() << ".");
124 FileChecker.reset(new AdjacencyList);
125 }
126
127 // make sure bond degree is correct
128 {
129 BondGraph *BG = World::getInstance().getBondGraph();
130 World::AtomComposite Set = World::getInstance().getAllAtoms(AtomsBySelection());
131 // check whether bond graph is correct
132 if (!BG->checkBondDegree(Set))
133 BG->CorrectBondDegree(Set);
134 else
135 LOG(1, "INFO: Bond degrees all valid, not correcting.");
136 }
137
138 // we parse in the keysets from last time if present
139 Graph StoredGraph;
140 StoredGraph.ParseKeySetFile(params.prefix.get());
141
142 start = clock();
143 // go through all keys (i.e. all molecules)
144 clusters_t::const_iterator advanceiter;
145 Graph TotalGraph;
146 int keysetcounter = 0;
147 for (clusters_t::const_iterator iter = clusters.begin();
148 iter != clusters.end();
149 iter = advanceiter) {
150 // get iterator to past last atom in this molecule
151 molecule * mol = iter->first;
152 advanceiter = clusters.upper_bound(mol);
153
154 // copy molecule's atoms' ids as parameters to Fragmentation's AtomMask
155 std::vector<atomId_t> mols_atomids;
156 std::transform(iter, advanceiter, std::back_inserter(mols_atomids),
157 boost::bind( &atom::getNr,
158 boost::bind( &clusters_t::value_type::second, _1 ))
159 );
160 LOG(2, "INFO: Fragmenting in molecule " << mol->getName() << " in " << clusters.count(mol)
161 << " atoms, out of " << mol->getAtomCount() << ".");
162 const enum HydrogenTreatment treatment = params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
163 Fragmentation Fragmenter(mol, *FileChecker, treatment);
164
165 // perform fragmentation
166 LOG(0, std::endl << " ========== Fragmentation of molecule " << mol->getName() << " ========================= ");
167 {
168 Graph StoredLocalGraph(StoredGraph.getLocalGraph(mol));
169 const int tempFlag = Fragmenter.FragmentMolecule(mols_atomids, params.order.get(), params.prefix.get(), StoredLocalGraph);
170 if ((ExitFlag == 2) && (tempFlag != 2))
171 ExitFlag = tempFlag; // if there is one molecule that needs further fragmentation, it overrides others
172 if (ExitFlag == -1)
173 ExitFlag = tempFlag; // if we are the first, we set the standard
174 }
175 if (TotalGraph.empty()) {
176 TotalGraph = Fragmenter.getGraph();
177 keysetcounter = TotalGraph.size();
178 } else
179 TotalGraph.InsertGraph(Fragmenter.getGraph(), keysetcounter);
180
181 }
182 // add full cycles if desired
183 if (params.DoCyclesFull.get()) {
184 // get the BackEdgeStack from somewhere
185 DepthFirstSearchAnalysis DFS;
186 DFS();
187 std::deque<bond::ptr> BackEdgeStack = DFS.getBackEdgeStack();
188 // then we analyse the cycles and get them
189 CyclicStructureAnalysis CycleAnalysis(params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen);
190 CycleAnalysis(&BackEdgeStack);
191 CyclicStructureAnalysis::cycles_t cycles = CycleAnalysis.getAllCycles();
192 // sort them according to KeySet::operator<()
193 std::sort(cycles.begin(), cycles.end());
194 // store all found cycles to file
195 {
196 boost::filesystem::path filename(params.prefix.get() + std::string(CYCLEKEYSETFILE));
197 std::ofstream File;
198 LOG(1, "INFO: Storing cycle keysets to " << filename.string() << ".");
199 File.open(filename.string().c_str(), ios::out);
200 for (CyclicStructureAnalysis::cycles_t::const_iterator iter = cycles.begin();
201 iter != cycles.end(); ++iter) {
202 for (CyclicStructureAnalysis::cycle_t::const_iterator cycleiter = (*iter).begin();
203 cycleiter != (*iter).end(); ++cycleiter) {
204 File << *cycleiter << "\t";
205 }
206 File << "\n";
207 }
208 File.close();
209 }
210 // ... and to result container
211 {
212 KeySetsContainer cyclekeys;
213 for (CyclicStructureAnalysis::cycles_t::const_iterator iter = cycles.begin();
214 iter != cycles.end(); ++iter) {
215 const CyclicStructureAnalysis::cycle_t &cycle = *iter;
216 const size_t order = cycle.size();
217 KeySetsContainer::IntVector temp_cycle(cycle.begin(), cycle.end());
218 cyclekeys.insert(temp_cycle, order);
219 }
220 FragmentationResultContainer::getInstance().addCycles(cyclekeys);
221 }
222 // Create graph and insert into TotalGraph
223 LOG(0, "STATUS: Adding " << cycles.size() << " cycles.");
224 {
225 Graph CycleGraph;
226 for (CyclicStructureAnalysis::cycles_t::const_iterator iter = cycles.begin();
227 iter != cycles.end(); ++iter) {
228 const CyclicStructureAnalysis::cycle_t &currentcycle = *iter;
229 LOG(2, "INFO: Inserting cycle " << currentcycle << ".");
230#ifndef NDEBUG
231 std::pair< Graph::iterator, bool > inserter =
232#endif
233 CycleGraph.insert( std::make_pair(currentcycle, NumberValuePair(1,1.)) );
234 ASSERT( inserter.second,
235 "FragmentationFragmentationAction::performCall() - keyset "
236 +toString(currentcycle)+" inserted twice into CycleGraph.");
237 }
238 TotalGraph.InsertGraph(CycleGraph, keysetcounter);
239 }
240 }
241
242 LOG(0, "STATUS: There are " << TotalGraph.size() << " fragments.");
243
244 {
245 // remove OrderAtSite file
246 std::string line;
247 std::ofstream file;
248 line = params.prefix.get() + ORDERATSITEFILE;
249 file.open(line.c_str(), std::ofstream::out | std::ofstream::trunc);
250 file << "";
251 file.close();
252 }
253
254 // now add interfragments
255 if (params.InterOrder.get() != 0) {
256 LOG(0, "STATUS: Putting fragments together up to order "
257 << params.InterOrder.get() << " and distance of "
258 << params.distance.get() << ".");
259 Interfragmenter fragmenter(TotalGraph);
260 const enum HydrogenTreatment treatment = params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
261 fragmenter(params.InterOrder.get(), params.distance.get(), treatment);
262 LOG(0, "STATUS: There are now " << TotalGraph.size() << " fragments after interfragmenting.");
263 }
264
265 // store keysets to file
266 {
267 TotalGraph.StoreKeySetFile(params.prefix.get());
268 }
269
270 // create global saturation positions map
271 SaturatedFragment::GlobalSaturationPositions_t globalsaturationpositions;
272 {
273 // go through each atom
274 for (World::AtomSelectionConstIterator iter = world.beginAtomSelection();
275 iter != world.endAtomSelection(); ++iter) {
276 const atom * const _atom = iter->second;
277
278 // skip hydrogens if treated special
279 const enum HydrogenTreatment treatment = params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
280 if ((treatment == ExcludeHydrogen) && (_atom->getType()->getAtomicNumber() == 1)) {
281 LOG(4, "DEBUG: Skipping hydrogen atom " << *_atom);
282 continue;
283 }
284
285 // get the valence
286 unsigned int NumberOfPoints = _atom->getElement().getNoValenceOrbitals();
287 LOG(3, "DEBUG: There are " << NumberOfPoints
288 << " places to fill in in total for this atom " << *_atom << ".");
289
290 // check whether there are any bonds with degree larger than 1
291 unsigned int SumOfDegrees = 0;
292 bool PresentHigherBonds = false;
293 const BondList &bondlist = _atom->getListOfBonds();
294 for (BondList::const_iterator bonditer = bondlist.begin();
295 bonditer != bondlist.end(); ++bonditer) {
296 SumOfDegrees += (*bonditer)->getDegree();
297 PresentHigherBonds |= (*bonditer)->getDegree() > 1;
298 }
299
300 // check whether there are alphas to maximize the hydrogens distances
301 SaturationDistanceMaximizer::position_bins_t position_bins;
302 {
303 // gather all bonds and convert to SaturatedBonds
304 SaturationDistanceMaximizer::PositionContainers_t CutBonds;
305 for (BondList::const_iterator bonditer = bondlist.begin();
306 bonditer != bondlist.end(); ++bonditer) {
307 CutBonds.push_back(
308 SaturatedBond::ptr(new SaturatedBond(*(bonditer->get()), *_atom) )
309 );
310 }
311 SaturationDistanceMaximizer maximizer(CutBonds);
312 if (PresentHigherBonds) {
313 // then find best alphas
314 maximizer();
315 } else {
316 // if no higher order bonds, we simply gather the scaled positions
317 }
318 position_bins = maximizer.getAllPositionBins();
319 LOG(4, "DEBUG: Positions for atom " << *_atom << " are " << position_bins);
320 }
321
322 // convert into the desired entry in the map
323 SaturatedFragment::SaturationsPositionsPerNeighbor_t positions_per_neighbor;
324 {
325 BondList::const_iterator bonditer = bondlist.begin();
326 SaturationDistanceMaximizer::position_bins_t::const_iterator biniter =
327 position_bins.begin();
328
329 for (;bonditer != bondlist.end(); ++bonditer, ++biniter) {
330 const atom * const OtherAtom = (*bonditer)->GetOtherAtom(_atom);
331 std::pair<
332 SaturatedFragment::SaturationsPositionsPerNeighbor_t::iterator,
333 bool
334 > inserter;
335 // check whether we treat hydrogen special
336 if ((treatment == ExcludeHydrogen) && (OtherAtom->getType()->getAtomicNumber() == 1)) {
337 // if hydrogen, forget rescaled position and use original one
338 inserter =
339 positions_per_neighbor.insert(
340 std::make_pair(
341 OtherAtom->getId(),
342 SaturatedFragment::SaturationsPositions_t(
343 1, OtherAtom->getPosition() - _atom->getPosition())
344 )
345 );
346 } else {
347 inserter =
348 positions_per_neighbor.insert(
349 std::make_pair(
350 OtherAtom->getId(),
351 SaturatedFragment::SaturationsPositions_t(
352 biniter->begin(),
353 biniter->end())
354 )
355 );
356 }
357 // if already pressent, add to this present list
358 ASSERT (inserter.second,
359 "FragmentationAction::performCall() - other atom "
360 +toString(*OtherAtom)+" already present?");
361 }
362 // bonditer follows nicely
363 ASSERT( biniter == position_bins.end(),
364 "FragmentationAction::performCall() - biniter is out of step, it still points at bond "
365 +toString(*biniter)+".");
366 }
367 // and insert
368 globalsaturationpositions.insert(
369 std::make_pair( _atom->getId(),
370 positions_per_neighbor
371 ));
372 }
373 }
374
375 {
376 const enum HydrogenSaturation saturation = params.DoSaturation.get() ? DoSaturate : DontSaturate;
377 const enum HydrogenTreatment treatment = params.HowtoTreatHydrogen.get() ? ExcludeHydrogen : IncludeHydrogen;
378 if (params.types.get().size() != 0) {
379 // store molecule's fragment to file
380 ExportGraph_ToFiles exporter(TotalGraph, treatment, saturation, globalsaturationpositions);
381 exporter.setPrefix(params.prefix.get());
382 exporter.setOutputTypes(params.types.get());
383 exporter();
384 } else {
385 // store molecule's fragment in FragmentJobQueue
386 ExportGraph_ToJobs exporter(TotalGraph, treatment, saturation, globalsaturationpositions);
387 exporter.setLevel(params.level.get());
388 exporter();
389 }
390 }
391
392 // store Adjacency to file
393 {
394 std::string filename = params.prefix.get() + ADJACENCYFILE;
395 std::ofstream AdjacencyFile;
396 AdjacencyFile.open(filename.c_str(), ios::out);
397 AdjacencyList adjacency(atomids);
398 adjacency.StoreToFile(AdjacencyFile);
399 AdjacencyFile.close();
400 }
401
402 World::getInstance().setExitFlag(ExitFlag);
403 end = clock();
404 LOG(0, "STATUS: Clocks for this operation: " << (end-start) << ", time: " << ((double)(end-start)/CLOCKS_PER_SEC) << "s.");
405
406 return Action::success;
407}
408
409ActionState::ptr FragmentationFragmentationAction::performUndo(ActionState::ptr _state) {
410 return Action::success;
411}
412
413ActionState::ptr FragmentationFragmentationAction::performRedo(ActionState::ptr _state){
414 return Action::success;
415}
416
417bool FragmentationFragmentationAction::canUndo() {
418 return true;
419}
420
421bool FragmentationFragmentationAction::shouldUndo() {
422 return true;
423}
424/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.