source: src/LinkedCell/LinkedCell_Controller.cpp@ 5e2864

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 Candidate_v1.7.0 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 5e2864 was 5e2864, checked in by Frederik Heber <heber@…>, 14 years ago

FIX: LinkedCell_Controller now signs on to Channel Box::MatrixChanged.

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