/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2011 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * \file controller.cpp * * This file strongly follows the Serialization example from the boost::asio * library (see client.cpp) * * Created on: Nov 27, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif // boost asio needs specific operator new #include #include "CodePatterns/MemDebug.hpp" #include #include #include #include #include #include #include #include #include "atexit.hpp" #include "CodePatterns/Info.hpp" #include "CodePatterns/Log.hpp" #include "Fragmentation/EnergyMatrix.hpp" #include "Fragmentation/ForceMatrix.hpp" #include "Fragmentation/KeySetsContainer.hpp" #include "FragmentController.hpp" #include "Helpers/defs.hpp" #include "Jobs/MPQCCommandJob.hpp" #include "Jobs/MPQCCommandJob_MPQCData.hpp" #include "Jobs/SystemCommandJob.hpp" #include "Results/FragmentResult.hpp" enum CommandIndices { UnknownCommandIndex = 0, AddJobsIndex = 1, CreateJobsIndex = 2, CheckResultsIndex = 3, ReceiveResultsIndex = 4, ReceiveMPQCIndex = 5, ShutdownIndex = 6, }; /** Creates a SystemCommandJob out of give \a command with \a argument. * * @param jobs created job is added to this vector * @param command command to execute for SystemCommandJob * @param argument argument for command to execute * @param nextid id for this job */ void createjobs( std::vector &jobs, const std::string &command, const std::string &argument, const JobId_t nextid) { FragmentJob::ptr testJob( new SystemCommandJob(command, argument, nextid) ); jobs.push_back(testJob); LOG(1, "INFO: Added one SystemCommandJob."); } /** Creates a MPQCCommandJob with argument \a filename. * * @param jobs created job is added to this vector * @param command mpqc command to execute * @param filename filename being argument to job * @param nextid id for this job */ void parsejob( std::vector &jobs, const std::string &command, const std::string &filename, const JobId_t nextid) { std::ifstream file; file.open(filename.c_str()); ASSERT( file.good(), "parsejob() - file "+filename+" does not exist."); std::string output((std::istreambuf_iterator(file)), std::istreambuf_iterator()); FragmentJob::ptr testJob( new MPQCCommandJob(output, nextid, command) ); jobs.push_back(testJob); file.close(); LOG(1, "INFO: Added MPQCCommandJob from file "+filename+"."); } /** Print received results. * * @param results received results to print */ void printReceivedResults(std::vector &results) { for (std::vector::const_iterator iter = results.begin(); iter != results.end(); ++iter) LOG(1, "RESULT: job #"+toString((*iter)->getId())+": "+toString((*iter)->result)); } /** Print MPQCData from received results. * * @param results received results to extract MPQCData from * @param KeySetFilename filename with keysets to associate forces correctly * @param NoAtoms total number of atoms */ bool printReceivedMPQCResults( const std::vector &results, const std::string &KeySetFilename, size_t NoAtoms) { EnergyMatrix Energy; EnergyMatrix EnergyFragments; ForceMatrix Force; ForceMatrix ForceFragments; KeySetsContainer KeySet; // align fragments std::map< JobId_t, size_t > MatrixNrLookup; size_t FragmentCounter = 0; { // bring ids in order ... typedef std::map< JobId_t, FragmentResult::ptr> IdResultMap_t; IdResultMap_t IdResultMap; for (std::vector::const_iterator iter = results.begin(); iter != results.end(); ++iter) { #ifndef NDEBUG std::pair< IdResultMap_t::iterator, bool> inserter = #endif IdResultMap.insert( make_pair((*iter)->getId(), *iter) ); ASSERT( inserter.second, "printReceivedMPQCResults() - two results have same id " +toString((*iter)->getId())+"."); } // ... and fill lookup for(IdResultMap_t::const_iterator iter = IdResultMap.begin(); iter != IdResultMap.end(); ++iter) MatrixNrLookup.insert( make_pair(iter->first, FragmentCounter++) ); } LOG(1, "INFO: There are " << FragmentCounter << " fragments."); // extract results std::vector fragmentData(results.size()); MPQCData combinedData; LOG(2, "DEBUG: Parsing now through " << results.size() << " results."); for (std::vector::const_iterator iter = results.begin(); iter != results.end(); ++iter) { LOG(1, "RESULT: job #"+toString((*iter)->getId())+": "+toString((*iter)->result)); MPQCData extractedData; std::stringstream inputstream((*iter)->result); LOG(2, "DEBUG: First 50 characters FragmentResult's string: "+(*iter)->result.substr(0, 50)); boost::archive::text_iarchive ia(inputstream); ia >> extractedData; LOG(1, "INFO: extracted data is " << extractedData << "."); // place results into EnergyMatrix ... { MatrixContainer::MatrixArray matrix; matrix.resize(1); matrix[0].resize(1, extractedData.energy); if (!Energy.AddMatrix( std::string("MPQCJob ")+toString((*iter)->getId()), matrix, MatrixNrLookup[(*iter)->getId()])) { ELOG(1, "Adding energy matrix failed."); return false; } } // ... and ForceMatrix (with two empty columns in front) { MatrixContainer::MatrixArray matrix; const size_t rows = extractedData.forces.size(); matrix.resize(rows); for (size_t i=0;igetId()), matrix, MatrixNrLookup[(*iter)->getId()])) { ELOG(1, "Adding force matrix failed."); return false; } } } // add one more matrix (not required for energy) MatrixContainer::MatrixArray matrix; matrix.resize(1); matrix[0].resize(1, 0.); if (!Energy.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter)) return false; // but for energy because we need to know total number of atoms matrix.resize(NoAtoms); for (size_t i = 0; i< NoAtoms; ++i) matrix[i].resize(2+NDIM, 0.); if (!Force.AddMatrix(std::string("MPQCJob total"), matrix, FragmentCounter)) return false; // combine all found data if (!Energy.InitialiseIndices()) return false; if (!Force.ParseIndices(KeySetFilename.c_str())) return false; if (!KeySet.ParseKeySets(KeySetFilename.c_str(), Force.RowCounter, Force.MatrixCounter)) return false; if (!KeySet.ParseManyBodyTerms()) return false; if (!EnergyFragments.AllocateMatrix(Energy.Header, Energy.MatrixCounter, Energy.RowCounter, Energy.ColumnCounter)) return false; if (!ForceFragments.AllocateMatrix(Force.Header, Force.MatrixCounter, Force.RowCounter, Force.ColumnCounter)) return false; if(!Energy.SetLastMatrix(0., 0)) return false; if(!Force.SetLastMatrix(0., 2)) return false; for (int BondOrder=0;BondOrder &commandmap, const std::string &cmd) { std::map::const_iterator iter = commandmap.find(cmd); if (iter != commandmap.end()) return iter->second; else return UnknownCommandIndex; } int main(int argc, char* argv[]) { // from this moment on, we need to be sure to deeinitialize in the correct order // this is handled by the cleanup function atexit(cleanUp); setVerbosity(3); size_t Exitflag = 0; typedef std::map CommandsMap_t; CommandsMap_t CommandsMap; CommandsMap.insert( std::make_pair("addjobs", AddJobsIndex) ); CommandsMap.insert( std::make_pair("createjobs", CreateJobsIndex) ); CommandsMap.insert( std::make_pair("checkresults", CheckResultsIndex) ); CommandsMap.insert( std::make_pair("receiveresults", ReceiveResultsIndex) ); CommandsMap.insert( std::make_pair("receivempqc", ReceiveMPQCIndex) ); CommandsMap.insert( std::make_pair("shutdown", ShutdownIndex) ); try { // Check command line arguments. if (argc < 4) { std::cerr << "Usage: " << argv[0] << " [options to command]" << std::endl; std::cerr << "List of available commands:" << std::endl; for(CommandsMap_t::const_iterator iter = CommandsMap.begin(); iter != CommandsMap.end(); ++iter) { std::cerr << "\t" << iter->first << std::endl; } return false; } boost::asio::io_service io_service; FragmentController controller(io_service); // Initial phase: information gathering from server switch(getCommandIndex(CommandsMap, argv[3])) { case AddJobsIndex: { if (argc < 6) { ELOG(1, "'addjobs' requires at least two options: [mpqc] [list of input files ...]."); } else { // get an id for every filename controller.requestIds(argv[1], argv[2], argc-5); } break; } case CreateJobsIndex: { std::vector jobs; if (argc < 6) { ELOG(1, "'createjobs' requires two options: [command] [argument]."); } else { controller.requestIds(argv[1], argv[2], 1); } break; } case CheckResultsIndex: break; case ReceiveResultsIndex: break; case ReceiveMPQCIndex: break; case ShutdownIndex: break; case UnknownCommandIndex: default: ELOG(1, "Unrecognized command '"+toString(argv[3])+"'."); break; } { io_service.reset(); Info info("io_service: Phase One"); io_service.run(); } // Second phase: Building jobs and sending information to server switch(getCommandIndex(CommandsMap, argv[3])) { case AddJobsIndex: { std::vector jobs; if (argc < 6) { ELOG(1, "Please add a filename for the MPQCCommandJob."); } else { const std::string command(argv[4]); for (int argcount = 5; argcount < argc; ++argcount) { const JobId_t next_id = controller.getAvailableId(); const std::string filename(argv[argcount]); LOG(1, "INFO: Creating MPQCCommandJob with filename'" +filename+"', and id "+toString(next_id)+"."); parsejob(jobs, command, filename, next_id); } controller.addJobs(jobs); controller.sendJobs(argv[1], argv[2]); } break; } case CreateJobsIndex: { std::vector jobs; if (argc < 6) { ELOG(1, "'createjobs' requires two options: [command] [argument]."); } else { const JobId_t next_id = controller.getAvailableId(); createjobs(jobs, argv[4], argv[5], next_id); controller.addJobs(jobs); controller.sendJobs(argv[1], argv[2]); } break; } case CheckResultsIndex: { controller.checkResults(argv[1], argv[2]); break; } case ReceiveResultsIndex: { controller.receiveResults(argv[1], argv[2]); break; } case ReceiveMPQCIndex: { controller.receiveResults(argv[1], argv[2]); break; } case ShutdownIndex: { controller.shutdown(argv[1], argv[2]); break; } case UnknownCommandIndex: default: ELOG(0, "Unrecognized command '"+toString(argv[3])+"'."); break; } { io_service.reset(); Info info("io_service: Phase Two"); io_service.run(); } // Final phase: Print result of command switch(getCommandIndex(CommandsMap, argv[3])) { case AddJobsIndex: case CreateJobsIndex: break; case CheckResultsIndex: { controller.printDoneJobs(); break; } case ReceiveResultsIndex: { std::vector results = controller.getReceivedResults(); printReceivedResults(results); break; } case ReceiveMPQCIndex: { if (argc < 5) { ELOG(1, "'receivempqc' require one option: [path to fragment files]."); } else { const std::string path = argv[4]; LOG(1, "INFO: Parsing fragment files from " << path << "."); std::vector results = controller.getReceivedResults(); printReceivedMPQCResults( results, path, getNoAtomsFromAdjacencyFile(path)); } break; } case ShutdownIndex: break; case UnknownCommandIndex: default: ELOG(0, "Unrecognized command '"+toString(argv[3])+"'."); break; } Exitflag = controller.getExitflag(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return Exitflag; }