source: src/Actions/FragmentationAction/FragmentationAutomationAction.cpp@ ce70d25

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator 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_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions 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 GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since ce70d25 was 7debff, checked in by Frederik Heber <heber@…>, 9 years ago

VMGData additionally stores absolute residual.

  • we check for absolute residual to be less than 1e-5 in any case, otherwise issue a warning.
  • either relative or absolute residual must be less than precision. This is the check used by vmg. Otherwise we may get false failed convergence warnings because not relative but absolute residual reached precision threshold.
  • Property mode set to 100644
File size: 16.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * FragmentationAutomationAction.cpp
26 *
27 * Created on: May 18, 2012
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include <boost/archive/text_iarchive.hpp>
37// boost asio needs specific operator new
38#include <boost/asio.hpp>
39
40#include "CodePatterns/MemDebug.hpp"
41
42//// include headers that implement a archive in simple text format
43#include <boost/archive/text_oarchive.hpp>
44#include <boost/archive/text_iarchive.hpp>
45
46//
47//#include <boost/mpl/remove.hpp>
48//#include <boost/lambda/lambda.hpp>
49
50//#include <iostream>
51
52#include "CodePatterns/Assert.hpp"
53#include "CodePatterns/Info.hpp"
54#include "CodePatterns/Log.hpp"
55
56#ifdef HAVE_JOBMARKET
57#include "JobMarket/Jobs/FragmentJob.hpp"
58#else
59#include "Jobs/JobMarket/FragmentJob.hpp"
60#endif
61
62#include "Fragmentation/Automation/FragmentJobQueue.hpp"
63#ifdef HAVE_JOBMARKET
64#include "Fragmentation/Automation/MPQCFragmentController.hpp"
65#else
66#include "Fragmentation/Automation/MPQCCommandFragmentController.hpp"
67#endif
68#include "Fragmentation/Summation/Containers/FragmentationChargeDensity.hpp"
69#include "Fragmentation/Summation/Containers/FragmentationLongRangeResults.hpp"
70#include "Fragmentation/Summation/Containers/FragmentationResultContainer.hpp"
71#include "Fragmentation/Summation/Containers/FragmentationShortRangeResults.hpp"
72#include "Fragmentation/Summation/Containers/MPQCData.hpp"
73#include "Fragmentation/KeySetsContainer.hpp"
74#if defined(HAVE_JOBMARKET) && defined(HAVE_VMG)
75#include "Fragmentation/Automation/VMGDebugGridFragmentController.hpp"
76#include "Fragmentation/Automation/VMGFragmentController.hpp"
77#include "Fragmentation/Summation/Containers/VMGData.hpp"
78#include "Fragmentation/Summation/Containers/VMGDataFused.hpp"
79#include "Fragmentation/Summation/Containers/VMGDataMap.hpp"
80#include "Fragmentation/Summation/Containers/VMGData_printKeyNames.hpp"
81#endif
82#include "World.hpp"
83
84#include <boost/bind.hpp>
85#include <boost/thread.hpp>
86#include <fstream>
87#include <iostream>
88#include <string>
89#include <vector>
90
91#include <boost/mpl/for_each.hpp>
92
93#include "Actions/FragmentationAction/FragmentationAutomationAction.hpp"
94
95using namespace MoleCuilder;
96
97// and construct the stuff
98#include "FragmentationAutomationAction.def"
99#include "Action_impl_pre.hpp"
100/** =========== define the function ====================== */
101
102class controller_AddOn;
103
104// needs to be defined for using the FragmentController
105controller_AddOn *getAddOn()
106{
107 return NULL;
108}
109
110static void updateSteps(Process &p, const size_t step, const size_t total)
111{
112 LOG(1, "There are " << step << " steps out of " << total << " done.");
113 p.setCurrStep(step);
114}
115
116template <class ResultClass>
117std::pair<double, double> getResiduals(const ResultClass &_result)
118{ return std::pair<double, double>(0.,0.); }
119
120std::pair<double, double> getResiduals(const MPQCData &_result)
121{ return std::make_pair(_result.accuracy, _result.desired_accuracy); }
122
123std::pair<double, double> getResiduals(const VMGData &_result)
124{
125 // sensibility check on absolute residual
126 if (_result.residual > 1e-5)
127 ELOG(2, "Encountered absolute residual greater than 1e-5: " << _result.residual);
128 // take smaller value of the two as just one of them needs to be less than precision
129 const double residual = std::min(_result.relative_residual, _result.residual);
130 return std::make_pair(residual, _result.precision);
131}
132
133template <class ResultClass>
134bool checkResults(const typename std::map<JobId_t, ResultClass> &_results)
135{
136 bool result = true;
137 for (typename std::map<JobId_t, ResultClass>::const_iterator iter = _results.begin();
138 iter != _results.end(); ++iter) {
139 std::pair<double, double> residuals = getResiduals(iter->second);
140 if (residuals.second != 0.) {
141 if (residuals.first >= residuals.second) {
142 ELOG(1, "Fragment Job " << iter->first << " converged to " << residuals.first
143 << " instead of " << residuals.second);
144 result = false;
145 }
146 } else {
147 LOG(4, "DEBUG: Not checking accuracy because desired precision not given.");
148 }
149 }
150 return result;
151}
152
153ActionState::ptr FragmentationFragmentationAutomationAction::performCall() {
154 boost::asio::io_service io_service;
155
156 // TODO: Have io_service run in second thread and merge with current again eventually
157
158 FragmentationResultContainer &container =
159 FragmentationResultContainer::getInstance();
160 const KeySetsContainer& keysets = FragmentJobQueue::getInstance().getKeySets();
161 const KeySetsContainer& forcekeysets = FragmentJobQueue::getInstance().getFullKeySets();
162
163 size_t Exitflag = 0;
164 std::map<JobId_t, MPQCData> shortrangedata;
165#ifdef HAVE_JOBMARKET
166 {
167 const size_t NumberJobs = FragmentJobQueue::getInstance().size();
168 MPQCFragmentController mpqccontroller(io_service);
169 mpqccontroller.setHost(params.host.get());
170 mpqccontroller.setPort(params.port.get());
171 // Phase One: obtain ids
172 mpqccontroller.requestIds(NumberJobs);
173 if (mpqccontroller.getExitflag() != 0)
174 return Action::failure;
175
176 // Phase Two: add MPQCJobs and send
177 const bool AddJobsStatus = mpqccontroller.addJobsFromQueue(
178 params.DoLongrange.get() ? MPQCData::DoSampleDensity : MPQCData::DontSampleDensity,
179 params.DoValenceOnly.get() ? MPQCData::DoSampleValenceOnly : MPQCData::DontSampleValenceOnly
180 );
181 if (AddJobsStatus)
182 LOG(1, "INFO: Added jobs from FragmentJobsQueue.");
183 else {
184 ELOG(1, "Adding jobs failed.");
185 return Action::failure;
186 }
187 mpqccontroller.run();
188
189 // Phase Three: calculate result
190 setMaxSteps(NumberJobs);
191 mpqccontroller.setUpdateHandler(
192 boost::bind(&updateSteps, boost::ref(*this), _1, _2)
193 );
194 start();
195 boost::thread wait_thread(
196 boost::bind(&MPQCFragmentController::waitforResults, boost::ref(mpqccontroller), boost::cref(NumberJobs))
197 );
198 wait_thread.join();
199 stop();
200 if (mpqccontroller.getExitflag() != 0)
201 return Action::failure;
202
203 mpqccontroller.getResults(shortrangedata);
204 if (!checkResults(shortrangedata)) {
205 ELOG(1, "At least one of the fragments' energy could not be properly minimized.");
206 return Action::failure;
207 }
208 if (mpqccontroller.getExitflag() != 0) {
209 ELOG(1, "MPQCCommandFragmentController returned non-zero exit flag.");
210 return Action::failure;
211 }
212
213 Exitflag += mpqccontroller.getExitflag();
214 }
215#else
216 {
217 const size_t NumberJobs = FragmentJobQueue::getInstance().size();
218 MPQCCommandFragmentController mpqccontroller;
219 // Phase One: obtain ids: not needed, we have infinite pool
220
221 // Phase Two: add MPQCJobs and send
222 const size_t NoJobs = mpqccontroller.addJobsFromQueue(
223 params.DoLongrange.get() ? MPQCData::DoSampleDensity : MPQCData::DontSampleDensity,
224 params.DoValenceOnly.get() ? MPQCData::DoSampleValenceOnly : MPQCData::DontSampleValenceOnly,
225 params.executable.get().string()
226 );
227 if (NoJobs != NumberJobs) {
228 ELOG(1, "Not all jobs were added succesfully.");
229 return Action::failure;
230 }
231 LOG(1, "INFO: Added " << NoJobs << " from FragmentJobsQueue.");
232
233 // prepare process
234 setMaxSteps(NumberJobs);
235 mpqccontroller.setUpdateHandler(
236 boost::bind(&updateSteps, boost::ref(*this), _1, _2)
237 );
238 start();
239 mpqccontroller.run();
240 stop();
241 if (mpqccontroller.getExitflag() != 0) {
242 ELOG(1, "MPQCCommandFragmentController returned non-zero exit flag before getting results.");
243 return Action::failure;
244 }
245
246 // get back the results and place them in shortrangedata
247 mpqccontroller.getResults(shortrangedata);
248 ASSERT( shortrangedata.size() == NumberJobs,
249 "FragmentationFragmentationAutomationAction::performCall() - number of converted results "
250 +toString(shortrangedata.size())+" and number of jobs "+toString(NumberJobs)+ " differ.");
251 if (!checkResults(shortrangedata)) {
252 ELOG(1, "At least one of the fragments' energy could not be properly minimized.");
253 return Action::failure;
254 }
255 if (mpqccontroller.getExitflag() != 0) {
256 ELOG(1, "MPQCCommandFragmentController returned non-zero exit flag after getting results.");
257 return Action::failure;
258 }
259
260 Exitflag += mpqccontroller.getExitflag();
261 }
262#endif
263
264#if defined(HAVE_JOBMARKET) && defined(HAVE_VMG)
265 if (params.DoLongrange.get()) {
266 if ( const_cast<const World &>(World::getInstance()).getAllAtoms().size() == 0) {
267 STATUS("Please load the full molecule into the world before starting this action.");
268 return Action::failure;
269 }
270
271 // obtain combined charge density
272 FragmentationChargeDensity summedChargeDensity(
273 shortrangedata,
274 FragmentJobQueue::getInstance().getKeySets());
275 const std::vector<SamplingGrid> full_sample = summedChargeDensity.getFullSampledGrid();
276 LOG(1, "INFO: There are " << shortrangedata.size() << " short-range and "
277 << full_sample.size() << " level-wise long-range jobs.");
278
279 // check boundary conditions
280 const BoundaryConditions::Conditions_t &conditions =
281 World::getInstance().getDomain().getConditions();
282 const bool OpenBoundaryConditions =
283 !((conditions[0] == BoundaryConditions::Wrap) &&
284 (conditions[1] == BoundaryConditions::Wrap) &&
285 (conditions[2] == BoundaryConditions::Wrap));
286 LOG(1, std::string("INFO: Using ")
287 << (OpenBoundaryConditions ? "open" : "periodic")
288 << " boundary conditions.");
289
290 // Phase Four: obtain more ids
291 std::map<JobId_t, VMGData> longrangedata;
292 {
293 VMGFragmentController vmgcontroller(io_service);
294 vmgcontroller.setHost(params.host.get());
295 vmgcontroller.setPort(params.port.get());
296 const size_t NoJobs = shortrangedata.size()+full_sample.size();
297 vmgcontroller.requestIds(2*NoJobs);
298 if (vmgcontroller.getExitflag() != 0) {
299 ELOG(1, "VMGFragmentController returned non-zero exit flag on requesting long-range ids.");
300 return Action::failure;
301 }
302
303 // Phase Five a: create VMGJobs for electronic charge distribution
304 const size_t near_field_cells = params.near_field_cells.get();
305 const size_t interpolation_degree = params.interpolation_degree.get();
306 if (!vmgcontroller.createLongRangeJobs(
307 shortrangedata,
308 full_sample,
309 near_field_cells,
310 interpolation_degree,
311 VMGFragmentController::DontSampleParticles,
312 VMGFragmentController::DoTreatGrid,
313 params.DoValenceOnly.get() ? MPQCData::DoSampleValenceOnly : MPQCData::DontSampleValenceOnly,
314 params.DoPrintDebug.get(),
315 OpenBoundaryConditions,
316 params.DoSmearCharges.get(),
317 false)) {
318 STATUS("Could not create long-range jobs for electronic charge distribution.");
319 return Action::failure;
320 }
321
322 // Phase Six a: calculate result
323 vmgcontroller.waitforResults(NoJobs);
324 if (vmgcontroller.getExitflag() != 0) {
325 ELOG(1, "VMGFragmentController returned non-zero exit flag before getting results.");
326 return Action::failure;
327 }
328 vmgcontroller.getResults(longrangedata);
329 ASSERT( NoJobs == longrangedata.size(),
330 "FragmentationFragmentationAutomationAction::performCall() - number of MPQCresults+"
331 +toString(full_sample.size())+"="+toString(NoJobs)
332 +" and first VMGresults "+toString(longrangedata.size())+" don't match.");
333 if (!checkResults(longrangedata)) {
334 ELOG(1, "At least one of the fragments' electronic long-range potential could not be properly minimized.");
335 return Action::failure;
336 }
337 Exitflag += vmgcontroller.getExitflag();
338
339 {
340 std::map<JobId_t, VMGData> longrangedata_both;
341 // Phase Five b: create VMGJobs for nuclei charge distributions
342 const size_t near_field_cells = params.near_field_cells.get();
343 const size_t interpolation_degree = params.interpolation_degree.get();
344 if (!vmgcontroller.createLongRangeJobs(
345 shortrangedata,
346 full_sample,
347 near_field_cells,
348 interpolation_degree,
349 VMGFragmentController::DoSampleParticles,
350 VMGFragmentController::DoTreatGrid,
351 params.DoValenceOnly.get() ? MPQCData::DoSampleValenceOnly : MPQCData::DontSampleValenceOnly,
352 params.DoPrintDebug.get(),
353 OpenBoundaryConditions,
354 params.DoSmearCharges.get(),
355 params.UseImplicitCharges.get())) {
356 STATUS("Could not create long-range jobs for nuclei charge distribution.");
357 return Action::failure;
358 }
359
360 // Phase Six b: calculate result
361 vmgcontroller.waitforResults(NoJobs);
362 if (vmgcontroller.getExitflag() != 0)
363 return Action::failure;
364 vmgcontroller.getResults(longrangedata_both);
365 ASSERT( NoJobs == longrangedata_both.size(),
366 "FragmentationFragmentationAutomationAction::performCall() - number of MPQCresults+"
367 +toString(full_sample.size())+"="+toString(NoJobs)
368 +" and second VMGresults "+toString(longrangedata_both.size())+" don't match.");
369 if (!checkResults(longrangedata_both)) {
370 ELOG(1, "At least one of the fragments' nuclei long-range potential could not be properly minimized.");
371 return Action::failure;
372 }
373 if (vmgcontroller.getExitflag() != 0) {
374 ELOG(1, "VMGFragmentController returned non-zero exit flag after getting results.");
375 return Action::failure;
376 }
377 Exitflag += vmgcontroller.getExitflag();
378
379 // go through either data and replace nuclei_long with contribution from both
380 ASSERT( longrangedata.size() == longrangedata_both.size(),
381 "FragmentationFragmentationAutomationAction::performCall() - longrange results have different sizes.");
382 std::map<JobId_t, VMGData>::iterator destiter = longrangedata.begin();
383 std::map<JobId_t, VMGData>::const_iterator srciter = longrangedata_both.begin();
384 for (;destiter != longrangedata.end(); ++srciter, ++destiter) {
385 destiter->second.both_sampled_potential = srciter->second.sampled_potential;
386 destiter->second.nuclei_long = srciter->second.nuclei_long;
387 destiter->second.forces = srciter->second.forces;
388 destiter->second.hasForces = srciter->second.hasForces;
389 }
390 }
391 }
392
393 if (params.DoPrintDebug.get()) {
394 std::map<JobId_t, std::string> debugData;
395 {
396 if (!full_sample.empty()) {
397 // create debug jobs for each level to print the summed-up potential to vtk files
398 VMGDebugGridFragmentController debugcontroller(io_service);
399 debugcontroller.setHost(params.host.get());
400 debugcontroller.setPort(params.port.get());
401 debugcontroller.requestIds(full_sample.size());
402 if (!debugcontroller.createDebugJobs(full_sample, OpenBoundaryConditions)) {
403 STATUS("Could not create debug jobs.");
404 return Action::failure;
405 }
406 debugcontroller.waitforResults(full_sample.size());
407 debugcontroller.getResults(debugData);
408 Exitflag += debugcontroller.getExitflag();
409 }
410 }
411 }
412 container.addFullResults(keysets, forcekeysets, shortrangedata, longrangedata);
413 } else {
414 container.addShortRangeResults(keysets, forcekeysets, shortrangedata);
415 }
416#else
417 container.addShortRangeResults(keysets, forcekeysets, shortrangedata);
418#endif
419
420 // now clear all present jobs as we are done
421 FragmentJobQueue::getInstance().clear();
422
423 // if file is given, advise results container to store to file
424 if (!params.resultsfile.get().empty()) {
425 boost::filesystem::path resultsfile = params.resultsfile.get();
426 std::ofstream returnstream(resultsfile.string().c_str());
427 if (returnstream.good()) {
428 boost::archive::text_oarchive oa(returnstream);
429 oa << container;
430 }
431 Exitflag += (int)(!returnstream.good());
432 returnstream.close();
433 }
434
435 if (Exitflag != 0)
436 STATUS("Controller has returned failure.");
437 return (Exitflag == 0) ? Action::success : Action::failure;
438}
439
440ActionState::ptr FragmentationFragmentationAutomationAction::performUndo(ActionState::ptr _state) {
441 return Action::success;
442}
443
444ActionState::ptr FragmentationFragmentationAutomationAction::performRedo(ActionState::ptr _state){
445 return Action::success;
446}
447
448bool FragmentationFragmentationAutomationAction::canUndo() {
449 return false;
450}
451
452bool FragmentationFragmentationAutomationAction::shouldUndo() {
453 return false;
454}
455/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.