/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2012 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * Filler.cpp * * Created on: Jan 16, 2012 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include #include #include #include #include #include "Filler.hpp" #include "CodePatterns/Assert.hpp" #include "CodePatterns/Log.hpp" #include "Atom/atom.hpp" #include "Box.hpp" #include "ClusterInterface.hpp" #include "Descriptors/AtomIdDescriptor.hpp" #include "Inserter/Inserter.hpp" #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "LinearAlgebra/Vector.hpp" #include "NodeTypes.hpp" #include "Predicates/FillPredicate.hpp" #include "Predicates/Ops_FillPredicate.hpp" #include "World.hpp" /** Constructor for class Filler. * * \note We store inverted \a _predicate because we need it only for * remove_copy_if which works in this inverted way as desired. * * @param _mesh Mesh with a NodeSet that fills its Shape * @param _predicate predicate construct to check at each Node * @param _inserter inserter which places the cloned cluster */ Filler::Filler(const Mesh &_mesh, const FillPredicate &_predicate, const Inserter &_inserter) : mesh(_mesh), predicate(!_predicate), inserter(_inserter) {} /** Destructor for class Filler. * */ Filler::~Filler() {} /** Fill in the desired Cluster at each remaining node. * * \note The cluster is non-const because it is moved to the first vacant node. * * @param copyMethod functor that knows how to copy atoms. * @param cluster set of atomic ids contained in a specific Shape to fill each Node with * @return true - at least one node has been filled, false - no node filled */ bool Filler::operator()( CopyAtomsInterface ©Method, ClusterInterface::Cluster_impl cluster) const { const NodeSet &nodes = mesh.getNodes(); std::stringstream output; std::for_each( nodes.begin(), nodes.end(), output << boost::lambda::_1 << " "); LOG(3, "DEBUG: Listing nodes to check: " << output.str()); if (nodes.size() == 0) return false; NodeSet FillNodes(nodes.size(), zeroVec); // move filler cluster's atoms out of domain such that it does not disturb the predicate. // we only move the atoms as otherwise two translate ShapeOps will be on top of the Shape // which is subsequently copied to all other cloned Clusters ... Vector BoxDiagonal; { const RealSpaceMatrix &M = World::getInstance().getDomain().getM(); BoxDiagonal = (M * Vector(1.,1.,1.)); BoxDiagonal -= cluster->getShape().getCenter(); BoxDiagonal *= 1. + 2.*cluster->getShape().getRadius()/BoxDiagonal.Norm(); // extend it a little further AtomIdSet atoms = cluster->getAtoms(); for (AtomIdSet::iterator iter = atoms.begin(); iter != atoms.end(); ++iter) (*iter)->setPosition( (*iter)->getPosition() + BoxDiagonal ); LOG(1, "INFO: Translating original cluster's atoms by " << BoxDiagonal << "."); } // evaluate predicate and gather into new set NodeSet::iterator transform_end = std::remove_copy_if(nodes.begin(), nodes.end(), FillNodes.begin(), predicate ); FillNodes.erase(transform_end, FillNodes.end()); // shift cluster back to original place { AtomIdSet atoms = cluster->getAtoms(); for (AtomIdSet::iterator iter = atoms.begin(); iter != atoms.end(); ++iter) (*iter)->setPosition( (*iter)->getPosition() - BoxDiagonal ); LOG(1, "INFO: Translating original cluster's atoms back."); } if (FillNodes.size() == 0) { ELOG(2, "For none of the nodes did the predicate return true."); return false; } else { LOG(1, "INFO: " << FillNodes.size() << " out of " << nodes.size() << " returned true from predicate."); } // clone clusters std::vector clusters(FillNodes.size()); std::vector::iterator clusteriter = clusters.begin(); *clusteriter = cluster; clusteriter++; std::generate_n(clusteriter, FillNodes.size()-1, boost::bind(&ClusterInterface::clone, boost::cref(cluster), boost::ref(copyMethod), zeroVec) ); // insert each cluster by abusing std::search a bit: // we look for the subsequence of FillNodes inside clusters. If Inserter always // returns true, we'll have the iterator pointing at first cluster std::vector::const_iterator inserteriter = std::search(clusters.begin(), clusters.end(), FillNodes.begin(), FillNodes.end(), boost::bind(&Inserter::operator(), boost::cref(inserter), _1, _2)); if( inserteriter != clusters.begin()) { ELOG(1, "Not all cloned clusters could be successfully inserted."); return false; } // give final statment on whether at least \a single cluster has been placed if ( FillNodes.size() != 0) return true; else return false; }