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

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

Refactored FragmentationAutomationAction, pulling out bracketed function parts into distinct functions.

  • Property mode set to 100644
File size: 13.3 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/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.energies.total);
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
278
279void RunService(
280 boost::asio::io_service &io_service,
281 std::string message)
282{
283 message = std::string("io_service: ") + message;
284 io_service.reset();
285 Info info(message.c_str());
286 io_service.run();
287}
288
289void requestIds(
290 FragmentController &controller,
291 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
292 const size_t numberjobs)
293{
294 controller.requestIds(params.host.get(), params.port.get(), numberjobs);
295}
296
297bool createJobsFromFiles(
298 FragmentController &controller,
299 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
300 const std::vector< boost::filesystem::path > &jobfiles)
301{
302 std::vector<FragmentJob::ptr> jobs;
303 for (std::vector< boost::filesystem::path >::const_iterator iter = jobfiles.begin();
304 iter != jobfiles .end(); ++iter) {
305 const std::string &filename = (*iter).string();
306 if (boost::filesystem::exists(filename)) {
307 const JobId_t next_id = controller.getAvailableId();
308 LOG(1, "INFO: Creating MPQCCommandJob with filename'"
309 +filename+"', and id "+toString(next_id)+".");
310 parsejob(jobs, params.executable.get().string(), filename, next_id);
311 } else {
312 ELOG(1, "Fragment job "+filename+" does not exist.");
313 return false;
314 }
315 }
316 controller.addJobs(jobs);
317 controller.sendJobs(params.host.get(), params.port.get());
318 return true;
319}
320
321void WaitforResults(
322 boost::asio::io_service &io_service,
323 FragmentController &controller,
324 const FragmentationFragmentationAutomationAction::FragmentationFragmentationAutomationParameters &params,
325 const size_t NoExpectedResults
326 )
327{
328 size_t NoCalculatedResults = 0;
329 while (NoCalculatedResults != NoExpectedResults) {
330 // wait a bit
331 boost::asio::deadline_timer timer(io_service);
332 timer.expires_from_now(boost::posix_time::milliseconds(500));
333 timer.wait();
334 // then request status
335 controller.checkResults(params.host.get(), params.port.get());
336 RunService(io_service, "Checking on results");
337
338 const std::pair<size_t, size_t> JobStatus = controller.getJobStatus();
339 LOG(1, "INFO: #" << JobStatus.first << " are waiting in the queue and #" << JobStatus.second << " jobs are calculated so far.");
340 NoCalculatedResults = JobStatus.second;
341 }
342}
343
344
345Action::state_ptr FragmentationFragmentationAutomationAction::performCall() {
346 boost::asio::io_service io_service;
347 FragmentController controller(io_service);
348
349 // TODO: Have io_service run in second thread and merge with current again eventually
350
351 // Phase One: obtain ids
352 std::vector< boost::filesystem::path > jobfiles = params.jobfiles.get();
353 requestIds(controller, params, jobfiles.size());
354 RunService(io_service, "Requesting ids");
355
356 // Phase Two: create and add jobs
357 if (!createJobsFromFiles(controller, params, jobfiles))
358 return Action::failure;
359 RunService(io_service, "Adding jobs");
360
361 // Phase Three: calculate result
362 WaitforResults(io_service, controller, params, jobfiles.size());
363
364 // Phase Three: get result
365 controller.receiveResults(params.host.get(), params.port.get());
366 RunService(io_service, "Phase Four");
367
368 // Final phase: print result
369 {
370 LOG(1, "INFO: Parsing fragment files from " << params.path.get() << ".");
371 std::vector<FragmentResult::ptr> results = controller.getReceivedResults();
372 printReceivedMPQCResults(
373 results,
374 params.path.get(),
375 getNoAtomsFromAdjacencyFile(params.path.get()));
376 }
377 size_t Exitflag = controller.getExitflag();
378
379 return (Exitflag == 0) ? Action::success : Action::failure;
380}
381
382Action::state_ptr FragmentationFragmentationAutomationAction::performUndo(Action::state_ptr _state) {
383 return Action::success;
384}
385
386Action::state_ptr FragmentationFragmentationAutomationAction::performRedo(Action::state_ptr _state){
387 return Action::success;
388}
389
390bool FragmentationFragmentationAutomationAction::canUndo() {
391 return false;
392}
393
394bool FragmentationFragmentationAutomationAction::shouldUndo() {
395 return false;
396}
397/** =========== end of function ====================== */
Note: See TracBrowser for help on using the repository browser.