/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2010-2012 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 .
*/
/*
* Box.cpp
*
* Created on: Jun 30, 2010
* Author: crueger
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include "CodePatterns/MemDebug.hpp"
#include "Box.hpp"
#include
#include
#include
#include
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
#include "CodePatterns/Observer/Channels.hpp"
#include "CodePatterns/Observer/Notification.hpp"
#include "CodePatterns/Verbose.hpp"
#include "Helpers/defs.hpp"
#include "LinearAlgebra/RealSpaceMatrix.hpp"
#include "LinearAlgebra/Vector.hpp"
#include "LinearAlgebra/Plane.hpp"
#include "Shapes/BaseShapes.hpp"
#include "Shapes/ShapeOps.hpp"
Box::Box() :
Observable("Box"),
M(new RealSpaceMatrix()),
Minv(new RealSpaceMatrix())
{
internal_list.reserve(pow(3,3));
coords.reserve(NDIM);
index.reserve(NDIM);
// observable stuff
Channels *OurChannel = new Channels;
Observable::insertNotificationChannel( std::make_pair(static_cast(this), OurChannel) );
// add instance for each notification type
for (size_t type = 0; type < NotificationType_MAX; ++type)
OurChannel->addChannel(type);
M->setIdentity();
Minv->setIdentity();
}
Box::Box(const Box& src) :
Observable("Box"),
conditions(src.conditions),
M(new RealSpaceMatrix(*src.M)),
Minv(new RealSpaceMatrix(*src.Minv))
{
internal_list.reserve(pow(3,3));
coords.reserve(NDIM);
index.reserve(NDIM);
// observable stuff
Channels *OurChannel = new Channels;
Observable::insertNotificationChannel( std::make_pair(static_cast(this), OurChannel) );
// add instance for each notification type
for (size_t type = 0; type < NotificationType_MAX; ++type)
OurChannel->addChannel(type);
}
Box::Box(RealSpaceMatrix _M) :
Observable("Box"),
M(new RealSpaceMatrix(_M)),
Minv(new RealSpaceMatrix())
{
internal_list.reserve(pow(3,3));
coords.reserve(NDIM);
index.reserve(NDIM);
// observable stuff
Channels *OurChannel = new Channels;
Observable::insertNotificationChannel( std::make_pair(static_cast(this), OurChannel) );
// add instance for each notification type
for (size_t type = 0; type < NotificationType_MAX; ++type)
OurChannel->addChannel(type);
ASSERT(M->determinant()!=0,"Matrix in Box construction was not invertible");
*Minv = M->invert();
}
Box::~Box()
{
delete M;
delete Minv;
}
const RealSpaceMatrix &Box::getM() const{
return *M;
}
const RealSpaceMatrix &Box::getMinv() const{
return *Minv;
}
void Box::setM(const RealSpaceMatrix &_M){
ASSERT(_M.determinant()!=0,"Matrix in Box construction was not invertible");
OBSERVE;
if (_M != *M)
NOTIFY(MatrixChanged);
*M =_M;
*Minv = M->invert();
}
Vector Box::translateIn(const Vector &point) const{
return (*M) * point;
}
Vector Box::translateOut(const Vector &point) const{
return (*Minv) * point;
}
Vector Box::enforceBoundaryConditions(const Vector &point) const{
Vector helper = translateOut(point);
for(int i=NDIM;i--;){
switch(conditions[i]){
case BoundaryConditions::Wrap:
helper.at(i)=fmod(helper.at(i),1);
helper.at(i)+=(helper.at(i)>=0)?0:1;
break;
case BoundaryConditions::Bounce:
{
// there probably is a better way to handle this...
// all the fabs and fmod modf probably makes it very slow
double intpart,fracpart;
fracpart = modf(fabs(helper.at(i)),&intpart);
helper.at(i) = fabs(fracpart-fmod(intpart,2));
}
break;
case BoundaryConditions::Ignore:
break;
default:
ASSERT(0,"No default case for this");
break;
}
}
return translateIn(helper);
}
bool Box::isInside(const Vector &point) const
{
bool result = true;
Vector tester = translateOut(point);
for(int i=0;i= -MYEPSILON) &&
((tester[i] - 1.) < MYEPSILON)));
return result;
}
bool Box::isValid(const Vector &point) const
{
bool result = true;
Vector tester = translateOut(point);
for(int i=0;i= -MYEPSILON) &&
((tester[i] - 1.) < MYEPSILON)));
return result;
}
VECTORSET(std::vector) Box::explode(const Vector &point,int n) const{
ASSERT(isInside(point),"Exploded point not inside Box");
internal_explode(point, n);
VECTORSET(std::vector) res(internal_list);
return res;
}
void Box::internal_explode(const Vector &point,int n) const{
// internal_list.clear();
size_t list_index = 0;
Vector translater = translateOut(point);
Vector mask; // contains the ignored coordinates
// count the number of coordinates we need to do
int dims = 0; // number of dimensions that are not ignored
coords.clear();
index.clear();
for(int i=0;i x
// 1 -> 2-x
// 2 -> 2+x
// 3 -> 4-x
// 4 -> 4+x
// the first number is the next bigger even number (n+n%2)
// the next number is the value with alternating sign (x-2*(n%2)*x)
// the negative numbers produce the same sequence reversed and shifted
int n = abs(index[i]) + ((index[i]<0)?-1:0);
int sign = (index[i]<0)?-1:+1;
int even = n%2;
helper[coords[i]]=n+even+translater[coords[i]]-2*even*translater[coords[i]];
helper[coords[i]]*=sign;
}
break;
case BoundaryConditions::Ignore:
ASSERT(0,"Ignored coordinate handled in generation loop");
break;
default:
ASSERT(0,"No default case for this switch-case");
break;
}
}
// add back all ignored coordinates (not handled in above loop)
helper+=mask;
ASSERT(list_index < internal_list.size(),
"Box::internal_explode() - we have estimated the number of vectors wrong: "
+toString(list_index) +" >= "+toString(internal_list.size())+".");
internal_list[list_index++] = translateIn(helper);
// set the new indexes
int pos=0;
++index[pos];
while(index[pos]>n){
index[pos++]=-n;
if(pos>=dims) { // it's trying to increase one beyond array... all vectors generated
done = true;
break;
}
++index[pos];
}
}
}
VECTORSET(std::vector) Box::explode(const Vector &point) const{
ASSERT(isInside(point),"Exploded point not inside Box");
return explode(point,1);
}
const Vector Box::periodicDistanceVector(const Vector &point1,const Vector &point2) const{
Vector helper1(enforceBoundaryConditions(point1));
Vector helper2(enforceBoundaryConditions(point2));
internal_explode(helper1,1);
const Vector res = internal_list.minDistance(helper2);
return res;
}
double Box::periodicDistanceSquared(const Vector &point1,const Vector &point2) const{
const Vector res = periodicDistanceVector(point1, point2);
return res.NormSquared();
}
double Box::periodicDistance(const Vector &point1,const Vector &point2) const{
double res = sqrt(periodicDistanceSquared(point1,point2));
return res;
}
double Box::DistanceToBoundary(const Vector &point) const
{
std::map DistanceSet;
std::vector > Boundaries = getBoundingPlanes();
for (int i=0;ifirst;
}
Shape Box::getShape() const{
return transform(Cuboid(Vector(0,0,0),Vector(1,1,1)),(*M));
}
const std::string Box::getConditionNames() const
{
std::stringstream outputstream;
outputstream << conditions;
return outputstream.str();
}
const BoundaryConditions::Conditions_t & Box::getConditions() const
{
return conditions.get();
}
const BoundaryConditions::BoundaryCondition_t Box::getCondition(size_t i) const
{
return conditions.get(i);
}
void Box::setCondition(size_t i, const BoundaryConditions::BoundaryCondition_t _condition)
{
OBSERVE;
if (conditions.get(i) != _condition)
NOTIFY(BoundaryConditionsChanged);
conditions.set(i, _condition);
}
void Box::setConditions(const BoundaryConditions::Conditions_t & _conditions)
{
OBSERVE;
if (conditions.get() != _conditions)
NOTIFY(BoundaryConditionsChanged);
conditions.set(_conditions);
}
void Box::setConditions(const std::string & _conditions)
{
OBSERVE;
NOTIFY(BoundaryConditionsChanged);
std::stringstream inputstream(_conditions);
inputstream >> conditions;
}
void Box::setConditions(const std::vector< std::string >& _conditions)
{
OBSERVE;
NOTIFY(BoundaryConditionsChanged);
conditions.set(_conditions);
}
const std::vector > Box::getBoundingPlanes() const
{
std::vector > res;
for(int i=0;i0 && endpoint[1]>0 && endpoint[2]>0,"Vector does not define a full cuboid");
M->setIdentity();
M->diagonal()=endpoint;
Vector &dinv = Minv->diagonal();
for(int i=NDIM;i--;)
dinv[i]=1/endpoint[i];
}
Box &Box::operator=(const Box &src)
{
if(&src!=this){
OBSERVE;
// new matrix
NOTIFY(MatrixChanged);
delete M;
delete Minv;
M = new RealSpaceMatrix(*src.M);
Minv = new RealSpaceMatrix(*src.Minv);
// new boundary conditions
NOTIFY(BoundaryConditionsChanged);
conditions = src.conditions;
}
return *this;
}
Box &Box::operator=(const RealSpaceMatrix &mat)
{
OBSERVE;
NOTIFY(MatrixChanged);
setM(mat);
return *this;
}
std::ostream & operator << (std::ostream& ost, const Box &m)
{
ost << m.getM();
return ost;
}