/* * 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 . */ /* * Cluster.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 "Cluster.hpp" #include "CodePatterns/Assert.hpp" #include "CodePatterns/Log.hpp" #include "Atom/atom.hpp" #include "Descriptors/AtomIdDescriptor.hpp" #include "LinearAlgebra/RealSpaceMatrix.hpp" #include "LinearAlgebra/Vector.hpp" #include "Shapes/ShapeOps.hpp" #include "World.hpp" /** Constructor for class Cluster. * * @param _s Shape of this Cluster */ Cluster::Cluster(const Shape & _s) : s(_s) {} /** Copy Constructor for class Cluster. * * Here, we do not check whether we atomds reside in the Shape or not, as * this should have been validated in the instance to copy \a _cluster. * * @param _cluster instance to copy */ Cluster::Cluster(const Cluster & _cluster) : atoms(_cluster.atoms), s(_cluster.s) {} /** Constructor for class Cluster. * * @param _atoms list of atoms to place in this cluster * @param _s Shape of this Cluster */ Cluster::Cluster(const atomIdSet & _atoms, const Shape & _s) : s(_s) { // make sure only those atoms are in Cluster that are also inside its Shape std::vector tempIds(_atoms.size(), (size_t)-1); std::vector::iterator iter = std::remove_copy_if( _atoms.begin(), _atoms.end(), tempIds.begin(), !boost::bind(&Cluster::IsInShape, this, _1) ); tempIds.erase( iter, tempIds.end() ); ASSERT( tempIds.size() == _atoms.size(), "Cluster::Cluster() - at least one atom is not inside the Shape."); atoms.insert( tempIds.begin(), tempIds.end() ); LOG(1, "INFO: New cluster has " << atoms.size() << " atoms."); } /** Destructor for class Cluster. * */ Cluster::~Cluster() {} /** Inserts an atomic by its \a id into the Cluster. * * We check whether the atom is inside the given Shape \a s. * * @param id id to insert */ void Cluster::insert(const atomId_t id) { const bool status = IsInShape(id); ASSERT(status, "Cluster::insert() - atomic id "+toString(id)+" is not contained in Shape."); if (status) { #ifndef NDEBUG std::pair inserter = #endif atoms.insert(id); ASSERT(inserter.second, "Cluster::insert() - atomic id "+toString(id)+" is already present."); } } /** Remove atom by its \a id from the cluster. * * @param id atom to remove */ void Cluster::erase(const atomId_t id) { atomIdSet::iterator iter = atoms.find(id); ASSERT(iter != atoms.end(), "Cluster::erase() - atomic id "+toString(id)+" unknown in this Cluster."); if (iter != atoms.end()) atoms.erase(iter); } /** Checks whether a given atom is within the shape \a s. * * @param id atomic id to check * @return true - is in Shape, false - is not contained (or does not exist) */ bool Cluster::IsInShape(const atomId_t id) const { const atom * const _atom = getAtomById(id); if (_atom != NULL) return s.isInside(_atom->getPosition()); else return false; } /** Helper function for looking up atomic reference by its id. * * @param id id to look up * @return reference to atom with this id */ atom * const Cluster::getAtomById(const atomId_t id) const { atom * const _atom = World::getInstance().getAtom(AtomById(id)); ASSERT(_atom != NULL, "Cluster::getAtomById() - id "+toString(id)+" is unknown to World."); return _atom; } bool isNullAtom(const atom* _atom) { return _atom == NULL; } /** Getter for the underlying true atoms refs. * * @return AtomVector filled with looked-up atom references */ Cluster::AtomVector Cluster::getAtomRefs() const { AtomVector atomVector; atomVector.reserve(atoms.size()); BOOST_FOREACH(atomId_t _id, atoms) { atom * const _atom = World::getInstance().getAtom(AtomById(_id)); if (_atom != NULL) atomVector.push_back( _atom ); else ASSERT( false, "Cluster::getAtomRefs() - unknown id "+toString(_id)+"."); } return atomVector; } /** Clone function for this instance. * * @param copyMethod functor that knows how to copy atoms * @param offset Vector to translate new cluster relative to old one * @return another instance with newly allocated atoms */ ClusterInterface::Cluster_impl Cluster::clone( CopyAtomsInterface& copyMethod, const Vector &offset) const { LOG(2, "INFO: Clone this cluster with " << atoms.size() << " atoms."); /// get another cluster instance Cluster * clonedInstance = new Cluster(::translate(getShape(), offset)); /// copy and move atoms copyMethod(getAtomRefs()); AtomVector CopiedAtoms = copyMethod.getCopiedAtoms(); BOOST_FOREACH( atom *_atom, CopiedAtoms) { _atom->setPosition( _atom->getPosition() + offset ); } /// fill copied atoms into new instance // dont use a set here, makes life hard with STL algos std::vector Copies(CopiedAtoms.size(), (size_t)-1); std::transform(CopiedAtoms.begin(), CopiedAtoms.end(), Copies.begin(), boost::bind(&atom::getId, _1) ); clonedInstance->atoms.insert(Copies.begin(), Copies.end()); return ClusterInterface::Cluster_impl(clonedInstance); } /** Translate atoms inside Cluster and Shape. * * @param offset offset to translate by */ void Cluster::translate(const Vector &offset) { // move atoms AtomVector atomVector = getAtomRefs(); BOOST_FOREACH(atom *_atom, atomVector) { _atom->setPosition(_atom->getPosition()+offset); } // translate shape s = ::translate(s, offset); } /** Transform atoms inside Cluster and Shape. * * @param M transformation matrix */ void Cluster::transform(const RealSpaceMatrix &M) { // transform atoms AtomVector atomVector = getAtomRefs(); BOOST_FOREACH(atom *_atom, atomVector) { _atom->setPosition( M * _atom->getPosition() ); } // translate shape s = ::transform(s, M); }