source: src/Actions/FillAction/SuspendInMoleculeAction.cpp@ d93d2c

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 d93d2c was f01769, checked in by Frederik Heber <heber@…>, 9 years ago

Replaced World::getAtom() wherever possible by const version.

  • some AtomSet member functions now have const atom ptr instead of atom ptr.
  • molecule can return const and non-const AtomSet.
  • added FromIdToConstAtom to allow iterate through atoms in molecule (which are stored by id, not by ptr) in const fashion.
  • in molecule::isInMolecule() is now const, ::CopyMolecule..() is non-const (because copying involves father atom who is stored non-const).
  • Property mode set to 100644
File size: 12.7 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2014 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 * SuspendInMoleculeAction.cpp
25 *
26 * Created on: Sep 05, 2014
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 "Actions/UndoRedoHelpers.hpp"
38#include "Atom/atom.hpp"
39#include "Atom/AtomicInfo.hpp"
40#include "Atom/CopyAtoms/CopyAtoms_withBonds.hpp"
41#include "Bond/BondInfo.hpp"
42#include "CodePatterns/Log.hpp"
43#include "Descriptors/MoleculeOrderDescriptor.hpp"
44#include "Element/element.hpp"
45#include "Filling/Cluster.hpp"
46#include "Filling/Filler.hpp"
47#include "Filling/Preparators/BoxFillerPreparator.hpp"
48#include "LinkedCell/linkedcell.hpp"
49#include "LinkedCell/PointCloudAdaptor.hpp"
50#include "molecule.hpp"
51#include "MoleculeListClass.hpp"
52#include "Parser/FormatParserInterface.hpp"
53#include "Parser/FormatParserStorage.hpp"
54#include "Tesselation/boundary.hpp"
55#include "Tesselation/tesselation.hpp"
56#include "World.hpp"
57
58#include <algorithm>
59#include<gsl/gsl_poly.h>
60#include <iostream>
61#include <string>
62#include <vector>
63
64#include "Actions/FillAction/SuspendInMoleculeAction.hpp"
65
66using namespace MoleCuilder;
67
68static double calculateMass(const molecule &_mol)
69{
70 // sum up the atomic masses
71 const double mass = _mol.getAtomSet().totalMass();
72 LOG(2, "DEBUG: Molecule "+_mol.getName()+"'s summed mass is "
73 << setprecision(10) << mass << " atomicmassunit.");
74 return mass;
75}
76
77static double calculateEnvelopeVolume(
78 molecule &_mol,
79 std::vector<double> &_diameters)
80{
81 const bool IsAngstroem = true;
82 class Tesselation *TesselStruct = NULL;
83
84 Boundaries *BoundaryPoints = GetBoundaryPoints(&_mol, TesselStruct);
85 const double * diameters =
86 GetDiametersOfCluster(BoundaryPoints, &_mol, TesselStruct, IsAngstroem);
87 std::copy(&diameters[0], &diameters[3], _diameters.begin());
88 delete[] diameters;
89 PointCloudAdaptor< molecule > cloud(&_mol, _mol.getName());
90 LinkedCell_deprecated *LCList = new LinkedCell_deprecated(cloud, 10.);
91 FindConvexBorder(&_mol, BoundaryPoints, TesselStruct, (const LinkedCell_deprecated *&)LCList, NULL);
92 delete (LCList);
93 delete[] BoundaryPoints;
94
95 // some preparations beforehand
96 const double volume = TesselStruct->getVolumeOfConvexEnvelope(IsAngstroem);
97
98 delete TesselStruct;
99
100 LOG(2, "DEBUG: Molecule "+_mol.getName()+"'s volume is "
101 << setprecision(10) << volume << " angstrom^3.");
102
103 return volume;
104}
105
106// and construct the stuff
107#include "SuspendInMoleculeAction.def"
108#include "Action_impl_pre.hpp"
109/** =========== define the function ====================== */
110ActionState::ptr FillSuspendInMoleculeAction::performCall() {
111 typedef std::vector<atom*> AtomVector;
112
113 // get the filler molecule
114 std::vector<AtomicInfo> movedatoms;
115 molecule *filler = NULL;
116 {
117 const std::vector< molecule *> molecules = World::getInstance().getSelectedMolecules();
118 if (molecules.size() != 1) {
119 STATUS("No exactly one molecule selected, aborting,");
120 return Action::failure;
121 }
122 filler = *(molecules.begin());
123 }
124 for(molecule::const_iterator iter = const_cast<const molecule *>(filler)->begin();
125 iter != const_cast<const molecule *>(filler)->end(); ++iter)
126 movedatoms.push_back( AtomicInfo(*(*iter)) );
127 LOG(1, "INFO: Chosen molecule has " << filler->size() << " atoms.");
128
129 // center filler's tip at origin
130 filler->CenterEdge();
131
132 std::vector<molecule *> molecules = World::getInstance().getAllMolecules();
133 if (molecules.size() < 2) {
134 STATUS("There must be at least two molecules: filler and to be suspended.");
135 return Action::failure;
136 }
137
138 /// first we need to calculate some volumes and masses
139 double totalmass = 0.;
140 const bool IsAngstroem = true;
141 Vector BoxLengths;
142 double clustervolume = 0.;
143 std::vector<double> GreatestDiameter(NDIM, 0.);
144 for (std::vector<molecule *>::const_iterator iter = molecules.begin();
145 iter != molecules.end(); ++iter)
146 {
147 // skip the filler
148 if (*iter == filler)
149 continue;
150 molecule & mol = **iter;
151 const double mass = calculateMass(mol);
152 totalmass += mass;
153 std::vector<double> diameters(NDIM, 0.);
154 const double volume = calculateEnvelopeVolume(mol, diameters);
155 clustervolume += volume;
156 for (size_t i=0;i<NDIM;++i)
157 GreatestDiameter[i] = std::max(GreatestDiameter[i], diameters[i]);
158 }
159 LOG(1, "INFO: The summed mass is " << setprecision(10)
160 << totalmass << " atomicmassunit.");
161 LOG(1, "INFO: The average density is " << setprecision(10)
162 << totalmass / clustervolume << " atomicmassunit/"
163 << (IsAngstroem ? " angstrom" : " atomiclength") << "^3.");
164 if ( ((totalmass / clustervolume < 1.) && (params.density.get() > 1.))
165 || ((totalmass / clustervolume > 1.) && (params.density.get() < 1.))) {
166 STATUS("Desired and present molecular densities must both be either in [0,1) or in (1, inf).");
167 return Action::failure;
168 }
169
170 // calculate maximum solvent density
171 std::vector<double> fillerdiameters(NDIM, 0.);
172 const double fillervolume = calculateEnvelopeVolume(*filler, fillerdiameters);
173 const double fillermass = calculateMass(*filler);
174 LOG(1, "INFO: The filler's mass is " << setprecision(10)
175 << fillermass << " atomicmassunit, and it's volume is "
176 << fillervolume << (IsAngstroem ? " angstrom" : " atomiclength") << "^3.");
177// const double solventdensity = fillermass / fillervolume;
178
179 /// solve cubic polynomial
180 double cellvolume = 0.;
181 LOG(1, "Solving equidistant suspension in water problem ...");
182 // s = solvent, f = filler, 0 = initial molecules/cluster
183 // v_s = v_0 + v_f, m_s = m_0 + rho_f * v_f --> rho_s = m_s/v_s ==> v_f = (m_0 - rho_s * v_o) / (rho_s - rho_f)
184 cellvolume = (totalmass - params.density.get() * clustervolume) / (params.density.get() - 1.) + clustervolume;
185 LOG(1, "Cellvolume needed for a density of " << params.density.get()
186 << " g/cm^3 is " << cellvolume << " angstroem^3.");
187
188 const double minimumvolume =
189 (GreatestDiameter[0] * GreatestDiameter[1] * GreatestDiameter[2]);
190 LOG(1, "Minimum volume of the convex envelope contained in a rectangular box is "
191 << minimumvolume << " angstrom^3.");
192
193 if (minimumvolume > cellvolume) {
194 ELOG(1, "The containing box already has a greater volume than the envisaged cell volume!");
195 LOG(0, "Setting Box dimensions to minimum possible, the greatest diameters.");
196 for (int i = 0; i < NDIM; i++)
197 BoxLengths[i] = GreatestDiameter[i];
198// mol->CenterEdge();
199 } else {
200 BoxLengths[0] = GreatestDiameter[0] + GreatestDiameter[1] + GreatestDiameter[2];
201 BoxLengths[1] = GreatestDiameter[0] * GreatestDiameter[1]
202 + GreatestDiameter[0] * GreatestDiameter[2]
203 + GreatestDiameter[1] * GreatestDiameter[2];
204 BoxLengths[2] = minimumvolume - cellvolume;
205 std::vector<double> x(3, 0.);
206 // for cubic polynomial there are either 1 or 3 unique solutions
207 if (gsl_poly_solve_cubic(BoxLengths[0], BoxLengths[1], BoxLengths[2], &x[0], &x[1], &x[2]) == 1) {
208 x[1] = x[0];
209 x[2] = x[0];
210 } else {
211 std::swap(x[0], x[2]); // sorted in ascending order
212 }
213 LOG(0, "RESULT: The resulting spacing is: " << x << " .");
214
215 cellvolume = 1.;
216 for (size_t i = 0; i < NDIM; ++i) {
217 BoxLengths[i] = x[i] + GreatestDiameter[i];
218 cellvolume *= BoxLengths[i];
219 }
220 }
221
222 // TODO: Determine counts from resulting mass correctly (hard problem due to integers)
223 std::vector<unsigned int> counts(3, 0);
224 const unsigned int totalcounts = round(params.density.get() * cellvolume - totalmass) / fillermass;
225 if (totalcounts > 0) {
226 counts[0] = ceil(BoxLengths[0]/3.1);
227 counts[1] = ceil(BoxLengths[1]/3.1);
228 counts[2] = ceil(BoxLengths[2]/3.1);
229 }
230
231 // update Box of atoms by boundary
232 {
233 RealSpaceMatrix domain;
234 for(size_t i =0; i<NDIM;++i)
235 domain.at(i,i) = BoxLengths[i];
236 World::getInstance().setDomain(domain);
237 }
238 LOG(0, "RESULT: The resulting cell dimensions are: " << BoxLengths[0] << " and " << BoxLengths[1] << " and " << BoxLengths[2] << " with total volume of " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3.");
239
240 // prepare the filler preparator
241 BoxFillerPreparator filler_preparator(filler);
242 filler_preparator.addVoidPredicate(params.mindistance.get());
243 filler_preparator.addRandomInserter(
244 params.RandAtomDisplacement.get(),
245 params.RandMoleculeDisplacement.get(),
246 params.DoRotate.get());
247 Vector offset(.5,.5,.5);
248 filler_preparator.addCubeMesh(
249 counts,
250 offset,
251 World::getInstance().getDomain().getM());
252 if (!filler_preparator()) {
253 STATUS("Filler was not fully constructed.");
254 return Action::failure;
255 }
256
257 // use filler
258 bool successflag = false;
259 FillSuspendInMoleculeState *UndoState = NULL;
260 {
261 // fill
262 Filler *fillerFunction = filler_preparator.obtainFiller();
263 // TODO: When molecule::getBoundingSphere() does not use a sphere anymore,
264 // we need to check whether we rotate the molecule randomly. For this to
265 // work we need a sphere!
266 const Shape s = filler->getBoundingSphere(params.RandAtomDisplacement.get());
267 ClusterInterface::Cluster_impl cluster( new Cluster(filler->getAtomIds(), s) );
268 CopyAtoms_withBonds copyMethod;
269 Filler::ClusterVector_t ClonedClusters;
270 successflag = (*fillerFunction)(copyMethod, cluster, ClonedClusters);
271 delete fillerFunction;
272
273 // append each cluster's atoms to clonedatoms (however not selected ones)
274 std::vector<const atom *> clonedatoms;
275 std::vector<AtomicInfo> clonedatominfos;
276 for (Filler::ClusterVector_t::const_iterator iter = ClonedClusters.begin();
277 iter != ClonedClusters.end(); ++iter) {
278 const AtomIdSet &atoms = (*iter)->getAtomIds();
279 clonedatoms.reserve(clonedatoms.size()+atoms.size());
280 for (AtomIdSet::const_iterator atomiter = atoms.begin(); atomiter != atoms.end(); ++atomiter)
281 if (!filler->containsAtom(*atomiter)) {
282 clonedatoms.push_back( *atomiter );
283 clonedatominfos.push_back( AtomicInfo(*(*atomiter)) );
284 }
285 }
286 std::vector< BondInfo > clonedbonds;
287 StoreBondInformationFromAtoms(clonedatoms, clonedbonds);
288 LOG(2, "DEBUG: There are " << clonedatominfos.size() << " newly created atoms.");
289
290 if (!successflag) {
291 STATUS("Insertion failed, removing inserted clusters, translating original one back");
292 RemoveAtomsFromAtomicInfo(clonedatominfos);
293 clonedatoms.clear();
294 SetAtomsFromAtomicInfo(movedatoms);
295 } else {
296 std::vector<Vector> MovedToVector(filler->size(), zeroVec);
297 std::transform(filler->begin(), filler->end(), MovedToVector.begin(),
298 boost::bind(&AtomInfo::getPosition, _1) );
299 UndoState = new FillSuspendInMoleculeState(clonedatominfos,clonedbonds,movedatoms,MovedToVector,params);
300 }
301 }
302
303 if (successflag)
304 return ActionState::ptr(UndoState);
305 else {
306 return Action::failure;
307 }
308}
309
310ActionState::ptr FillSuspendInMoleculeAction::performUndo(ActionState::ptr _state) {
311 FillSuspendInMoleculeState *state = assert_cast<FillSuspendInMoleculeState*>(_state.get());
312
313 // remove all created atoms
314 RemoveAtomsFromAtomicInfo(state->clonedatoms);
315 // add the original cluster
316 SetAtomsFromAtomicInfo(state->movedatoms);
317
318 return ActionState::ptr(_state);
319}
320
321ActionState::ptr FillSuspendInMoleculeAction::performRedo(ActionState::ptr _state){
322 FillSuspendInMoleculeState *state = assert_cast<FillSuspendInMoleculeState*>(_state.get());
323
324 // place filler cluster again at new spot
325 ResetAtomPosition(state->movedatoms, state->MovedToVector);
326
327 // re-create all clusters
328 bool statusflag = AddAtomsFromAtomicInfo(state->clonedatoms);
329
330 // re-create the bonds
331 if (statusflag)
332 AddBondsFromBondInfo(state->clonedbonds);
333 if (statusflag)
334 return ActionState::ptr(_state);
335 else {
336 STATUS("Failed re-adding filled in atoms.");
337 return Action::failure;
338 }
339}
340
341bool FillSuspendInMoleculeAction::canUndo() {
342 return false;
343}
344
345bool FillSuspendInMoleculeAction::shouldUndo() {
346 return false;
347}
348/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.