source: src/Actions/FillAction/SuspendInMoleculeAction.cpp@ 2440ce

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 2440ce was 2440ce, checked in by Frederik Heber <heber@…>, 10 years ago

FIX: Changed SuspendInMoleculeAction to catch segfault when rho=1 was given.

  • however, the action is still not tested to work.
  • TESTFIX: suspend-in-water gets parameter density via "density" not via "suspend-in-water", set desired density to faulting 1 for the moment.
  • TESTFIX: added water molecule to test.conf, to have at least two molecules.
  • Property mode set to 100644
File size: 12.6 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 = filler->begin(); iter != filler->end(); ++iter)
125 movedatoms.push_back( AtomicInfo(*(*iter)) );
126 LOG(1, "INFO: Chosen molecule has " << filler->size() << " atoms.");
127
128 // center filler's tip at origin
129 filler->CenterEdge();
130
131 std::vector<molecule *> molecules = World::getInstance().getAllMolecules();
132 if (molecules.size() < 2) {
133 STATUS("There must be at least two molecules: filler and to be suspended.");
134 return Action::failure;
135 }
136
137 /// first we need to calculate some volumes and masses
138 double totalmass = 0.;
139 const bool IsAngstroem = true;
140 Vector BoxLengths;
141 double clustervolume = 0.;
142 std::vector<double> GreatestDiameter(NDIM, 0.);
143 for (std::vector<molecule *>::iterator iter = molecules.begin();
144 iter != molecules.end(); ++iter)
145 {
146 // skip the filler
147 if (*iter == filler)
148 continue;
149 molecule & mol = **iter;
150 const double mass = calculateMass(mol);
151 totalmass += mass;
152 std::vector<double> diameters(NDIM, 0.);
153 const double volume = calculateEnvelopeVolume(mol, diameters);
154 clustervolume += volume;
155 for (size_t i=0;i<NDIM;++i)
156 GreatestDiameter[i] = std::max(GreatestDiameter[i], diameters[i]);
157 }
158 LOG(1, "INFO: The summed mass is " << setprecision(10)
159 << totalmass << " atomicmassunit.");
160 LOG(1, "INFO: The average density is " << setprecision(10)
161 << totalmass / clustervolume << " atomicmassunit/"
162 << (IsAngstroem ? " angstrom" : " atomiclength") << "^3.");
163 if ( ((totalmass / clustervolume < 1.) && (params.density.get() > 1.))
164 || ((totalmass / clustervolume > 1.) && (params.density.get() < 1.))) {
165 STATUS("Desired and present molecular densities must both be either in [0,1) or in (1, inf).");
166 return Action::failure;
167 }
168
169 // calculate maximum solvent density
170 std::vector<double> fillerdiameters(NDIM, 0.);
171 const double fillervolume = calculateEnvelopeVolume(*filler, fillerdiameters);
172 const double fillermass = calculateMass(*filler);
173 LOG(1, "INFO: The filler's mass is " << setprecision(10)
174 << fillermass << " atomicmassunit, and it's volume is "
175 << fillervolume << (IsAngstroem ? " angstrom" : " atomiclength") << "^3.");
176 const double solventdensity = fillermass / fillervolume;
177
178 /// solve cubic polynomial
179 double cellvolume = 0.;
180 LOG(1, "Solving equidistant suspension in water problem ...");
181 // s = solvent, f = filler, 0 = initial molecules/cluster
182 // 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)
183 cellvolume = (totalmass - params.density.get() * clustervolume) / (params.density.get() - 1.) + clustervolume;
184 LOG(1, "Cellvolume needed for a density of " << params.density.get()
185 << " g/cm^3 is " << cellvolume << " angstroem^3.");
186
187 const double minimumvolume =
188 (GreatestDiameter[0] * GreatestDiameter[1] * GreatestDiameter[2]);
189 LOG(1, "Minimum volume of the convex envelope contained in a rectangular box is "
190 << minimumvolume << " angstrom^3.");
191
192 if (minimumvolume > cellvolume) {
193 ELOG(1, "The containing box already has a greater volume than the envisaged cell volume!");
194 LOG(0, "Setting Box dimensions to minimum possible, the greatest diameters.");
195 for (int i = 0; i < NDIM; i++)
196 BoxLengths[i] = GreatestDiameter[i];
197// mol->CenterEdge();
198 } else {
199 BoxLengths[0] = GreatestDiameter[0] + GreatestDiameter[1] + GreatestDiameter[2];
200 BoxLengths[1] = GreatestDiameter[0] * GreatestDiameter[1]
201 + GreatestDiameter[0] * GreatestDiameter[2]
202 + GreatestDiameter[1] * GreatestDiameter[2];
203 BoxLengths[2] = minimumvolume - cellvolume;
204 std::vector<double> x(3, 0.);
205 // for cubic polynomial there are either 1 or 3 unique solutions
206 if (gsl_poly_solve_cubic(BoxLengths[0], BoxLengths[1], BoxLengths[2], &x[0], &x[1], &x[2]) == 1) {
207 x[1] = x[0];
208 x[2] = x[0];
209 } else {
210 std::swap(x[0], x[2]); // sorted in ascending order
211 }
212 LOG(0, "RESULT: The resulting spacing is: " << x << " .");
213
214 cellvolume = 1.;
215 for (size_t i = 0; i < NDIM; ++i) {
216 BoxLengths[i] = x[i] + GreatestDiameter[i];
217 cellvolume *= BoxLengths[i];
218 }
219 }
220
221 // TODO: Determine counts from resulting mass correctly (hard problem due to integers)
222 std::vector<unsigned int> counts(3, 0);
223 const unsigned int totalcounts = round(params.density.get() * cellvolume - totalmass) / fillermass;
224 if (totalcounts > 0) {
225 counts[0] = ceil(BoxLengths[0]/3.1);
226 counts[1] = ceil(BoxLengths[1]/3.1);
227 counts[2] = ceil(BoxLengths[2]/3.1);
228 }
229
230 // update Box of atoms by boundary
231 {
232 RealSpaceMatrix domain;
233 for(size_t i =0; i<NDIM;++i)
234 domain.at(i,i) = BoxLengths[i];
235 World::getInstance().setDomain(domain);
236 }
237 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.");
238
239 // prepare the filler preparator
240 BoxFillerPreparator filler_preparator(filler);
241 filler_preparator.addVoidPredicate(params.mindistance.get());
242 filler_preparator.addRandomInserter(
243 params.RandAtomDisplacement.get(),
244 params.RandMoleculeDisplacement.get(),
245 params.DoRotate.get());
246 Vector offset(.5,.5,.5);
247 filler_preparator.addCubeMesh(
248 counts,
249 offset,
250 World::getInstance().getDomain().getM());
251 if (!filler_preparator()) {
252 STATUS("Filler was not fully constructed.");
253 return Action::failure;
254 }
255
256 // use filler
257 bool successflag = false;
258 FillSuspendInMoleculeState *UndoState = NULL;
259 {
260 // fill
261 Filler *fillerFunction = filler_preparator.obtainFiller();
262 // TODO: When molecule::getBoundingSphere() does not use a sphere anymore,
263 // we need to check whether we rotate the molecule randomly. For this to
264 // work we need a sphere!
265 const Shape s = filler->getBoundingSphere(params.RandAtomDisplacement.get());
266 ClusterInterface::Cluster_impl cluster( new Cluster(filler->getAtomIds(), s) );
267 CopyAtoms_withBonds copyMethod;
268 Filler::ClusterVector_t ClonedClusters;
269 successflag = (*fillerFunction)(copyMethod, cluster, ClonedClusters);
270 delete fillerFunction;
271
272 // append each cluster's atoms to clonedatoms (however not selected ones)
273 std::vector<const atom *> clonedatoms;
274 std::vector<AtomicInfo> clonedatominfos;
275 for (Filler::ClusterVector_t::const_iterator iter = ClonedClusters.begin();
276 iter != ClonedClusters.end(); ++iter) {
277 const AtomIdSet &atoms = (*iter)->getAtomIds();
278 clonedatoms.reserve(clonedatoms.size()+atoms.size());
279 for (AtomIdSet::const_iterator atomiter = atoms.begin(); atomiter != atoms.end(); ++atomiter)
280 if (!filler->containsAtom(*atomiter)) {
281 clonedatoms.push_back( *atomiter );
282 clonedatominfos.push_back( AtomicInfo(*(*atomiter)) );
283 }
284 }
285 std::vector< BondInfo > clonedbonds;
286 StoreBondInformationFromAtoms(clonedatoms, clonedbonds);
287 LOG(2, "DEBUG: There are " << clonedatominfos.size() << " newly created atoms.");
288
289 if (!successflag) {
290 STATUS("Insertion failed, removing inserted clusters, translating original one back");
291 RemoveAtomsFromAtomicInfo(clonedatominfos);
292 clonedatoms.clear();
293 SetAtomsFromAtomicInfo(movedatoms);
294 } else {
295 std::vector<Vector> MovedToVector(filler->size(), zeroVec);
296 std::transform(filler->begin(), filler->end(), MovedToVector.begin(),
297 boost::bind(&AtomInfo::getPosition, _1) );
298 UndoState = new FillSuspendInMoleculeState(clonedatominfos,clonedbonds,movedatoms,MovedToVector,params);
299 }
300 }
301
302 if (successflag)
303 return ActionState::ptr(UndoState);
304 else {
305 return Action::failure;
306 }
307}
308
309ActionState::ptr FillSuspendInMoleculeAction::performUndo(ActionState::ptr _state) {
310 FillSuspendInMoleculeState *state = assert_cast<FillSuspendInMoleculeState*>(_state.get());
311
312 // remove all created atoms
313 RemoveAtomsFromAtomicInfo(state->clonedatoms);
314 // add the original cluster
315 SetAtomsFromAtomicInfo(state->movedatoms);
316
317 return ActionState::ptr(_state);
318}
319
320ActionState::ptr FillSuspendInMoleculeAction::performRedo(ActionState::ptr _state){
321 FillSuspendInMoleculeState *state = assert_cast<FillSuspendInMoleculeState*>(_state.get());
322
323 // place filler cluster again at new spot
324 ResetAtomPosition(state->movedatoms, state->MovedToVector);
325
326 // re-create all clusters
327 bool statusflag = AddAtomsFromAtomicInfo(state->clonedatoms);
328
329 // re-create the bonds
330 if (statusflag)
331 AddBondsFromBondInfo(state->clonedbonds);
332 if (statusflag)
333 return ActionState::ptr(_state);
334 else {
335 STATUS("Failed re-adding filled in atoms.");
336 return Action::failure;
337 }
338}
339
340bool FillSuspendInMoleculeAction::canUndo() {
341 return false;
342}
343
344bool FillSuspendInMoleculeAction::shouldUndo() {
345 return false;
346}
347/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.