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