/*
* 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;
}