source: src/LinkedCell/LinkedCell_Controller.cpp@ c96423

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 c96423 was ce81e76, checked in by Frederik Heber <heber@…>, 13 years ago

LinkedCell_Controller now signs on to Channel WorldTime::TimeChanged.

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