source: src/LinkedCell/LinkedCell_Controller.cpp@ 4a8169

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 4a8169 was 4a8169, checked in by Frederik Heber <heber@…>, 14 years ago

LinkedCell_Controller is now an Observer.

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