source: src/LinkedCell/LinkedCell_Controller.cpp@ d66cb7

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

Updated all source files's copyright note to current year 2012.

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