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

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

Added Fragment to MPQCData fusion maps and is used in FragmentationAutomationAction.

  • new helpers Fragment::getPositions() and ::getCharges().
  • SumUpChargeDensity() now also sums up a full Fragment.
  • the Fragment is used by createLongRangeJobs to extract required posittions and charges from.
  • Property mode set to 100644
File size: 31.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 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * FragmentationAutomationAction.cpp
25 *
26 * Created on: May 18, 2012
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include <boost/archive/text_iarchive.hpp>
36// boost asio needs specific operator new
37#include <boost/asio.hpp>
38
39#include "CodePatterns/MemDebug.hpp"
40
41#include <boost/mpl/remove.hpp>
42
43#include "CodePatterns/Assert.hpp"
44#include "CodePatterns/Info.hpp"
45#include "CodePatterns/Log.hpp"
46#include "JobMarket/Controller/FragmentController.hpp"
47#include "JobMarket/Jobs/FragmentJob.hpp"
48
49#include "Atom/atom.hpp"
50#include "Box.hpp"
51#include "Fragmentation/EnergyMatrix.hpp"
52#include "Fragmentation/ForceMatrix.hpp"
53#include "Fragmentation/Fragmentation.hpp"
54#include "Fragmentation/SetValues/Fragment.hpp"
55#include "Fragmentation/SetValues/Histogram.hpp"
56#include "Fragmentation/SetValues/IndexedVectors.hpp"
57#include "Fragmentation/HydrogenSaturation_enum.hpp"
58#include "Fragmentation/KeySet.hpp"
59#include "Fragmentation/KeySetsContainer.hpp"
60#include "Fragmentation/Summation/AllLevelOrthogonalSummator.hpp"
61#include "Fragmentation/Summation/AllLevelSummator.hpp"
62#include "Fragmentation/Summation/writeTable.hpp"
63#include "Graph/DepthFirstSearchAnalysis.hpp"
64#include "Helpers/defs.hpp"
65#include "Jobs/MPQCJob.hpp"
66#include "Jobs/MPQCData.hpp"
67#include "Jobs/MPQCData_printKeyNames.hpp"
68#include "Jobs/Grid/SamplingGrid.hpp"
69#include "LinearAlgebra/RealSpaceMatrix.hpp"
70#ifdef HAVE_VMG
71#include "Jobs/VMGJob.hpp"
72#endif
73#include "molecule.hpp"
74#include "World.hpp"
75
76#include <iostream>
77#include <string>
78#include <vector>
79
80#include <boost/mpl/for_each.hpp>
81
82#include "Actions/FragmentationAction/FragmentationAutomationAction.hpp"
83
84using namespace MoleCuilder;
85
86// and construct the stuff
87#include "FragmentationAutomationAction.def"
88#include "Action_impl_pre.hpp"
89/** =========== define the function ====================== */
90
91class controller_AddOn;
92
93// needs to be defined for using the FragmentController
94controller_AddOn *getAddOn()
95{
96 return NULL;
97}
98
99const int LEVEL = 5;
100
101/** Creates a MPQCCommandJob with argument \a filename.
102 *
103 * @param jobs created job is added to this vector
104 * @param command mpqc command to execute
105 * @param filename filename being argument to job
106 * @param nextid id for this job
107 */
108void parsejob(
109 std::vector<FragmentJob::ptr> &jobs,
110 const std::string &command,
111 const std::string &filename,
112 const JobId_t nextid)
113{
114 std::ifstream file;
115 file.open(filename.c_str());
116 ASSERT( file.good(), "parsejob() - file "+filename+" does not exist.");
117 std::string output((std::istreambuf_iterator<char>(file)),
118 std::istreambuf_iterator<char>());
119 double begin[NDIM] = { 0., 0., 0. };
120 const RealSpaceMatrix& M = World::getInstance().getDomain().getM();
121 const double size = M.at(0,0);
122 ASSERT( M.determinant() == size*size*size,
123 "parsejob() - current domain matrix "+toString(M)+" is not cubic.");
124 const int level = LEVEL;
125 FragmentJob::ptr testJob( new MPQCJob(nextid, output, begin, size, level) );
126 jobs.push_back(testJob);
127 file.close();
128 LOG(1, "INFO: Added MPQCCommandJob from file "+filename+".");
129}
130
131/** Helper function to get number of atoms somehow.
132 *
133 * Here, we just parse the number of lines in the adjacency file as
134 * it should correspond to the number of atoms, except when some atoms
135 * are not bonded, but then fragmentation makes no sense.
136 *
137 * @param path path to the adjacency file
138 */
139size_t getNoAtomsFromAdjacencyFile(const std::string &path)
140{
141 size_t NoAtoms = 0;
142
143 // parse in special file to get atom count (from line count)
144 std::string filename(path);
145 filename += FRAGMENTPREFIX;
146 filename += ADJACENCYFILE;
147 std::ifstream adjacency(filename.c_str());
148 if (adjacency.fail()) {
149 LOG(0, endl << "getNoAtomsFromAdjacencyFile() - Unable to open " << filename << ", is the directory correct?");
150 return false;
151 }
152 std::string buffer;
153 while (getline(adjacency, buffer))
154 NoAtoms++;
155 LOG(1, "INFO: There are " << NoAtoms << " atoms.");
156
157 return NoAtoms;
158}
159
160/** Extracts MPQCData from received vector of FragmentResults.
161 *
162 * @param results results to extract MPQCData from
163 * @param fragmentData on return array filled with extracted MPQCData
164 */
165void ConvertFragmentResultToMPQCData(
166 const std::vector<FragmentResult::ptr> &results,
167 std::vector<MPQCData> &fragmentData)
168{
169 // extract results
170 fragmentData.clear();
171 fragmentData.reserve(results.size());
172
173 LOG(2, "DEBUG: Parsing now through " << results.size() << " results.");
174 for (std::vector<FragmentResult::ptr>::const_iterator iter = results.begin();
175 iter != results.end(); ++iter) {
176 //LOG(1, "RESULT: job #"+toString((*iter)->getId())+": "+toString((*iter)->result));
177 MPQCData extractedData;
178 std::stringstream inputstream((*iter)->result);
179 LOG(2, "DEBUG: First 50 characters FragmentResult's string: "+(*iter)->result.substr(0, 50));
180 boost::archive::text_iarchive ia(inputstream);
181 ia >> extractedData;
182 LOG(1, "INFO: extracted data is " << extractedData << ".");
183 fragmentData.push_back(extractedData);
184 }
185
186 ASSERT( results.size() == fragmentData.size(),
187 "ConvertFragmentResultToMPQCData() - the number of extracted data differs from the number of results.");
188}
189
190/** Creates a lookup from FragmentJob::id to the true fragment number.
191 *
192 * @param results result with job ids
193 * @param MatrixNrLookup Lookup up-map, filled on return
194 * @param FragmentCounter total number of fragments on return
195 */
196void createMatrixNrLookup(
197 const std::vector<FragmentResult::ptr> &results,
198 std::map< JobId_t, size_t > &MatrixNrLookup,
199 size_t &FragmentCounter)
200{
201 // align fragments
202 MatrixNrLookup.clear();
203 FragmentCounter = 0;
204 {
205 // bring ids in order ...
206 typedef std::map< JobId_t, FragmentResult::ptr> IdResultMap_t;
207 IdResultMap_t IdResultMap;
208 for (std::vector<FragmentResult::ptr>::const_iterator iter = results.begin();
209 iter != results.end(); ++iter) {
210 #ifndef NDEBUG
211 std::pair< IdResultMap_t::iterator, bool> inserter =
212 #endif
213 IdResultMap.insert( make_pair((*iter)->getId(), *iter) );
214 ASSERT( inserter.second,
215 "ExtractMPQCDataFromResults() - two results have same id "
216 +toString((*iter)->getId())+".");
217 }
218 // ... and fill lookup
219 for(IdResultMap_t::const_iterator iter = IdResultMap.begin();
220 iter != IdResultMap.end(); ++iter)
221 MatrixNrLookup.insert( make_pair(iter->first, FragmentCounter++) );
222 }
223 LOG(1, "INFO: There are " << FragmentCounter << " fragments.");
224}
225
226/** Place results from FragmentResult into EnergyMatrix and ForceMatrix.
227 *
228 * @param results results with ids to associate with fragment number
229 * @param fragmentData MPQCData resulting from the jobs
230 * @param MatrixNrLookup Lookup up-map from job id to fragment number
231 * @param FragmentCounter total number of fragments
232 * @param NoAtoms total number of atoms
233 * @param Energy energy matrix to be filled on return
234 * @param Force force matrix to be filled on return
235 * @return true - everything ok, false - else
236 */
237bool putResultsintoMatrices(
238 const std::vector<FragmentResult::ptr> &results,
239 const std::vector<MPQCData> &fragmentData,
240 std::map< JobId_t, size_t > &MatrixNrLookup,
241 const size_t FragmentCounter,
242 const size_t NoAtoms,
243 EnergyMatrix &Energy,
244 ForceMatrix &Force)
245{
246 ASSERT( results.size() == fragmentData.size(),
247 "printReceivedMPQCResults() - results and fragmentData differ in size.");
248 std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
249 std::vector<FragmentResult::ptr>::const_iterator resultiter = results.begin();
250 for (; dataiter != fragmentData.end(); ++dataiter, ++resultiter) {
251 const MPQCData &extractedData = *dataiter;
252 // place results into EnergyMatrix ...
253 {
254 MatrixContainer::MatrixArray matrix;
255 matrix.resize(1);
256 matrix[0].resize(1, extractedData.energies.total);
257 if (!Energy.AddMatrix(
258 std::string("MPQCJob ")+toString((*resultiter)->getId()),
259 matrix,
260 MatrixNrLookup[(*resultiter)->getId()])) {
261 ELOG(1, "Adding energy matrix failed.");
262 return false;
263 }
264 }
265 // ... and ForceMatrix (with two empty columns in front)
266 {
267 MatrixContainer::MatrixArray matrix;
268 const size_t rows = extractedData.forces.size();
269 matrix.resize(rows);
270 for (size_t i=0;i<rows;++i) {
271 const size_t columns = 2+extractedData.forces[i].size();
272 matrix[i].resize(columns, 0.);
273 // for (size_t j=0;j<2;++j)
274 // matrix[i][j] = 0.;
275 for (size_t j=2;j<columns;++j)
276 matrix[i][j] = extractedData.forces[i][j-2];
277 }
278 if (!Force.AddMatrix(
279 std::string("MPQCJob ")+toString((*resultiter)->getId()),
280 matrix,
281 MatrixNrLookup[(*resultiter)->getId()])) {
282 ELOG(1, "Adding force matrix failed.");
283 return false;
284 }
285 }
286 }
287 // add one more matrix (not required for energy)
288 MatrixContainer::MatrixArray matrix;
289 matrix.resize(1);
290 matrix[0].resize(1, 0.);
291 if (!Energy.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter))
292 return false;
293 // but for energy because we need to know total number of atoms
294 matrix.resize(NoAtoms);
295 for (size_t i = 0; i< NoAtoms; ++i)
296 matrix[i].resize(2+NDIM, 0.);
297 if (!Force.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter))
298 return false;
299
300 return true;
301}
302
303template <typename T>
304void convertMPQCDataTo(
305 const std::vector<MPQCData> &fragmentData,
306 std::vector<T> &MPQCData_fused)
307{
308 MPQCData_fused.clear();
309}
310
311template <>
312void convertMPQCDataTo<MPQCDataEnergyMap_t>(
313 const std::vector<MPQCData> &fragmentData,
314 std::vector<MPQCDataEnergyMap_t> &MPQCData_Energy_fused)
315{
316 // energy_t
317 MPQCData_Energy_fused.clear();
318 MPQCData_Energy_fused.reserve(fragmentData.size());
319 for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
320 dataiter != fragmentData.end(); ++dataiter) {
321 const MPQCData &extractedData = *dataiter;
322 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
323 MPQCDataEnergyMap_t instance;
324 boost::fusion::at_key<MPQCDataFused::energy_total>(instance) = extractedData.energies.total;
325 boost::fusion::at_key<MPQCDataFused::energy_nuclear_repulsion>(instance) = extractedData.energies.nuclear_repulsion;
326 boost::fusion::at_key<MPQCDataFused::energy_electron_coulomb>(instance) = extractedData.energies.electron_coulomb;
327 boost::fusion::at_key<MPQCDataFused::energy_electron_exchange>(instance) = extractedData.energies.electron_exchange;
328 boost::fusion::at_key<MPQCDataFused::energy_correlation>(instance) = extractedData.energies.correlation;
329 boost::fusion::at_key<MPQCDataFused::energy_overlap>(instance) = extractedData.energies.overlap;
330 boost::fusion::at_key<MPQCDataFused::energy_kinetic>(instance) = extractedData.energies.kinetic;
331 boost::fusion::at_key<MPQCDataFused::energy_hcore>(instance) = extractedData.energies.hcore;
332 boost::fusion::at_key<MPQCDataFused::energy_eigenvalues>(instance) = extractedData.energies.eigenvalues;
333 MPQCData_Energy_fused.push_back(instance);
334 }
335}
336
337
338void convertMPQCDatatoForceMap(
339 const std::vector<MPQCData> &fragmentData,
340 const KeySetsContainer &ForceKeySet,
341 std::vector<MPQCDataForceMap_t> &MPQCData_Force_fused)
342{
343 // forces
344 ASSERT( ForceKeySet.KeySets.size() == fragmentData.size(),
345 "FragmentationAutomationAction::performCall() - indices and fragmentData differ in size.");
346 MPQCData_Force_fused.clear();
347 MPQCData_Force_fused.reserve(fragmentData.size());
348 std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
349 KeySetsContainer::ArrayOfIntVectors::const_iterator arrayiter = ForceKeySet.KeySets.begin();
350 for(;dataiter != fragmentData.end(); ++dataiter, ++arrayiter) {
351 const MPQCData &extractedData = *dataiter;
352 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
353 MPQCDataForceMap_t instance;
354 // must convert int to index_t
355 IndexedVectors::indices_t indices(arrayiter->begin(), arrayiter->end());
356 boost::fusion::at_key<MPQCDataFused::forces>(instance) =
357 IndexedVectors(indices, extractedData.forces);
358 MPQCData_Force_fused.push_back(instance);
359 }
360}
361
362template <>
363void convertMPQCDataTo<MPQCDataGridMap_t>(
364 const std::vector<MPQCData> &fragmentData,
365 std::vector<MPQCDataGridMap_t> &MPQCData_Grid_fused)
366{
367 // sampled_grid
368 MPQCData_Grid_fused.clear();
369 MPQCData_Grid_fused.reserve(fragmentData.size());
370 for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
371 dataiter != fragmentData.end(); ++dataiter) {
372 const MPQCData &extractedData = *dataiter;
373 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
374 MPQCDataGridMap_t instance;
375 boost::fusion::at_key<MPQCDataFused::sampled_grid>(instance) = extractedData.sampled_grid;
376 MPQCData_Grid_fused.push_back(instance);
377 }
378}
379
380template <>
381void convertMPQCDataTo<MPQCDataFragmentMap_t>(
382 const std::vector<MPQCData> &fragmentData,
383 std::vector<MPQCDataFragmentMap_t> &MPQCData_Fragment_fused)
384{
385 // fragment
386 MPQCData_Fragment_fused.clear();
387 MPQCData_Fragment_fused.reserve(fragmentData.size());
388 for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
389 dataiter != fragmentData.end(); ++dataiter) {
390 const MPQCData &extractedData = *dataiter;
391 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
392 MPQCDataFragmentMap_t instance;
393 boost::fusion::at_key<MPQCDataFused::fragment>(instance) =
394 Fragment(extractedData.positions, extractedData.charges);
395 MPQCData_Fragment_fused.push_back(instance);
396 }
397}
398
399template <>
400void convertMPQCDataTo<MPQCDataTimeMap_t>(
401 const std::vector<MPQCData> &fragmentData,
402 std::vector<MPQCDataTimeMap_t> &MPQCData_Time_fused)
403{
404 // times
405 MPQCData_Time_fused.clear();
406 MPQCData_Time_fused.reserve(fragmentData.size());
407 for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
408 dataiter != fragmentData.end(); ++dataiter) {
409 const MPQCData &extractedData = *dataiter;
410 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
411 MPQCDataTimeMap_t instance;
412 boost::fusion::at_key<MPQCDataFused::times_walltime>(instance) = extractedData.times.walltime;
413 boost::fusion::at_key<MPQCDataFused::times_cputime>(instance) = extractedData.times.cputime;
414 boost::fusion::at_key<MPQCDataFused::times_flops>(instance) = extractedData.times.flops;
415 MPQCData_Time_fused.push_back(instance);
416 }
417}
418
419template <typename TypeMap, typename TypeVector>
420std::vector<TypeMap> SumUpPerLevel(
421 const std::vector<MPQCData> &fragmentData,
422 const std::vector<JobId_t> &jobids,
423 std::map< JobId_t, size_t > &MatrixNrLookup,
424 const IndexSetContainer::ptr &container,
425 SubsetMap::ptr &subsetmap
426 )
427{
428 // place data into boost::fusion::map instance
429 std::vector<TypeMap> MPQCData_fused;
430 convertMPQCDataTo<TypeMap>(fragmentData, MPQCData_fused);
431 // instantiate summator
432 std::vector<TypeMap> Result_fused(subsetmap->getMaximumSubsetLevel());
433 AllLevelOrthogonalSummator<TypeMap> Summer(
434 subsetmap,
435 MPQCData_fused,
436 jobids,
437 container->getContainer(),
438 MatrixNrLookup,
439 Result_fused);
440 // sum up for each type key in TypeVector
441 boost::mpl::for_each<TypeVector>(boost::ref(Summer));
442 return Result_fused;
443}
444
445/** Print MPQCData from received results.
446 *
447 * @param results results with ids to associate with fragment number
448 * @param fragmentData MPQCData resulting from the jobs
449 * @param KeySetFilename filename with keysets to associate forces correctly
450 * @param NoAtoms total number of atoms
451 * @param full_sample summed up charge density of electrons from fragments on return
452 * @param full_fragment summed up positions and charges of nuclei from fragments on return
453 */
454bool sumUpChargeDensity(
455 const std::vector<FragmentResult::ptr> &results,
456 const std::vector<MPQCData> &fragmentData,
457 const std::string &KeySetFilename,
458 SamplingGrid &full_sample,
459 Fragment &full_fragment)
460{
461 // create lookup from job nr to fragment number
462 std::map< JobId_t, size_t > MatrixNrLookup;
463 size_t FragmentCounter = 0;
464 createMatrixNrLookup(results, MatrixNrLookup, FragmentCounter);
465
466 // initialise keysets
467 KeySetsContainer KeySet;
468 {
469 // else needs keysets without hydrogens
470 std::stringstream filename;
471 filename << FRAGMENTPREFIX << KEYSETFILE;
472 if (!KeySet.ParseKeySets(KeySetFilename, filename.str(), FragmentCounter)) return false;
473 }
474
475 /// prepare for OrthogonalSummation
476
477 // convert KeySetContainer to IndexSetContainer
478 IndexSetContainer::ptr container(new IndexSetContainer(KeySet));
479 // create the map of all keysets
480 SubsetMap::ptr subsetmap(new SubsetMap(*container));
481
482 // create a vector of all job ids
483 std::vector<JobId_t> jobids(results.size(), JobId::IllegalJob);
484 std::transform(results.begin(), results.end(), jobids.begin(),
485 boost::bind(&FragmentResult::getId,
486 boost::bind(&FragmentResult::ptr::operator->, _1)));
487
488 /// convert all MPQCData to MPQCDataMap_t
489 std::vector<MPQCDataGridMap_t> Result_Grid_fused(
490 SumUpPerLevel<MPQCDataGridMap_t, MPQCDataGridVector_t>(
491 fragmentData, jobids, MatrixNrLookup, container, subsetmap));
492 std::vector<MPQCDataFragmentMap_t> Result_Fragment_fused(
493 SumUpPerLevel<MPQCDataFragmentMap_t, MPQCDataFragmentVector_t>(
494 fragmentData, jobids, MatrixNrLookup, container, subsetmap));
495 // obtain full grid
496 full_sample = boost::fusion::at_key<MPQCDataFused::sampled_grid>(Result_Grid_fused.back());
497 full_fragment = boost::fusion::at_key<MPQCDataFused::fragment>(Result_Fragment_fused.back());
498
499 return true;
500}
501
502
503/** Print MPQCData from received results.
504 *
505 * @param results results with ids to associate with fragment number
506 * @param fragmentData MPQCData resulting from the jobs
507 * @param KeySetFilename filename with keysets to associate forces correctly
508 * @param NoAtoms total number of atoms
509 * @param full_sample summed up charge from fragments on return
510 */
511bool printReceivedMPQCResults(
512 const std::vector<FragmentResult::ptr> &results,
513 const std::vector<MPQCData> &fragmentData,
514 const std::string &KeySetFilename,
515 size_t NoAtoms,
516 SamplingGrid &full_sample)
517{
518 // create lookup from job nr to fragment number
519 std::map< JobId_t, size_t > MatrixNrLookup;
520 size_t FragmentCounter = 0;
521 createMatrixNrLookup(results, MatrixNrLookup, FragmentCounter);
522
523 // place results into maps
524 EnergyMatrix Energy;
525 ForceMatrix Force;
526 if (!putResultsintoMatrices(results, fragmentData, MatrixNrLookup, FragmentCounter, NoAtoms, Energy, Force))
527 return false;
528
529 // initialise keysets
530 KeySetsContainer KeySet;
531 KeySetsContainer ForceKeySet;
532 if (!Energy.InitialiseIndices()) return false;
533
534 if (!Force.ParseIndices(KeySetFilename.c_str())) return false;
535
536 {
537 // else needs keysets without hydrogens
538 std::stringstream filename;
539 filename << FRAGMENTPREFIX << KEYSETFILE;
540 if (!KeySet.ParseKeySets(KeySetFilename, filename.str(), FragmentCounter)) return false;
541 }
542
543 {
544 // forces need keysets including hydrogens
545 std::stringstream filename;
546 filename << FRAGMENTPREFIX << FORCESFILE;
547 if (!ForceKeySet.ParseKeySets(KeySetFilename, filename.str(), FragmentCounter)) return false;
548 }
549
550 /// prepare for OrthogonalSummation
551
552 // convert KeySetContainer to IndexSetContainer
553 IndexSetContainer::ptr container(new IndexSetContainer(KeySet));
554 // create the map of all keysets
555 SubsetMap::ptr subsetmap(new SubsetMap(*container));
556
557 // create a vector of all job ids
558 std::vector<JobId_t> jobids(results.size(), JobId::IllegalJob);
559 std::transform(results.begin(), results.end(), jobids.begin(),
560 boost::bind(&FragmentResult::getId,
561 boost::bind(&FragmentResult::ptr::operator->, _1)));
562
563 /// convert all MPQCData to MPQCDataMap_t
564 {
565 ASSERT( ForceKeySet.KeySets.size() == fragmentData.size(),
566 "FragmentationAutomationAction::performCall() - ForceKeySet's KeySets and fragmentData differ in size.");
567
568 std::vector<MPQCDataEnergyMap_t> Result_Energy_fused(
569 SumUpPerLevel<MPQCDataEnergyMap_t, MPQCDataEnergyVector_t>(
570 fragmentData, jobids, MatrixNrLookup, container, subsetmap));
571 std::vector<MPQCDataGridMap_t> Result_Grid_fused(
572 SumUpPerLevel<MPQCDataGridMap_t, MPQCDataGridVector_t>(
573 fragmentData, jobids, MatrixNrLookup, container, subsetmap));
574 std::vector<MPQCDataTimeMap_t> Result_Time_fused(
575 SumUpPerLevel<MPQCDataTimeMap_t, MPQCDataTimeVector_t>(
576 fragmentData, jobids, MatrixNrLookup, container, subsetmap));
577
578 // force has extra converter
579 std::vector<MPQCDataForceMap_t> MPQCData_Force_fused;
580 convertMPQCDatatoForceMap(fragmentData, ForceKeySet, MPQCData_Force_fused);
581 std::vector<MPQCDataForceMap_t> Result_Force_fused(subsetmap->getMaximumSubsetLevel());
582 AllLevelOrthogonalSummator<MPQCDataForceMap_t> forceSummer(
583 subsetmap,
584 MPQCData_Force_fused,
585 jobids,
586 container->getContainer(),
587 MatrixNrLookup,
588 Result_Force_fused);
589 boost::mpl::for_each<MPQCDataForceVector_t>(boost::ref(forceSummer));
590
591 // obtain full grid
592 full_sample = boost::fusion::at_key<MPQCDataFused::sampled_grid>(Result_Grid_fused.back());
593
594 // print tables (without eigenvalues, they go extra)
595 const size_t MaxLevel = subsetmap->getMaximumSubsetLevel();
596 typedef boost::mpl::remove<MPQCDataEnergyVector_t, MPQCDataFused::energy_eigenvalues>::type MPQCDataEnergyVector_noeigenvalues_t;
597 const std::string energyresult =
598 writeTable<MPQCDataEnergyMap_t, MPQCDataEnergyVector_noeigenvalues_t >()(
599 Result_Energy_fused, MaxLevel);
600 LOG(0, "Energy table is \n" << energyresult);
601 const std::string eigenvalueresult;
602
603 LOG(0, "Eigenvalue table is \n" << eigenvalueresult);
604 const std::string forceresult =
605 writeTable<MPQCDataForceMap_t, MPQCDataForceVector_t>()(
606 Result_Force_fused, MaxLevel);
607 LOG(0, "Force table is \n" << forceresult);
608 // we don't want to print grid to a table
609 // print times (without flops for now)
610 typedef boost::mpl::remove<MPQCDataTimeVector_t, MPQCDataFused::times_flops>::type MPQCDataTimeVector_noflops_t;
611 const std::string timesresult =
612 writeTable<MPQCDataTimeMap_t, MPQCDataTimeVector_noflops_t >()(
613 Result_Time_fused, MaxLevel);
614 LOG(0, "Times table is \n" << timesresult);
615 }
616
617 // combine all found data
618 if (!KeySet.ParseManyBodyTerms()) return false;
619
620 EnergyMatrix EnergyFragments;
621 ForceMatrix ForceFragments;
622 if (!EnergyFragments.AllocateMatrix(Energy.Header, Energy.MatrixCounter, Energy.RowCounter, Energy.ColumnCounter)) return false;
623 if (!ForceFragments.AllocateMatrix(Force.Header, Force.MatrixCounter, Force.RowCounter, Force.ColumnCounter)) return false;
624
625 if(!Energy.SetLastMatrix(0., 0)) return false;
626 if(!Force.SetLastMatrix(0., 2)) return false;
627
628 for (int BondOrder=0;BondOrder<KeySet.Order;BondOrder++) {
629 // --------- sum up energy --------------------
630 LOG(1, "INFO: Summing energy of order " << BondOrder+1 << " ...");
631 if (!EnergyFragments.SumSubManyBodyTerms(Energy, KeySet, BondOrder)) return false;
632 if (!Energy.SumSubEnergy(EnergyFragments, NULL, KeySet, BondOrder, 1.)) return false;
633
634 // --------- sum up Forces --------------------
635 LOG(1, "INFO: Summing forces of order " << BondOrder+1 << " ...");
636 if (!ForceFragments.SumSubManyBodyTerms(Force, KeySet, BondOrder)) return false;
637 if (!Force.SumSubForces(ForceFragments, KeySet, BondOrder, 1.)) return false;
638 }
639
640 // for debugging print resulting energy and forces
641 LOG(1, "INFO: Resulting energy is " << Energy.Matrix[ FragmentCounter ][0][0]);
642 std::stringstream output;
643 for (int i=0; i< Force.RowCounter[FragmentCounter]; ++i) {
644 for (int j=0; j< Force.ColumnCounter[FragmentCounter]; ++j)
645 output << Force.Matrix[ FragmentCounter ][i][j] << " ";
646 output << "\n";
647 }
648 LOG(1, "INFO: Resulting forces are " << std::endl << output.str());
649
650 return true;
651}
652
653
654void RunService(
655 boost::asio::io_service &io_service,
656 std::string message)
657{
658 message = std::string("io_service: ") + message;
659 io_service.reset();
660 Info info(message.c_str());
661 io_service.run();
662}
663
664void requestIds(
665 FragmentController &controller,
666 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
667 const size_t numberjobs)
668{
669 controller.requestIds(params.host.get(), params.port.get(), numberjobs);
670}
671
672bool createJobsFromFiles(
673 FragmentController &controller,
674 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
675 const std::vector< boost::filesystem::path > &jobfiles)
676{
677 std::vector<FragmentJob::ptr> jobs;
678 for (std::vector< boost::filesystem::path >::const_iterator iter = jobfiles.begin();
679 iter != jobfiles .end(); ++iter) {
680 const std::string &filename = (*iter).string();
681 if (boost::filesystem::exists(filename)) {
682 const JobId_t next_id = controller.getAvailableId();
683 LOG(1, "INFO: Creating MPQCCommandJob with filename'"
684 +filename+"', and id "+toString(next_id)+".");
685 parsejob(jobs, params.executable.get().string(), filename, next_id);
686 } else {
687 ELOG(1, "Fragment job "+filename+" does not exist.");
688 return false;
689 }
690 }
691 controller.addJobs(jobs);
692 controller.sendJobs(params.host.get(), params.port.get());
693 return true;
694}
695
696#ifdef HAVE_VMG
697bool createLongRangeJobs(
698 FragmentController &controller,
699 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
700 const std::vector<MPQCData> &fragmentData,
701 const SamplingGrid &full_sampled_grid,
702 const Fragment &full_fragment)
703{
704 std::vector<FragmentJob::ptr> jobs;
705 // add one job for each fragment as the short-range correction which we need
706 // to subtract from the obtained full potential to get the long-range part only
707 for (std::vector<MPQCData>::const_iterator iter = fragmentData.begin();
708 iter != fragmentData.end(); ++iter) {
709 const JobId_t next_id = controller.getAvailableId();
710 LOG(1, "INFO: Creating VMGJob with " << iter->sampled_grid.sampled_grid.size()
711 << " gridpoints and " << iter->charges.size() << " particle charges.");
712 FragmentJob::ptr testJob(
713 new VMGJob(next_id, iter->sampled_grid, iter->positions, iter->charges) );
714 jobs.push_back(testJob);
715 }
716
717 {
718// const int level = LEVEL;
719// const int GRID = pow(2, level);
720// double begin[NDIM] = { 0., 0., 0. };
721// const RealSpaceMatrix& M = World::getInstance().getDomain().getM();
722// const double size = M.at(0,0);
723// ASSERT( M.determinant() == size*size*size,
724// "createLongRangeJobs() - current domain matrix "+toString(M)+" is not cubic.");
725 const std::vector< std::vector<double> > positions(full_fragment.getPositions());
726 const std::vector<double> charges(full_fragment.getCharges());
727 const JobId_t next_id = controller.getAvailableId();
728 LOG(1, "INFO: Creating full VMGJob with " << full_sampled_grid.sampled_grid.size()
729 << " gridpoints and " << charges.size() << " particle charges.");
730 FragmentJob::ptr testJob(
731 new VMGJob(next_id, full_sampled_grid, positions, charges) );
732 jobs.push_back(testJob);
733 }
734
735 // then send jobs to controller
736 controller.addJobs(jobs);
737 controller.sendJobs(params.host.get(), params.port.get());
738 return true;
739}
740#endif
741
742void WaitforResults(
743 boost::asio::io_service &io_service,
744 FragmentController &controller,
745 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
746 const size_t NoExpectedResults
747 )
748{
749 size_t NoCalculatedResults = 0;
750 while (NoCalculatedResults != NoExpectedResults) {
751 // wait a bit
752 boost::asio::deadline_timer timer(io_service);
753 timer.expires_from_now(boost::posix_time::milliseconds(500));
754 timer.wait();
755 // then request status
756 controller.checkResults(params.host.get(), params.port.get());
757 RunService(io_service, "Checking on results");
758
759 const std::pair<size_t, size_t> JobStatus = controller.getJobStatus();
760 LOG(1, "INFO: #" << JobStatus.first << " are waiting in the queue and #" << JobStatus.second << " jobs are calculated so far.");
761 NoCalculatedResults = JobStatus.second;
762 }
763}
764
765
766Action::state_ptr FragmentationFragmentationAutomationAction::performCall() {
767 boost::asio::io_service io_service;
768 FragmentController controller(io_service);
769
770 // TODO: Have io_service run in second thread and merge with current again eventually
771
772 // Phase One: obtain ids
773 std::vector< boost::filesystem::path > jobfiles = params.jobfiles.get();
774 requestIds(controller, params, jobfiles.size());
775 RunService(io_service, "Requesting ids");
776
777 // Phase Two: create and add MPQCJobs
778 if (!createJobsFromFiles(controller, params, jobfiles))
779 return Action::failure;
780 RunService(io_service, "Adding MPQCJobs");
781
782 // Phase Three: calculate result
783 WaitforResults(io_service, controller, params, jobfiles.size());
784 controller.receiveResults(params.host.get(), params.port.get());
785 RunService(io_service, "Requesting short-range results");
786 std::vector<FragmentResult::ptr> MPQCresults = controller.getReceivedResults();
787 std::vector<MPQCData> fragmentData;
788 ConvertFragmentResultToMPQCData(MPQCresults, fragmentData);
789
790#ifdef HAVE_VMG
791 if (params.DoLongrange.get()) {
792 // obtain combined charge density
793 LOG(1, "INFO: Parsing fragment files from " << params.path.get() << ".");
794 SamplingGrid full_sample;
795 Fragment full_fragment;
796 sumUpChargeDensity(
797 MPQCresults,
798 fragmentData,
799 params.path.get(),
800 full_sample,
801 full_fragment);
802
803 // Phase Four: obtain more ids
804 requestIds(controller, params, fragmentData.size()+1);
805 RunService(io_service, "Requesting ids");
806
807 // Phase Five: create VMGJobs
808 if (!createLongRangeJobs(controller, params, fragmentData, full_sample, full_fragment))
809 return Action::failure;
810 RunService(io_service, "Adding VMGJobs");
811
812 // Phase Six: calculate result
813 WaitforResults(io_service, controller, params, fragmentData.size()+1);
814 controller.receiveResults(params.host.get(), params.port.get());
815 RunService(io_service, "Requesting long-range results");
816 std::vector<FragmentResult::ptr> VMGresults = controller.getReceivedResults();
817 ASSERT( MPQCresults.size()+1 == VMGresults.size(),
818 "FragmentationFragmentationAutomationAction::performCall() - number of MPQCresultd and VMGresults don't match.");
819
820 // Final phase: print result
821 {
822 LOG(1, "INFO: Parsing fragment files from " << params.path.get() << ".");
823 printReceivedMPQCResults(
824 MPQCresults,
825 fragmentData,
826 params.path.get(),
827 getNoAtomsFromAdjacencyFile(params.path.get()),
828 full_sample);
829 }
830 }
831#endif
832 size_t Exitflag = controller.getExitflag();
833
834 return (Exitflag == 0) ? Action::success : Action::failure;
835}
836
837Action::state_ptr FragmentationFragmentationAutomationAction::performUndo(Action::state_ptr _state) {
838 return Action::success;
839}
840
841Action::state_ptr FragmentationFragmentationAutomationAction::performRedo(Action::state_ptr _state){
842 return Action::success;
843}
844
845bool FragmentationFragmentationAutomationAction::canUndo() {
846 return false;
847}
848
849bool FragmentationFragmentationAutomationAction::shouldUndo() {
850 return false;
851}
852/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.