/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2012 University of Bonn. 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 . */ /* * RandomInserter.cpp * * Created on: Feb 21, 2012 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif //#include "CodePatterns/MemDebug.hpp" #include "RandomInserter.hpp" #include #include "Atom/atom.hpp" #include "CodePatterns/Log.hpp" #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "RandomNumbers/RandomNumberGeneratorFactory.hpp" #include "RandomNumbers/RandomNumberGenerator.hpp" size_t RandomInserter::Max_Attempts = 10; /** Sets given 3x3 matrix to a random rotation matrix. * * @param a matrix to set */ inline void setRandomRotation(RealSpaceMatrix &a) { double phi[NDIM]; RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator(); const double rng_min = random.min(); const double rng_max = random.max(); for (int i=0;igetAtomIds(); bool status = true; for (ClusterInterface::atomIdSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) status = status && cluster->isInside(*iter); return status; } /** Perform the given random translations and rotations on a cluster. * * @param cluster cluster to translate and rotate * @param Rotations random rotation matrix * @param RandomAtomTranslations vector with random translation for each atom in cluster * @param RandomMoleculeTranslation vector with random translation for cluster * @param offset vector with offset for cluster */ void RandomInserter::doTranslation( ClusterInterface::Cluster_impl cluster, const RealSpaceMatrix &Rotations, const std::vector &RandomAtomTranslations, const Vector &RandomMoleculeTranslation) const { AtomIdSet atoms = cluster->getAtoms(); ASSERT( atoms.size() <= RandomAtomTranslations.size(), "RandomInserter::doTranslation() - insufficient random atom translations given."); cluster->transform(Rotations); cluster->translate(RandomMoleculeTranslation); AtomIdSet::iterator miter = atoms.begin(); std::vector::const_iterator aiter = RandomAtomTranslations.begin(); for(;miter != atoms.end(); ++miter, ++aiter) (*miter)->setPosition((*miter)->getPosition() + *aiter); ASSERT( aiter == RandomAtomTranslations.end(), "RandomInserter::doTranslation() - there are more RandomAtomTranslations than atoms?"); } /** Undos a given random translations and rotations on a cluster. * * @param cluster cluster to translate and rotate * @param Rotations random rotation matrix * @param RandomAtomTranslations vector with random translation for each atom in cluster * @param RandomMoleculeTranslations vector with random translation for cluster * @param offset vector with offset for cluster */ void RandomInserter::undoTranslation( ClusterInterface::Cluster_impl cluster, const RealSpaceMatrix &Rotations, const std::vector &RandomAtomTranslations, const Vector &RandomMoleculeTranslation) const { AtomIdSet atoms = cluster->getAtoms(); ASSERT( atoms.size() <= RandomAtomTranslations.size(), "RandomInserter::doTranslation() - insufficient random atom translations given."); // get inverse rotation RealSpaceMatrix inverseRotations = Rotations.invert(); AtomIdSet::iterator miter = atoms.begin(); std::vector::const_iterator aiter = RandomAtomTranslations.begin(); for(;miter != atoms.end(); ++miter, ++aiter) { (*miter)->setPosition((*miter)->getPosition() - *aiter); } ASSERT( aiter == RandomAtomTranslations.end(), "RandomInserter::undoTranslation() - there are more RandomAtomTranslations than atoms?"); cluster->translate(zeroVec-RandomMoleculeTranslation); cluster->transform(inverseRotations); } /** Creates a random vector * * @param range range of components, i.e. \f$ v[i] \in [0,range)\f$ * @param offset offset for each component * @return \a range * rnd() + \a offset */ Vector RandomInserter::getRandomVector(const double range, const double offset) const { Vector returnVector; for (size_t i=0; igetAtoms(); Vector center; center.Zero(); for(AtomIdSet::iterator miter = atoms.begin();miter != atoms.end(); ++miter) center += (*miter)->getPosition(); center *= 1./atoms.size(); // shift cluster to center cluster->translate(zeroVec-center); size_t attempt = 0; for (;attempt < Max_Attempts; ++attempt) { // generate random rotation matrix RealSpaceMatrix Rotations; if (DoRandomRotation) setRandomRotation(Rotations); else Rotations.setIdentity(); // generate random molecule translation vector Vector RandomMoleculeTranslation(getRandomVector(MaxMoleculeComponent, -MaxMoleculeComponent)); // generate random atom translation vector std::vector RandomAtomTranslations(atoms.size(), zeroVec); std::generate_n(RandomAtomTranslations.begin(), atoms.size(), boost::bind(&RandomInserter::getRandomVector, boost::cref(this), MaxAtomComponent, -MaxAtomComponent)); // apply! // LOG(2, "DEBUG: cluster before doTranslation(): " << *cluster << "."); doTranslation(cluster, Rotations, RandomAtomTranslations, RandomMoleculeTranslation); // LOG(2, "DEBUG: cluster after doTranslation(): " << *cluster << "."); // ... and check if (!AreClustersAtomsInside(cluster)) { undoTranslation(cluster, Rotations, RandomAtomTranslations, RandomMoleculeTranslation); // LOG(2, "DEBUG: cluster after undoTranslation(): " << *cluster << "."); } else { break; } } // and move to final position cluster->translate(offset+center); return attempt != Max_Attempts; }