source: src/LinkedCell/LinkedCell_Controller.cpp@ b4f72c

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 b4f72c was 94d5ac6, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

  • GNU Scientific Library is used at every place in the code, especially the sub-package LinearAlgebra is based on it which in turn is used really everywhere in the remainder of MoleCuilder. Hence, we have to use the GPL license for the whole of MoleCuilder. In effect, GPL's COPYING was present all along and stated the terms of the GPL v2 license.
  • Hence, I added the default GPL v2 disclaimer to every source file and removed the note about a (actually missing) LICENSE file.
  • also, I added a help-redistribute action which again gives the disclaimer of the GPL v2.
  • also, I changed in the disclaimer that is printed at every program start in builder_init.cpp.
  • TEST: Added check on GPL statement present in every module to test CodeChecks project-disclaimer.
  • Property mode set to 100644
File size: 13.5 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. 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 * LinkedCell_Controller.cpp
25 *
26 * Created on: Nov 15, 2011
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 <set>
38
39#include "Box.hpp"
40#include "CodePatterns/Assert.hpp"
41#include "CodePatterns/Log.hpp"
42#include "CodePatterns/Observer/Notification.hpp"
43#include "CodePatterns/Range.hpp"
44#include "LinkedCell_Controller.hpp"
45#include "LinkedCell_Model.hpp"
46#include "LinkedCell_View.hpp"
47#include "LinkedCell_View_ModelWrapper.hpp"
48#include "IPointCloud.hpp"
49#include "WorldTime.hpp"
50
51
52using namespace LinkedCell;
53
54double LinkedCell_Controller::lower_threshold = 1.;
55double LinkedCell_Controller::upper_threshold = 20.;
56
57/** Constructor of class LinkedCell_Controller.
58 *
59 */
60LinkedCell_Controller::LinkedCell_Controller(const Box &_domain) :
61 Observer("LinkedCell_Controller"),
62 domain(_domain)
63{
64 // sign on to specific notifications
65 domain.signOn(this, Box::MatrixChanged);
66 WorldTime::getInstance().signOn(this, WorldTime::TimeChanged);
67
68 /// Check that upper_threshold fits within half the box.
69 Vector diagonal(1.,1.,1.);
70 diagonal.Scale(upper_threshold);
71 Vector diagonal_transformed = domain.getMinv() * diagonal;
72 double max_factor = 1.;
73 for (size_t i=0; i<NDIM; ++i)
74 if (diagonal_transformed.at(i) > 1./max_factor)
75 max_factor = 1./diagonal_transformed.at(i);
76 upper_threshold *= max_factor;
77
78 /// Check that lower_threshold is still lower, if not set to half times upper_threshold.
79 if (lower_threshold > upper_threshold)
80 lower_threshold = 0.5*upper_threshold;
81}
82
83/** Destructor of class LinkedCell_Controller.
84 *
85 * Here, we free all LinkedCell_Model instances again.
86 *
87 */
88LinkedCell_Controller::~LinkedCell_Controller()
89{
90 // sign off
91 domain.signOff(this, Box::MatrixChanged);
92 WorldTime::getInstance().signOff(this, WorldTime::TimeChanged);
93
94 /// we free all LinkedCell_Model instances again.
95 for(MapEdgelengthModel::iterator iter = ModelsMap.begin();
96 !ModelsMap.empty(); iter = ModelsMap.begin()) {
97 delete iter->second;
98 ModelsMap.erase(iter);
99 }
100}
101
102/** Internal function to obtain the range within which an model is suitable.
103 *
104 * \note We use statics lower_threshold and upper_threshold as min and max
105 * boundaries.
106 *
107 * @param distance desired egde length
108 * @return range within which model edge length is acceptable
109 */
110const range<double> LinkedCell_Controller::getHeuristicRange(const double distance) const
111{
112 const double lower = 0.5*distance < lower_threshold ? lower_threshold : 0.5*distance;
113 const double upper = 2.*distance > upper_threshold ? upper_threshold : 2.*distance;
114 range<double> HeuristicInterval(lower, upper);
115 return HeuristicInterval;
116}
117
118/** Internal function to decide whether a suitable model is present or not.
119 *
120 * Here, the heuristic for deciding whether a new linked cell structure has to
121 * be constructed or not is implemented. The current heuristic is as follows:
122 * -# the best model should have at least half the desired length (such
123 * that most we have to look two neighbor shells wide and not one).
124 * -# the best model should have at most twice the desired length but
125 * no less than 1 angstroem.
126 *
127 * \note Dealing out a pointer is here (hopefully) safe because the function is
128 * internal and we - inside this class - know what we are doing.
129 *
130 * @param distance edge length of the requested linked cell structure
131 * @return NULL - there is no fitting LinkedCell_Model, else - pointer to instance
132 */
133const LinkedCell_Model *LinkedCell_Controller::getBestModel(double distance) const
134{
135 /// Bound distance to be within [lower_threshold, upper_threshold).
136 /// Note that we need to stay away from upper boundary a bit,
137 /// otherwise the distance will end up outside of the interval.
138 if (distance < lower_threshold)
139 distance = lower_threshold;
140 if (distance > upper_threshold)
141 distance = upper_threshold - std::numeric_limits<double>::round_error();
142
143 /// Look for all models within [0.5 distance, 2. distance).
144 MapEdgelengthModel::const_iterator bestmatch = ModelsMap.end();
145 if (!ModelsMap.empty()) {
146 for(MapEdgelengthModel::const_iterator iter = ModelsMap.begin();
147 iter != ModelsMap.end(); ++iter) {
148 // check that we are truely within range
149 range<double> HeuristicInterval(getHeuristicRange(iter->first));
150 if (HeuristicInterval.isInRange(distance)) {
151 // if it's the first match or a closer one, pick
152 if ((bestmatch == ModelsMap.end())
153 || (fabs(bestmatch->first - distance) > fabs(iter->first - distance)))
154 bestmatch = iter;
155 }
156 }
157 }
158
159 /// Return best match or NULL if none found.
160 if (bestmatch != ModelsMap.end())
161 return bestmatch->second;
162 else
163 return NULL;
164}
165
166/** Internal function to insert a new model and check for valid insertion.
167 *
168 * @param distance edge length of new model
169 * @param instance pointer to model
170 */
171void LinkedCell_Controller::insertNewModel(const double edgelength, const LinkedCell_Model* instance)
172{
173 std::pair< MapEdgelengthModel::iterator, bool> inserter =
174 ModelsMap.insert( std::make_pair(edgelength, instance) );
175 ASSERT(inserter.second,
176 "LinkedCell_Controller::getView() - LinkedCell_Model instance with distance "
177 +toString(edgelength)+" already present.");
178}
179
180/** Returns the a suitable LinkedCell_Model contained in a LinkedCell_View
181 * for the requested \a distance.
182 *
183 * \sa getBestModel()
184 *
185 * @param distance edge length of the requested linked cell structure
186 * @param set of initial points to insert when new model is created (not always), should be World's
187 * @return LinkedCell_View wrapping the best LinkedCell_Model
188 */
189LinkedCell_View LinkedCell_Controller::getView(const double distance, IPointCloud &set)
190{
191 /// Look for best instance.
192 const LinkedCell_Model * const LCModel_best = getBestModel(distance);
193
194 /// Construct new instance if none found,
195 if (LCModel_best == NULL) {
196 LinkedCell_Model * const LCModel_new = new LinkedCell_Model(distance, domain);
197 LCModel_new->insertPointCloud(set);
198 insertNewModel(distance, LCModel_new);
199 LinkedCell_View view(*LCModel_new);
200 return view;
201 } else {
202 /// else construct interface and return.
203 LinkedCell_View view(*LCModel_best);
204 return view;
205 }
206}
207
208/** Internal function to re-create all present and used models for the new Box.
209 *
210 * This is necessary in the following cases:
211 * -# the Box is changed
212 * -# we step on to a different time step, i.e. all atomic positions change
213 *
214 * The main problem are the views currently in use.
215 *
216 * We make use of LinkedCell:LinkedCell_View::RAIIMap as there all present are
217 * listed. We go through the list, create a map with old model ref as keys to
218 * just newly created ones, and finally go again through each view and exchange
219 * the model against the new ones via a simple map lookup.
220 *
221 */
222void LinkedCell_Controller::updateModels()
223{
224 LOG(1, "INFO: Updating all models.");
225
226 typedef std::map<const LinkedCell_Model *, LinkedCell_Model *> ModelLookup;
227 ModelLookup models;
228
229 // set up map, for now with NULL pointers
230 for (LinkedCell_View::ModelInstanceMap::const_iterator iter = LinkedCell_View::RAIIMap.begin();
231 iter != LinkedCell_View::RAIIMap.end(); ++iter) {
232#ifndef NDEBUG
233 std::pair< ModelLookup::iterator, bool > inserter =
234#endif
235 models.insert( std::pair<const LinkedCell_Model *, LinkedCell_Model *>( (*iter)->LC->getModel(), NULL) );
236 LOG(2, "INFO: Added " << (*iter)->LC->getModel() << " to list of models to replace.");
237 ASSERT( inserter.second,
238 "LinkedCell_Controller::updateModelsForNewBoxMatrix() - failed to insert old model "
239 +toString( (*iter)->LC->getModel() )+","+toString(NULL)+" into models, is already present");
240 }
241
242 // invert MapEdgelengthModel
243 LOG(2, "INFO: ModelsMap is " << ModelsMap << ".");
244 typedef std::map<const LinkedCell_Model*, double > MapEdgelengthModel_inverted;
245 MapEdgelengthModel_inverted ModelsMap_inverted;
246 for (MapEdgelengthModel::const_iterator iter = ModelsMap.begin();
247 iter != ModelsMap.end(); ++iter) {
248#ifndef NDEBUG
249 MapEdgelengthModel_inverted::const_iterator assertiter = ModelsMap_inverted.find(iter->second);
250 ASSERT( assertiter == ModelsMap_inverted.end(),
251 "LinkedCell_Controller::updateModelsForNewBoxMatrix() - ModelsMap is not invertible, value "
252 +toString(iter->second)+" is already present.");
253#endif
254 ModelsMap_inverted.insert( std::make_pair(iter->second, iter->first) );
255 }
256 LOG(2, "INFO: Inverted ModelsMap is " << ModelsMap_inverted << ".");
257
258 // go through map and re-create models
259 for (ModelLookup::iterator iter = models.begin(); iter != models.end(); ++iter) {
260 // delete old model
261 const LinkedCell_Model * const oldref = iter->first;
262#ifndef NDEBUG
263 MapEdgelengthModel_inverted::const_iterator assertiter = ModelsMap_inverted.find(oldref);
264 ASSERT( assertiter != ModelsMap_inverted.end(),
265 "LinkedCell_Controller::updateModelsForNewBoxMatrix() - ModelsMap_inverted does not contain old model "
266 +toString(oldref)+".");
267#endif
268 const double distance = ModelsMap_inverted[oldref];
269 // create new one, afterwards erase old model (this is for unit test to get different memory addresses)
270 LinkedCell_Model * const newref = new LinkedCell_Model(distance, domain);
271 MapEdgelengthModel::iterator oldmodeliter = ModelsMap.find(distance);
272 delete oldmodeliter->second;
273 ModelsMap.erase(oldmodeliter);
274 LOG(2, "INFO: oldref is " << oldref << ", newref is " << newref << ".");
275 iter->second = newref;
276 // replace in ModelsMap
277#ifndef NDEBUG
278 std::pair< MapEdgelengthModel::iterator, bool > inserter =
279#endif
280 ModelsMap.insert( std::make_pair(distance, newref) );
281 ASSERT( inserter.second,
282 "LinkedCell_Controller::updateModelsForNewBoxMatrix() - failed to insert new model "
283 +toString(distance)+","+toString(newref)+" into ModelsMap, is already present");
284 }
285
286 // remove all remaining active models (also those that don't have an active View on them)
287 for (MapEdgelengthModel::iterator iter = ModelsMap.begin();
288 !ModelsMap.empty();
289 iter = ModelsMap.begin()) {
290 delete iter->second;
291 ModelsMap.erase(iter);
292 }
293
294
295 // delete inverted map for safety (values are gone)
296 ModelsMap_inverted.clear();
297
298 // go through views and exchange the models
299 for (LinkedCell_View::ModelInstanceMap::const_iterator iter = LinkedCell_View::RAIIMap.begin();
300 iter != LinkedCell_View::RAIIMap.end(); ++iter) {
301 ModelLookup::const_iterator modeliter = models.find((*iter)->LC->getModel());
302 ASSERT( modeliter != models.end(),
303 "LinkedCell_Controller::updateModelsForNewBoxMatrix() - we miss a model "
304 +toString((*iter)->LC->getModel())+" in ModelLookup.");
305 // this is ugly but the only place where we have to set ourselves over the constness of the member variable
306 if (modeliter != models.end()) {
307 LOG(2, "INFO: Setting model to " << modeliter->second << " in view " << *iter << ".");
308 (*iter)->LC->setModel(modeliter->second);
309 }
310 }
311}
312
313/** Callback function for Observer mechanism.
314 *
315 * @param publisher reference to the Observable that calls
316 */
317void LinkedCell_Controller::update(Observable *publisher)
318{
319 ELOG(2, "LinkedCell_Model received inconclusive general update from "
320 << publisher << ".");
321}
322
323/** Callback function for the Notifications mechanism.
324 *
325 * @param publisher reference to the Observable that calls
326 * @param notification specific notification as cause of the call
327 */
328void LinkedCell_Controller::recieveNotification(Observable *publisher, Notification_ptr notification)
329{
330 if (publisher == &domain) {
331 switch(notification->getChannelNo()) {
332 case Box::MatrixChanged:
333 LOG(1, "INFO: LinkedCell_Controller got update from Box.");
334 updateModels();
335 break;
336 default:
337 ASSERT(0,
338 "LinkedCell_Controller::recieveNotification() - unwanted notification from Box "
339 +toString(notification->getChannelNo())+" received.");
340 break;
341 }
342 } else if (publisher == WorldTime::getPointer()) {
343 switch(notification->getChannelNo()) {
344 case WorldTime::TimeChanged:
345 LOG(1, "INFO: LinkedCell_Controller got update from WorldTime.");
346 updateModels();
347 break;
348 default:
349 ASSERT(0,
350 "LinkedCell_Controller::recieveNotification() - unwanted notification from WorldTime "
351 +toString(notification->getChannelNo())+" received.");
352 break;
353 }
354 } else {
355 ELOG(1, "Notification " << notification->getChannelNo()
356 << " from unknown publisher " << publisher << ".");
357 }
358}
359
360/** Callback function when an Observer dies.
361 *
362 * @param publisher reference to the Observable that calls
363 */
364void LinkedCell_Controller::subjectKilled(Observable *publisher)
365{}
366
Note: See TracBrowser for help on using the repository browser.