source: src/Actions/FillAction/SuspendInMoleculeAction.cpp@ 23b6cf

Last change on this file since 23b6cf was aa55d0, checked in by Frederik Heber <heber@…>, 11 years ago

Moved and renamed SuspendInWaterAction from Molecule.. to FillAction/SuspendInMoleculeAction.

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