source: src/Actions/FragmentationAction/FragmentationAutomationAction.cpp@ 28e894

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

FragmentationAutomationAction now creates MPQCJobs.

  • MPQCJobs are simply MPQCCommandJobs without the command, i.e. they do not inherit SystemCommandJob but derived directly from mpqc and receive the inputfile via JobMarket's FragmentJob and also transmit the results directly encapsulated in MPQCData in a FragmentResult.
  • Property mode set to 100644
File size: 12.4 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 "CodePatterns/Info.hpp"
42#include "CodePatterns/Log.hpp"
43#include "JobMarket/Controller/FragmentController.hpp"
44#include "JobMarket/Jobs/FragmentJob.hpp"
45
46#include "Atom/atom.hpp"
47#include "Fragmentation/EnergyMatrix.hpp"
48#include "Fragmentation/ForceMatrix.hpp"
49#include "Fragmentation/Fragmentation.hpp"
50#include "Fragmentation/HydrogenSaturation_enum.hpp"
51#include "Fragmentation/KeySetsContainer.hpp"
52#include "Graph/DepthFirstSearchAnalysis.hpp"
53#include "Jobs/MPQCJob.hpp"
54#include "Jobs/MPQCCommandJob_MPQCData.hpp"
55#include "molecule.hpp"
56#include "World.hpp"
57
58#include <iostream>
59#include <string>
60#include <vector>
61
62#include "Actions/FragmentationAction/FragmentationAutomationAction.hpp"
63
64using namespace MoleCuilder;
65
66// and construct the stuff
67#include "FragmentationAutomationAction.def"
68#include "Action_impl_pre.hpp"
69/** =========== define the function ====================== */
70
71class controller_AddOn;
72
73// needs to be defined for using the FragmentController
74controller_AddOn *getAddOn()
75{
76 return NULL;
77}
78
79/** Creates a MPQCCommandJob with argument \a filename.
80 *
81 * @param jobs created job is added to this vector
82 * @param command mpqc command to execute
83 * @param filename filename being argument to job
84 * @param nextid id for this job
85 */
86void parsejob(
87 std::vector<FragmentJob::ptr> &jobs,
88 const std::string &command,
89 const std::string &filename,
90 const JobId_t nextid)
91{
92 std::ifstream file;
93 file.open(filename.c_str());
94 ASSERT( file.good(), "parsejob() - file "+filename+" does not exist.");
95 std::string output((std::istreambuf_iterator<char>(file)),
96 std::istreambuf_iterator<char>());
97 FragmentJob::ptr testJob( new MPQCJob(nextid, output) );
98 jobs.push_back(testJob);
99 file.close();
100 LOG(1, "INFO: Added MPQCCommandJob from file "+filename+".");
101}
102
103/** Helper function to get number of atoms somehow.
104 *
105 * Here, we just parse the number of lines in the adjacency file as
106 * it should correspond to the number of atoms, except when some atoms
107 * are not bonded, but then fragmentation makes no sense.
108 *
109 * @param path path to the adjacency file
110 */
111size_t getNoAtomsFromAdjacencyFile(const std::string &path)
112{
113 size_t NoAtoms = 0;
114
115 // parse in special file to get atom count (from line count)
116 std::string filename(path);
117 filename += FRAGMENTPREFIX;
118 filename += ADJACENCYFILE;
119 std::ifstream adjacency(filename.c_str());
120 if (adjacency.fail()) {
121 LOG(0, endl << "getNoAtomsFromAdjacencyFile() - Unable to open " << filename << ", is the directory correct?");
122 return false;
123 }
124 std::string buffer;
125 while (getline(adjacency, buffer))
126 NoAtoms++;
127 LOG(1, "INFO: There are " << NoAtoms << " atoms.");
128
129 return NoAtoms;
130}
131
132
133/** Print MPQCData from received results.
134 *
135 * @param results received results to extract MPQCData from
136 * @param KeySetFilename filename with keysets to associate forces correctly
137 * @param NoAtoms total number of atoms
138 */
139bool printReceivedMPQCResults(
140 const std::vector<FragmentResult::ptr> &results,
141 const std::string &KeySetFilename,
142 size_t NoAtoms)
143{
144 EnergyMatrix Energy;
145 EnergyMatrix EnergyFragments;
146 ForceMatrix Force;
147 ForceMatrix ForceFragments;
148 KeySetsContainer KeySet;
149
150 // align fragments
151 std::map< JobId_t, size_t > MatrixNrLookup;
152 size_t FragmentCounter = 0;
153 {
154 // bring ids in order ...
155 typedef std::map< JobId_t, FragmentResult::ptr> IdResultMap_t;
156 IdResultMap_t IdResultMap;
157 for (std::vector<FragmentResult::ptr>::const_iterator iter = results.begin();
158 iter != results.end(); ++iter) {
159 #ifndef NDEBUG
160 std::pair< IdResultMap_t::iterator, bool> inserter =
161 #endif
162 IdResultMap.insert( make_pair((*iter)->getId(), *iter) );
163 ASSERT( inserter.second,
164 "printReceivedMPQCResults() - two results have same id "
165 +toString((*iter)->getId())+".");
166 }
167 // ... and fill lookup
168 for(IdResultMap_t::const_iterator iter = IdResultMap.begin();
169 iter != IdResultMap.end(); ++iter)
170 MatrixNrLookup.insert( make_pair(iter->first, FragmentCounter++) );
171 }
172 LOG(1, "INFO: There are " << FragmentCounter << " fragments.");
173
174 // extract results
175 std::vector<MPQCData> fragmentData(results.size());
176 MPQCData combinedData;
177
178 LOG(2, "DEBUG: Parsing now through " << results.size() << " results.");
179 for (std::vector<FragmentResult::ptr>::const_iterator iter = results.begin();
180 iter != results.end(); ++iter) {
181 LOG(1, "RESULT: job #"+toString((*iter)->getId())+": "+toString((*iter)->result));
182 MPQCData extractedData;
183 std::stringstream inputstream((*iter)->result);
184 LOG(2, "DEBUG: First 50 characters FragmentResult's string: "+(*iter)->result.substr(0, 50));
185 boost::archive::text_iarchive ia(inputstream);
186 ia >> extractedData;
187 LOG(1, "INFO: extracted data is " << extractedData << ".");
188
189 // place results into EnergyMatrix ...
190 {
191 MatrixContainer::MatrixArray matrix;
192 matrix.resize(1);
193 matrix[0].resize(1, extractedData.energy);
194 if (!Energy.AddMatrix(
195 std::string("MPQCJob ")+toString((*iter)->getId()),
196 matrix,
197 MatrixNrLookup[(*iter)->getId()])) {
198 ELOG(1, "Adding energy matrix failed.");
199 return false;
200 }
201 }
202 // ... and ForceMatrix (with two empty columns in front)
203 {
204 MatrixContainer::MatrixArray matrix;
205 const size_t rows = extractedData.forces.size();
206 matrix.resize(rows);
207 for (size_t i=0;i<rows;++i) {
208 const size_t columns = 2+extractedData.forces[i].size();
209 matrix[i].resize(columns, 0.);
210 // for (size_t j=0;j<2;++j)
211 // matrix[i][j] = 0.;
212 for (size_t j=2;j<columns;++j)
213 matrix[i][j] = extractedData.forces[i][j-2];
214 }
215 if (!Force.AddMatrix(
216 std::string("MPQCJob ")+toString((*iter)->getId()),
217 matrix,
218 MatrixNrLookup[(*iter)->getId()])) {
219 ELOG(1, "Adding force matrix failed.");
220 return false;
221 }
222 }
223 }
224 // add one more matrix (not required for energy)
225 MatrixContainer::MatrixArray matrix;
226 matrix.resize(1);
227 matrix[0].resize(1, 0.);
228 if (!Energy.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter))
229 return false;
230 // but for energy because we need to know total number of atoms
231 matrix.resize(NoAtoms);
232 for (size_t i = 0; i< NoAtoms; ++i)
233 matrix[i].resize(2+NDIM, 0.);
234 if (!Force.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter))
235 return false;
236
237
238 // combine all found data
239 if (!Energy.InitialiseIndices()) return false;
240
241 if (!Force.ParseIndices(KeySetFilename.c_str())) return false;
242
243 if (!KeySet.ParseKeySets(KeySetFilename.c_str(), Force.RowCounter, Force.MatrixCounter)) return false;
244
245 if (!KeySet.ParseManyBodyTerms()) return false;
246
247 if (!EnergyFragments.AllocateMatrix(Energy.Header, Energy.MatrixCounter, Energy.RowCounter, Energy.ColumnCounter)) return false;
248 if (!ForceFragments.AllocateMatrix(Force.Header, Force.MatrixCounter, Force.RowCounter, Force.ColumnCounter)) return false;
249
250 if(!Energy.SetLastMatrix(0., 0)) return false;
251 if(!Force.SetLastMatrix(0., 2)) return false;
252
253 for (int BondOrder=0;BondOrder<KeySet.Order;BondOrder++) {
254 // --------- sum up energy --------------------
255 LOG(1, "INFO: Summing energy of order " << BondOrder+1 << " ...");
256 if (!EnergyFragments.SumSubManyBodyTerms(Energy, KeySet, BondOrder)) return false;
257 if (!Energy.SumSubEnergy(EnergyFragments, NULL, KeySet, BondOrder, 1.)) return false;
258
259 // --------- sum up Forces --------------------
260 LOG(1, "INFO: Summing forces of order " << BondOrder+1 << " ...");
261 if (!ForceFragments.SumSubManyBodyTerms(Force, KeySet, BondOrder)) return false;
262 if (!Force.SumSubForces(ForceFragments, KeySet, BondOrder, 1.)) return false;
263 }
264
265 // for debugging print resulting energy and forces
266 LOG(1, "INFO: Resulting energy is " << Energy.Matrix[ FragmentCounter ][0][0]);
267 std::stringstream output;
268 for (int i=0; i< Force.RowCounter[FragmentCounter]; ++i) {
269 for (int j=0; j< Force.ColumnCounter[FragmentCounter]; ++j)
270 output << Force.Matrix[ FragmentCounter ][i][j] << " ";
271 output << "\n";
272 }
273 LOG(1, "INFO: Resulting forces are " << std::endl << output.str());
274
275 return true;
276}
277
278Action::state_ptr FragmentationFragmentationAutomationAction::performCall() {
279 boost::asio::io_service io_service;
280 FragmentController controller(io_service);
281
282 // TODO: Have io_service run in second thread and merge with current again eventually
283
284 // Phase One: obtain ids
285 std::vector< boost::filesystem::path > jobfiles = params.jobfiles.get();
286 controller.requestIds(params.host.get(), params.port.get(), jobfiles.size());
287 {
288 io_service.reset();
289 Info info("io_service: Phase One");
290 io_service.run();
291 }
292 // Phase Two: create and add jobs
293 {
294 std::vector<FragmentJob::ptr> jobs;
295 for (std::vector< boost::filesystem::path >::const_iterator iter = jobfiles .begin();
296 iter != jobfiles .end(); ++iter) {
297 const std::string &filename = (*iter).string();
298 if (boost::filesystem::exists(filename)) {
299 const JobId_t next_id = controller.getAvailableId();
300 LOG(1, "INFO: Creating MPQCCommandJob with filename'"
301 +filename+"', and id "+toString(next_id)+".");
302 parsejob(jobs, params.executable.get().string(), filename, next_id);
303 } else {
304 ELOG(1, "Fragment job "+filename+" does not exist.");
305 return Action::failure;
306 }
307 }
308 controller.addJobs(jobs);
309 controller.sendJobs(params.host.get(), params.port.get());
310 }
311 {
312 io_service.reset();
313 Info info("io_service: Phase Two");
314 io_service.run();
315 }
316 // Phase Three: calculate result
317 size_t NoCalculatedResults = 0;
318 while (NoCalculatedResults != jobfiles.size()) {
319 // wait a bit
320 boost::asio::deadline_timer timer(io_service);
321 timer.expires_from_now(boost::posix_time::milliseconds(500));
322 timer.wait();
323 // then request status
324 controller.checkResults(params.host.get(), params.port.get());
325 {
326 io_service.reset();
327 Info info("io_service: Phase Three");
328 io_service.run();
329 }
330 const std::pair<size_t, size_t> JobStatus = controller.getJobStatus();
331 LOG(1, "INFO: #" << JobStatus.first << " are waiting in the queue and #" << JobStatus.second << " jobs are calculated so far.");
332 NoCalculatedResults = JobStatus.second;
333 }
334 // Phase Three: get result
335 controller.receiveResults(params.host.get(), params.port.get());
336 {
337 io_service.reset();
338 Info info("io_service: Phase Four");
339 io_service.run();
340 }
341 // Final phase: print result
342 {
343 LOG(1, "INFO: Parsing fragment files from " << params.path.get() << ".");
344 std::vector<FragmentResult::ptr> results = controller.getReceivedResults();
345 printReceivedMPQCResults(
346 results,
347 params.path.get(),
348 getNoAtomsFromAdjacencyFile(params.path.get()));
349 }
350 size_t Exitflag = controller.getExitflag();
351
352 return (Exitflag == 0) ? Action::success : Action::failure;
353}
354
355Action::state_ptr FragmentationFragmentationAutomationAction::performUndo(Action::state_ptr _state) {
356 return Action::success;
357}
358
359Action::state_ptr FragmentationFragmentationAutomationAction::performRedo(Action::state_ptr _state){
360 return Action::success;
361}
362
363bool FragmentationFragmentationAutomationAction::canUndo() {
364 return false;
365}
366
367bool FragmentationFragmentationAutomationAction::shouldUndo() {
368 return false;
369}
370/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.