source: src/Actions/FragmentationAction/FragmentationAction.cpp@ 2fe4a5

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests 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_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 FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks 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 2fe4a5 was d9dbef, checked in by Frederik Heber <heber@…>, 9 years ago

Added another ExportGraph for obtaining AtomFragmentsMap's forcekeysets, used by FragmentationAction.

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