/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2011 University of Bonn. All rights reserved. * Copyright (C) 2013 Frederik Heber. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * MoleCuilder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * ExportGraph_ToJobs.cpp * * Created on: 08.03.2012 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif // boost asio required before MemDebug due to placement new #include //#include "CodePatterns/MemDebug.hpp" #include "Fragmentation/Exporters/ExportGraph_ToJobs.hpp" #include #include #include #include "CodePatterns/Log.hpp" #include "Box.hpp" #include "Fragmentation/KeySet.hpp" #include "Fragmentation/Automation/FragmentJobQueue.hpp" #include "Helpers/defs.hpp" #ifdef HAVE_JOBMARKET #include "Jobs/MPQCJob.hpp" #else #include "Jobs/MPQCCommandJob.hpp" #endif #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "Parser/FormatParserStorage.hpp" #include "World.hpp" const double ExportGraph_ToJobs::log_two(log(2.)); ExportGraph_ToJobs::ExportGraph_ToJobs( const Graph &_graph, const enum HydrogenTreatment _treatment, const enum HydrogenSaturation _saturation, const SaturatedFragment::GlobalSaturationPositions_t &_globalsaturationpositions) : ExportGraph(_graph, _treatment, _saturation,_globalsaturationpositions), level(5), max_meshwidth(0.), minimum_empty_boundary(5./AtomicLengthToAngstroem) {} ExportGraph_ToJobs::~ExportGraph_ToJobs() {} SamplingGridProperties ExportGraph_ToJobs::getDomainGrid( const int _level) { double domain_begin[NDIM] = { 0., 0., 0. }; RealSpaceMatrix M = World::getInstance().getDomain().getM(); M *= 1./AtomicLengthToAngstroem; // scale to atomic length units const double size = std::max( std::max(M.at(0,0), M.at(1,1)), M.at(2,2)); double domain_end[NDIM] = { size, size, size }; SamplingGridProperties grid(domain_begin, domain_end, _level); return grid; } SamplingGridProperties ExportGraph_ToJobs::getGridExtentsForGivenBoundingBox( const std::pair &_minmax, const SamplingGridProperties &_domain, const double & _minimum_empty_boundary ) { // return value SamplingGridProperties fragment_window; /// determine center of fragment const Vector center = .5*(_minmax.first + _minmax.second); LOG(4, "DEBUG: center of fragment is at " << center); /// associate center to its containing grid cell (defined by boundary points) Vector lower_center; Vector higher_center; bool equal_components[NDIM] = { false, false, false }; for (size_t i=0;i::epsilon()*1e4; } LOG(5, "DEBUG: lower_center is " << lower_center << ", higher_center is " << higher_center); // fashion min max into cubic box extents of at least extent plus empty // boundary and at most three times the extent const Vector extent = _minmax.second - _minmax.first; double greatest_extent = extent[extent.GreatestComponent()]; if (greatest_extent > _minimum_empty_boundary) greatest_extent *= 3.; else greatest_extent += 2.* _minimum_empty_boundary; const Vector total( _domain.getTotalLengthPerAxis(0), _domain.getTotalLengthPerAxis(1), _domain.getTotalLengthPerAxis(2) ); const double greatest_total = total[total.GreatestComponent()]; greatest_extent = std::min(greatest_extent, greatest_total); LOG(5, "DEBUG: extent of fragment is " << extent << ", greatest_extent is " << greatest_extent); /// increase levels around this center to find the matching window const double delta[NDIM] = { _domain.getDeltaPerAxis(0), _domain.getDeltaPerAxis(1), _domain.getDeltaPerAxis(2) }; LOG(6, "DEBUG: delta is " << Vector(delta)); const double greatest_delta = std::max(delta[0], std::max(delta[1], delta[2])); fragment_window.level = (int)ceil(log(greatest_extent/greatest_delta+1)/log_two); const size_t half_fragment_gridpoints = 1 << (fragment_window.level-1); const size_t domain_gridpoints = _domain.getGridPointsPerAxis(); int begin_index[NDIM]; int end_index[NDIM]; int begin_steps[NDIM] = { 0, 0, 0 }; int end_steps[NDIM] = { 0, 0, 0 }; for (size_t i=0;i (int)domain_gridpoints) end_steps[i] = end_index[i] - domain_gridpoints; if ((begin_steps[i]+end_steps[i]+end_index[i]-begin_index[i] > (int)domain_gridpoints) || ((begin_steps[i] != 0) && (end_steps[i] != 0))) { begin_index[i] = 0; end_index[i] = domain_gridpoints; begin_steps[i] = 0; end_steps[i] = 0; } } for (size_t i=0;i "+toString(_minmax.second)); } #endif #ifndef NDEBUG for (size_t i=0;i= _domain.begin[i], "ExportGraph_ToJobs::getGridExtentsForGivenBoundingBox() - fragment begin " +toString(fragment_window.begin[i])+" is smaller than that of domain " +toString(_domain.begin[i])); ASSERT( fragment_window.end[i] <= _domain.end[i], "ExportGraph_ToJobs::getGridExtentsForGivenBoundingBox() - fragment end " +toString(fragment_window.end[i])+" is smaller than that of domain " +toString(_domain.end[i])); } #endif if (DoLog(6)) for (size_t i=0;i jobs; KeySetsContainer KeySets; KeySetsContainer FullKeySets; FragmentJobQueue::edges_per_fragment_t edges_per_fragment; jobs.reserve(TotalGraph.size()); LOG(1, "INFO: Creating " << TotalGraph.size() << " possible bond fragmentation jobs."); // checking that max-meshwidth is not smaller than grid spacing of global level const SamplingGridProperties grid(getDomainGrid(level)); // gather info about the domain const double global_grid_delta = std::max(grid.getDeltaPerAxis(0), std::max(grid.getDeltaPerAxis(1), grid.getDeltaPerAxis(2))); if (global_grid_delta < max_meshwidth) { ELOG(2, "Desired max meswidth " << max_meshwidth << " is larger than grid spacing of global grid " << global_grid_delta << ".\n" << "We cannot use coarser grids in fragment level, equating mesh width to global delta."); max_meshwidth = global_grid_delta; } // set parser to use for writing job configurations const ParserTypes jobtype = FormatParserStorage::getInstance().getTypeFromName("mpqc"); // go through all fragments, output to stream and create job therefrom ExportGraph::SaturatedFragment_ptr CurrentFragment = getNextFragment(); for (; (CurrentFragment != NULL) && (CurrentFragment->getKeySet() != ExportGraph::EmptySet); CurrentFragment = getNextFragment()) { const KeySet &set = CurrentFragment->getKeySet(); LOG(2, "INFO: Creating bond fragment job for set " << set << "."); // gather all edges FragmentationEdges::edges_t edges = CurrentFragment->getEdges(); SamplingGridProperties fragment_window(grid); if (max_meshwidth != 0.) { // gather extent of the fragment in atomic length(!) std::pair minmax = CurrentFragment->getRoughBoundingBox(); minmax.first *= 1./AtomicLengthToAngstroem; minmax.second *= 1./AtomicLengthToAngstroem; /** we need to find the begin and end points of the smaller grid * otherwise we would calculate the whole domain with an incrased grid level with just * a small window (which is only used for sampling and storing; vmg uses full grid). * Hence, we need to make the grid smaller and such that it is still in a power of two * and coinciding with the grid points of the global grid. */ fragment_window = getGridExtentsForGivenBoundingBox(minmax, grid, minimum_empty_boundary); LOG(4, "DEBUG: Fragment " << CurrentFragment->getKeySet() << " has window from " << Vector(fragment_window.begin) << " to " << Vector(fragment_window.end) << " with total level portion of " << fragment_window.level ); // next we need to check how much we need to increase from the grid level for // the total domain to achieve at least maximum mesh width setAcceptableFragmentLevel(fragment_window, max_meshwidth/AtomicLengthToAngstroem); } // store config in stream { std::stringstream output; // save to stream CurrentFragment->OutputConfig(output, jobtype); // create job and insert FragmentJob::ptr testJob( #ifdef HAVE_JOBMARKET new MPQCJob( JobId::IllegalJob, output.str(), fragment_window.begin, fragment_window.end, fragment_window.level) #else new MPQCCommandJob(output.str(), JobId::IllegalJob) #endif ); testJob->setPriority(CurrentFragment->getKeySet().size()); jobs.push_back(testJob); // order is the same as the number of non-hydrogen atoms const KeySet &keyset = CurrentFragment->getKeySet(); const size_t order = keyset.size(); const KeySet &fullmolecule = CurrentFragment->getFullMolecule(); const KeySet &saturationhydrogens = CurrentFragment->getSaturationHydrogens(); KeySetsContainer::IntVector indices(keyset.begin(), keyset.end()); KeySetsContainer::IntVector forceindices(fullmolecule.begin(), fullmolecule.end()); { // replace all saturated hydrogen indices by "-1" for (KeySetsContainer::IntVector::iterator iter = forceindices.begin(); iter != forceindices.end(); ++iter) if (saturationhydrogens.find(*iter) != saturationhydrogens.end()) *iter = -1; } KeySets.insert(indices, order); FullKeySets.insert(forceindices, order); edges_per_fragment.push_back(edges); } // store force index reference file // explicitly release fragment CurrentFragment.reset(); } if (CurrentFragment == NULL) { ELOG(1, "Some error while obtaining the next fragment occured."); return false; } // push final jobs FragmentJobQueue::getInstance().addJobs(jobs, KeySets, FullKeySets, edges_per_fragment); return true; }