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

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

Positions and charges of nuclei are also contained in MPQCData and used by VMGJob and InterfaceVMGJob, respectively.

  • this is a temporary solution until we finally create the fragments and send prepare the MPQCJobs in one go. I.e. for now mpqc has to fill in the vacant MPQCData entries of positions and charges to be used by the VMGJob created from this information.
  • Using CommSerial/MPI in ImportRightHandSide() to getParticleGrid().
  • Property mode set to 100644
File size: 24.2 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/assign.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/Histogram.hpp"
55#include "Fragmentation/SetValues/IndexedVectors.hpp"
56#include "Fragmentation/HydrogenSaturation_enum.hpp"
57#include "Fragmentation/KeySet.hpp"
58#include "Fragmentation/KeySetsContainer.hpp"
59#include "Fragmentation/Summation/printOrthogonalSum.hpp"
60#include "Fragmentation/Summation/printSum.hpp"
61#include "Graph/DepthFirstSearchAnalysis.hpp"
62#include "Jobs/MPQCJob.hpp"
63#include "Jobs/MPQCData.hpp"
64#include "Jobs/MPQCData_printKeyNames.hpp"
65#include "LinearAlgebra/RealSpaceMatrix.hpp"
66#ifdef HAVE_VMG
67#include "Jobs/VMGJob.hpp"
68#endif
69#include "molecule.hpp"
70#include "World.hpp"
71
72#include <iostream>
73#include <string>
74#include <vector>
75
76#include <boost/mpl/for_each.hpp>
77
78#include "Actions/FragmentationAction/FragmentationAutomationAction.hpp"
79
80using namespace MoleCuilder;
81
82using namespace boost::assign;
83
84// and construct the stuff
85#include "FragmentationAutomationAction.def"
86#include "Action_impl_pre.hpp"
87/** =========== define the function ====================== */
88
89class controller_AddOn;
90
91// needs to be defined for using the FragmentController
92controller_AddOn *getAddOn()
93{
94 return NULL;
95}
96
97const int LEVEL = 5;
98
99/** Creates a MPQCCommandJob with argument \a filename.
100 *
101 * @param jobs created job is added to this vector
102 * @param command mpqc command to execute
103 * @param filename filename being argument to job
104 * @param nextid id for this job
105 */
106void parsejob(
107 std::vector<FragmentJob::ptr> &jobs,
108 const std::string &command,
109 const std::string &filename,
110 const JobId_t nextid)
111{
112 std::ifstream file;
113 file.open(filename.c_str());
114 ASSERT( file.good(), "parsejob() - file "+filename+" does not exist.");
115 std::string output((std::istreambuf_iterator<char>(file)),
116 std::istreambuf_iterator<char>());
117 double begin[NDIM] = { 0., 0., 0. };
118 const RealSpaceMatrix& M = World::getInstance().getDomain().getM();
119 const double size = M.at(0,0);
120 ASSERT( M.determinant() == size*size*size,
121 "parsejob() - current domain matrix "+toString(M)+" is not cubic.");
122 const int level = LEVEL;
123 FragmentJob::ptr testJob( new MPQCJob(nextid, output, begin, size, level) );
124 jobs.push_back(testJob);
125 file.close();
126 LOG(1, "INFO: Added MPQCCommandJob from file "+filename+".");
127}
128
129/** Helper function to get number of atoms somehow.
130 *
131 * Here, we just parse the number of lines in the adjacency file as
132 * it should correspond to the number of atoms, except when some atoms
133 * are not bonded, but then fragmentation makes no sense.
134 *
135 * @param path path to the adjacency file
136 */
137size_t getNoAtomsFromAdjacencyFile(const std::string &path)
138{
139 size_t NoAtoms = 0;
140
141 // parse in special file to get atom count (from line count)
142 std::string filename(path);
143 filename += FRAGMENTPREFIX;
144 filename += ADJACENCYFILE;
145 std::ifstream adjacency(filename.c_str());
146 if (adjacency.fail()) {
147 LOG(0, endl << "getNoAtomsFromAdjacencyFile() - Unable to open " << filename << ", is the directory correct?");
148 return false;
149 }
150 std::string buffer;
151 while (getline(adjacency, buffer))
152 NoAtoms++;
153 LOG(1, "INFO: There are " << NoAtoms << " atoms.");
154
155 return NoAtoms;
156}
157
158/** Extracts MPQCData from received vector of FragmentResults.
159 *
160 * @param results results to extract MPQCData from
161 * @param fragmentData on return array filled with extracted MPQCData
162 */
163void ConvertFragmentResultToMPQCData(
164 const std::vector<FragmentResult::ptr> &results,
165 std::vector<MPQCData> &fragmentData)
166{
167 // extract results
168 fragmentData.clear();
169 fragmentData.reserve(results.size());
170
171 LOG(2, "DEBUG: Parsing now through " << results.size() << " results.");
172 for (std::vector<FragmentResult::ptr>::const_iterator iter = results.begin();
173 iter != results.end(); ++iter) {
174 //LOG(1, "RESULT: job #"+toString((*iter)->getId())+": "+toString((*iter)->result));
175 MPQCData extractedData;
176 std::stringstream inputstream((*iter)->result);
177 LOG(2, "DEBUG: First 50 characters FragmentResult's string: "+(*iter)->result.substr(0, 50));
178 boost::archive::text_iarchive ia(inputstream);
179 ia >> extractedData;
180 LOG(1, "INFO: extracted data is " << extractedData << ".");
181 fragmentData.push_back(extractedData);
182 }
183
184 ASSERT( results.size() == fragmentData.size(),
185 "ConvertFragmentResultToMPQCData() - the number of extracted data differs from the number of results.");
186}
187
188/** Print MPQCData from received results.
189 *
190 * @param results results with ids to associate with fragment number
191 * @param fragmentData MPQCData resulting from the jobs
192 * @param KeySetFilename filename with keysets to associate forces correctly
193 * @param NoAtoms total number of atoms
194 */
195bool printReceivedMPQCResults(
196 const std::vector<FragmentResult::ptr> &results,
197 const std::vector<MPQCData> &fragmentData,
198 const std::string &KeySetFilename,
199 size_t NoAtoms)
200{
201 EnergyMatrix Energy;
202 EnergyMatrix EnergyFragments;
203 ForceMatrix Force;
204 ForceMatrix ForceFragments;
205
206 // align fragments
207 std::map< JobId_t, size_t > MatrixNrLookup;
208 size_t FragmentCounter = 0;
209 {
210 // bring ids in order ...
211 typedef std::map< JobId_t, FragmentResult::ptr> IdResultMap_t;
212 IdResultMap_t IdResultMap;
213 for (std::vector<FragmentResult::ptr>::const_iterator iter = results.begin();
214 iter != results.end(); ++iter) {
215 #ifndef NDEBUG
216 std::pair< IdResultMap_t::iterator, bool> inserter =
217 #endif
218 IdResultMap.insert( make_pair((*iter)->getId(), *iter) );
219 ASSERT( inserter.second,
220 "ExtractMPQCDataFromResults() - two results have same id "
221 +toString((*iter)->getId())+".");
222 }
223 // ... and fill lookup
224 for(IdResultMap_t::const_iterator iter = IdResultMap.begin();
225 iter != IdResultMap.end(); ++iter)
226 MatrixNrLookup.insert( make_pair(iter->first, FragmentCounter++) );
227 }
228 LOG(1, "INFO: There are " << FragmentCounter << " fragments.");
229
230 std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
231 std::vector<FragmentResult::ptr>::const_iterator resultiter = results.begin();
232 for (; dataiter != fragmentData.end(); ++dataiter, ++resultiter) {
233 const MPQCData &extractedData = *dataiter;
234 // place results into EnergyMatrix ...
235 {
236 MatrixContainer::MatrixArray matrix;
237 matrix.resize(1);
238 matrix[0].resize(1, extractedData.energies.total);
239 if (!Energy.AddMatrix(
240 std::string("MPQCJob ")+toString((*resultiter)->getId()),
241 matrix,
242 MatrixNrLookup[(*resultiter)->getId()])) {
243 ELOG(1, "Adding energy matrix failed.");
244 return false;
245 }
246 }
247 // ... and ForceMatrix (with two empty columns in front)
248 {
249 MatrixContainer::MatrixArray matrix;
250 const size_t rows = extractedData.forces.size();
251 matrix.resize(rows);
252 for (size_t i=0;i<rows;++i) {
253 const size_t columns = 2+extractedData.forces[i].size();
254 matrix[i].resize(columns, 0.);
255 // for (size_t j=0;j<2;++j)
256 // matrix[i][j] = 0.;
257 for (size_t j=2;j<columns;++j)
258 matrix[i][j] = extractedData.forces[i][j-2];
259 }
260 if (!Force.AddMatrix(
261 std::string("MPQCJob ")+toString((*resultiter)->getId()),
262 matrix,
263 MatrixNrLookup[(*resultiter)->getId()])) {
264 ELOG(1, "Adding force matrix failed.");
265 return false;
266 }
267 }
268 }
269 // add one more matrix (not required for energy)
270 MatrixContainer::MatrixArray matrix;
271 matrix.resize(1);
272 matrix[0].resize(1, 0.);
273 if (!Energy.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter))
274 return false;
275 // but for energy because we need to know total number of atoms
276 matrix.resize(NoAtoms);
277 for (size_t i = 0; i< NoAtoms; ++i)
278 matrix[i].resize(2+NDIM, 0.);
279 if (!Force.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter))
280 return false;
281
282 // initialise indices
283 KeySetsContainer KeySet;
284 if (!Energy.InitialiseIndices()) return false;
285
286 if (!Force.ParseIndices(KeySetFilename.c_str())) return false;
287
288 if (!KeySet.ParseKeySets(KeySetFilename.c_str(), Force.RowCounter, Force.MatrixCounter)) return false;
289
290 /// prepare for OrthogonalSummation
291
292 // gather all present indices in AllIndices
293 IndexSet::ptr AllIndices(new IndexSet);
294 for (KeySetsContainer::ArrayOfIntVectors::const_iterator iter = KeySet.KeySets.begin();
295 iter != KeySet.KeySets.end(); ++iter)
296 for(KeySetsContainer::IntVector::const_iterator keyiter = (*iter).begin();
297 keyiter != (*iter).end(); ++keyiter) {
298 if (*keyiter != -1)
299 (*AllIndices) += *keyiter;
300 }
301 LOG(1, "INFO: AllIndices is " << AllIndices << ".");
302 // create container with all keysets
303 IndexSetContainer::ptr container(new IndexSetContainer(AllIndices));
304 for (KeySetsContainer::ArrayOfIntVectors::const_iterator iter = KeySet.KeySets.begin();
305 iter != KeySet.KeySets.end(); ++iter) {
306 IndexSet tempset;
307 for(KeySetsContainer::IntVector::const_iterator keyiter = (*iter).begin();
308 keyiter != (*iter).end(); ++keyiter)
309 if (*keyiter != -1)
310 tempset += *keyiter;
311 container->insert(tempset);
312 }
313 // create the map of all keysets
314 SubsetMap::ptr subsetmap(new SubsetMap(*container));
315
316 /// convert all MPQCData to MPQCDataMap_t
317 {
318 // energy_t
319 std::vector<MPQCDataEnergyMap_t> MPQCData_Energy_fused;
320 MPQCData_Energy_fused.reserve(fragmentData.size());
321 for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
322 dataiter != fragmentData.end(); ++dataiter) {
323 const MPQCData &extractedData = *dataiter;
324 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
325 MPQCDataEnergyMap_t instance;
326 boost::fusion::at_key<MPQCDataFused::energy_total>(instance) = extractedData.energies.total;
327 boost::fusion::at_key<MPQCDataFused::energy_nuclear_repulsion>(instance) = extractedData.energies.nuclear_repulsion;
328 boost::fusion::at_key<MPQCDataFused::energy_electron_coulomb>(instance) = extractedData.energies.electron_coulomb;
329 boost::fusion::at_key<MPQCDataFused::energy_electron_exchange>(instance) = extractedData.energies.electron_exchange;
330 boost::fusion::at_key<MPQCDataFused::energy_correlation>(instance) = extractedData.energies.correlation;
331 boost::fusion::at_key<MPQCDataFused::energy_overlap>(instance) = extractedData.energies.overlap;
332 boost::fusion::at_key<MPQCDataFused::energy_kinetic>(instance) = extractedData.energies.kinetic;
333 boost::fusion::at_key<MPQCDataFused::energy_hcore>(instance) = extractedData.energies.hcore;
334 boost::fusion::at_key<MPQCDataFused::energy_eigenvalues>(instance) = extractedData.energies.eigenvalues;
335 MPQCData_Energy_fused.push_back(instance);
336 }
337
338 // forces
339 const IndexSetContainer::Container_t &indices = container->getContainer();
340 ASSERT( indices.size() == fragmentData.size(),
341 "FragmentationAutomationAction::performCall() - indices and fragmentData differ in size.");
342 std::vector<MPQCDataForceMap_t> MPQCData_Force_fused;
343 MPQCData_Force_fused.reserve(fragmentData.size());
344 std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
345 IndexSetContainer::Container_t::const_iterator indexiter = indices.begin();
346 for(;dataiter != fragmentData.end(); ++dataiter, ++indexiter) {
347 const MPQCData &extractedData = *dataiter;
348 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
349 MPQCDataForceMap_t instance;
350 boost::fusion::at_key<MPQCDataFused::forces>(instance) =
351 IndexedVectors(**indexiter, extractedData.forces);
352 MPQCData_Force_fused.push_back(instance);
353 }
354
355 // sampled_grid
356 std::vector<MPQCDataGridMap_t> MPQCData_Grid_fused;
357 MPQCData_Grid_fused.reserve(fragmentData.size());
358 for(std::vector<MPQCData>::const_iterator dataiter = fragmentData.begin();
359 dataiter != fragmentData.end(); ++dataiter) {
360 const MPQCData &extractedData = *dataiter;
361 LOG(2, "DEBUG: Current extracted Data is " << extractedData << ".");
362 MPQCDataGridMap_t instance;
363 boost::fusion::at_key<MPQCDataFused::sampled_grid>(instance) = extractedData.sampled_grid;
364 MPQCData_Grid_fused.push_back(instance);
365 }
366
367 // times
368 std::vector<MPQCDataTimeMap_t> MPQCData_Time_fused;
369 MPQCData_Time_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 MPQCDataTimeMap_t instance;
375 boost::fusion::at_key<MPQCDataFused::times_walltime>(instance) = extractedData.times.walltime;
376 boost::fusion::at_key<MPQCDataFused::times_cputime>(instance) = extractedData.times.cputime;
377 boost::fusion::at_key<MPQCDataFused::times_flops>(instance) = extractedData.times.flops;
378 MPQCData_Time_fused.push_back(instance);
379 }
380
381 // create a vector of all job ids
382 std::vector<JobId_t> jobids(results.size(), JobId::IllegalJob);
383 std::transform(results.begin(), results.end(), jobids.begin(),
384 boost::bind(&FragmentResult::getId,
385 boost::bind(&FragmentResult::ptr::operator->, _1)));
386
387 // sum up and print energies
388 boost::mpl::for_each<MPQCDataEnergyVector_t>(
389 printOrthogonalSum<MPQCDataEnergyMap_t>(
390 subsetmap,
391 MPQCData_Energy_fused,
392 jobids,
393 container->getContainer(),
394 MatrixNrLookup)
395 );
396
397 // sum up and print forces
398 boost::mpl::for_each<MPQCDataForceVector_t>(
399 printOrthogonalSum<MPQCDataForceMap_t>(
400 subsetmap,
401 MPQCData_Force_fused,
402 jobids,
403 container->getContainer(),
404 MatrixNrLookup)
405 );
406
407 // sum up and print grids
408 boost::mpl::for_each<MPQCDataGridVector_t>(
409 printOrthogonalSum<MPQCDataGridMap_t>(
410 subsetmap,
411 MPQCData_Grid_fused,
412 jobids,
413 container->getContainer(),
414 MatrixNrLookup)
415 );
416
417 // sum up and print times
418 boost::mpl::for_each<MPQCDataTimeVector_t>(
419 printSum<MPQCDataTimeMap_t>(
420 subsetmap,
421 MPQCData_Time_fused,
422 jobids,
423 container->getContainer(),
424 MatrixNrLookup)
425 );
426 }
427
428 // combine all found data
429 if (!KeySet.ParseManyBodyTerms()) return false;
430
431 if (!EnergyFragments.AllocateMatrix(Energy.Header, Energy.MatrixCounter, Energy.RowCounter, Energy.ColumnCounter)) return false;
432 if (!ForceFragments.AllocateMatrix(Force.Header, Force.MatrixCounter, Force.RowCounter, Force.ColumnCounter)) return false;
433
434 if(!Energy.SetLastMatrix(0., 0)) return false;
435 if(!Force.SetLastMatrix(0., 2)) return false;
436
437 for (int BondOrder=0;BondOrder<KeySet.Order;BondOrder++) {
438 // --------- sum up energy --------------------
439 LOG(1, "INFO: Summing energy of order " << BondOrder+1 << " ...");
440 if (!EnergyFragments.SumSubManyBodyTerms(Energy, KeySet, BondOrder)) return false;
441 if (!Energy.SumSubEnergy(EnergyFragments, NULL, KeySet, BondOrder, 1.)) return false;
442
443 // --------- sum up Forces --------------------
444 LOG(1, "INFO: Summing forces of order " << BondOrder+1 << " ...");
445 if (!ForceFragments.SumSubManyBodyTerms(Force, KeySet, BondOrder)) return false;
446 if (!Force.SumSubForces(ForceFragments, KeySet, BondOrder, 1.)) return false;
447 }
448
449 // for debugging print resulting energy and forces
450 LOG(1, "INFO: Resulting energy is " << Energy.Matrix[ FragmentCounter ][0][0]);
451 std::stringstream output;
452 for (int i=0; i< Force.RowCounter[FragmentCounter]; ++i) {
453 for (int j=0; j< Force.ColumnCounter[FragmentCounter]; ++j)
454 output << Force.Matrix[ FragmentCounter ][i][j] << " ";
455 output << "\n";
456 }
457 LOG(1, "INFO: Resulting forces are " << std::endl << output.str());
458
459 return true;
460}
461
462
463void RunService(
464 boost::asio::io_service &io_service,
465 std::string message)
466{
467 message = std::string("io_service: ") + message;
468 io_service.reset();
469 Info info(message.c_str());
470 io_service.run();
471}
472
473void requestIds(
474 FragmentController &controller,
475 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
476 const size_t numberjobs)
477{
478 controller.requestIds(params.host.get(), params.port.get(), numberjobs);
479}
480
481bool createJobsFromFiles(
482 FragmentController &controller,
483 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
484 const std::vector< boost::filesystem::path > &jobfiles)
485{
486 std::vector<FragmentJob::ptr> jobs;
487 for (std::vector< boost::filesystem::path >::const_iterator iter = jobfiles.begin();
488 iter != jobfiles .end(); ++iter) {
489 const std::string &filename = (*iter).string();
490 if (boost::filesystem::exists(filename)) {
491 const JobId_t next_id = controller.getAvailableId();
492 LOG(1, "INFO: Creating MPQCCommandJob with filename'"
493 +filename+"', and id "+toString(next_id)+".");
494 parsejob(jobs, params.executable.get().string(), filename, next_id);
495 } else {
496 ELOG(1, "Fragment job "+filename+" does not exist.");
497 return false;
498 }
499 }
500 controller.addJobs(jobs);
501 controller.sendJobs(params.host.get(), params.port.get());
502 return true;
503}
504
505#ifdef HAVE_VMG
506bool createLongRangeJobs(
507 FragmentController &controller,
508 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
509 const std::vector<MPQCData> &fragmentData)
510{
511 std::vector<FragmentJob::ptr> jobs;
512 // add one job for each fragment as the short-range correction which we need
513 // to subtract from the obtained full potential to get the long-range part only
514 for (std::vector<MPQCData>::const_iterator iter = fragmentData.begin();
515 iter != fragmentData.end(); ++iter) {
516 const JobId_t next_id = controller.getAvailableId();
517 LOG(1, "INFO: Creating VMGJob.");
518 FragmentJob::ptr testJob(
519 new VMGJob(next_id, iter->sampled_grid, iter->positions, iter->charges) );
520 jobs.push_back(testJob);
521 }
522
523 // add one more job for the full calculation
524 // TODO: Here, we actually have to combine all the other sampled_grids
525 {
526 const int level = LEVEL;
527 const int GRID = pow(2, level);
528 std::vector<double> full_sample(GRID*GRID*GRID, 0.);
529 double begin[NDIM] = { 0., 0., 0. };
530 const RealSpaceMatrix& M = World::getInstance().getDomain().getM();
531 const double size = M.at(0,0);
532 ASSERT( M.determinant() == size*size*size,
533 "createLongRangeJobs() - current domain matrix "+toString(M)+" is not cubic.");
534 const SamplingGrid full_sampled_grid(begin, size, level, full_sample);
535 const std::vector< std::vector<double> > positions;
536 const std::vector<double> charges;
537 const JobId_t next_id = controller.getAvailableId();
538 FragmentJob::ptr testJob(
539 new VMGJob(next_id, full_sampled_grid, positions, charges) );
540 jobs.push_back(testJob);
541 }
542
543 // then send jobs to controller
544 controller.addJobs(jobs);
545 controller.sendJobs(params.host.get(), params.port.get());
546 return true;
547}
548#endif
549
550void WaitforResults(
551 boost::asio::io_service &io_service,
552 FragmentController &controller,
553 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
554 const size_t NoExpectedResults
555 )
556{
557 size_t NoCalculatedResults = 0;
558 while (NoCalculatedResults != NoExpectedResults) {
559 // wait a bit
560 boost::asio::deadline_timer timer(io_service);
561 timer.expires_from_now(boost::posix_time::milliseconds(500));
562 timer.wait();
563 // then request status
564 controller.checkResults(params.host.get(), params.port.get());
565 RunService(io_service, "Checking on results");
566
567 const std::pair<size_t, size_t> JobStatus = controller.getJobStatus();
568 LOG(1, "INFO: #" << JobStatus.first << " are waiting in the queue and #" << JobStatus.second << " jobs are calculated so far.");
569 NoCalculatedResults = JobStatus.second;
570 }
571}
572
573
574Action::state_ptr FragmentationFragmentationAutomationAction::performCall() {
575 boost::asio::io_service io_service;
576 FragmentController controller(io_service);
577
578 // TODO: Have io_service run in second thread and merge with current again eventually
579
580 // Phase One: obtain ids
581 std::vector< boost::filesystem::path > jobfiles = params.jobfiles.get();
582 requestIds(controller, params, jobfiles.size());
583 RunService(io_service, "Requesting ids");
584
585 // Phase Two: create and add MPQCJobs
586 if (!createJobsFromFiles(controller, params, jobfiles))
587 return Action::failure;
588 RunService(io_service, "Adding MPQCJobs");
589
590 // Phase Three: calculate result
591 WaitforResults(io_service, controller, params, jobfiles.size());
592 controller.receiveResults(params.host.get(), params.port.get());
593 RunService(io_service, "Requesting short-range results");
594 std::vector<FragmentResult::ptr> MPQCresults = controller.getReceivedResults();
595 std::vector<MPQCData> fragmentData;
596 ConvertFragmentResultToMPQCData(MPQCresults, fragmentData);
597
598 // print intermediate short-range results
599 {
600 LOG(1, "INFO: Parsing fragment files from " << params.path.get() << ".");
601 printReceivedMPQCResults(
602 MPQCresults,
603 fragmentData,
604 params.path.get(),
605 getNoAtomsFromAdjacencyFile(params.path.get()));
606 }
607
608#ifdef HAVE_VMG
609 if (params.DoLongrange.get()) {
610 // Phase Four: obtain more ids
611 requestIds(controller, params, fragmentData.size()+1);
612 RunService(io_service, "Requesting ids");
613
614 // Phase Five: create VMGJobs
615 if (!createLongRangeJobs(controller, params, fragmentData))
616 return Action::failure;
617 RunService(io_service, "Adding VMGJobs");
618
619 // Phase Six: calculate result
620 WaitforResults(io_service, controller, params, fragmentData.size()+1);
621 controller.receiveResults(params.host.get(), params.port.get());
622 RunService(io_service, "Requesting long-range results");
623 std::vector<FragmentResult::ptr> VMGresults = controller.getReceivedResults();
624 ASSERT( MPQCresults.size()+1 == VMGresults.size(),
625 "FragmentationFragmentationAutomationAction::performCall() - number of MPQCresultd and VMGresults don't match.");
626
627 // Final phase: print result
628 {
629 LOG(1, "INFO: Parsing fragment files from " << params.path.get() << ".");
630 printReceivedMPQCResults(
631 MPQCresults,
632 fragmentData,
633 params.path.get(),
634 getNoAtomsFromAdjacencyFile(params.path.get()));
635 }
636 }
637#endif
638 size_t Exitflag = controller.getExitflag();
639
640 return (Exitflag == 0) ? Action::success : Action::failure;
641}
642
643Action::state_ptr FragmentationFragmentationAutomationAction::performUndo(Action::state_ptr _state) {
644 return Action::success;
645}
646
647Action::state_ptr FragmentationFragmentationAutomationAction::performRedo(Action::state_ptr _state){
648 return Action::success;
649}
650
651bool FragmentationFragmentationAutomationAction::canUndo() {
652 return false;
653}
654
655bool FragmentationFragmentationAutomationAction::shouldUndo() {
656 return false;
657}
658/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.