I work with molecular simulations. In a normal infinate space
simulation, a particle can occupy any cartesian position in space.
If i want the distance between two particles in a system I can use:
Maths::dvector va, vb;
// Code here: Do something to initialise variables and move them around...
double distance = dist(va,vb);
I am currently looking at 'Periodic boundary simulations'. By this i
mean, I am simulating particles in a box, and when a particle goes off
one edge of the box, it comes back on the other side... Easy stuff -
very usesful in molecular dynamics.
<see example code below>
As dist(Maths::dvector& va, Maths::dvector& vb) is an inline function,
it has overall good performance. However if i want to now have a
'generalised' simulation class, my OOP experience tells me that I should
have a 'Space' class that manages calls like 'dist' for any arbritary
derived space system. Thus (via virtual calls) when I call getDistance()
in 'InfiniteSpace' I just call dist(), but when I call it in
'PeriodicRectangular' it takes the 'periodic cube' into account.
My problem is therefore one of performance. When I have a pointer to an
instance of a class that derives from 'Space', the compiler can't inline
the code when getDistance() is called, so performance sux. This goes
away if you make specialised classes, but that defeats the whole point
of inheritance and being generalised.
So my question is, is there a way of giving my simulation a Template
Meta Argument e.g. Simulation<Space sto avoid the need to have
'virtual' all over the place. I have scratched my head and cant really
think of the best way to do this...
Any Ideas Guys??
Many Thanks For Any Comments,
Jon Rea
-------------
Example Code:
-------------
class Space {
public:
Space(){};
virtual ~Space(){};
inline virtual double getDistance(
const Maths::dvector &va,
const Maths::dvector &vb
) const = 0;
}
class InfiniteSpace: public Space {
public:
InfiniteSpace(){};
virtual ~InfiniteSpace(){};
inline virtual double getDistance(
const Maths::dvector &va,
const Maths::dvector &vb
) const
{
return dist(va,vb);
}
}
class PeriodicRectangular: public Space {
public:
PeriodicRectangular(double allsize):
boxSize(allsize,allsize,allsize),
halfBoxSize(boxSize);
virtual ~PeriodicRectangular(){};
inline void getVector(
const Maths::dvector &va,
const Maths::dvector &vb,
Maths::dvector &vavb
) const
{
vavb.diff(vb,va);
if(vavb.innerdot() < sqrSaveDistance) return;
// find closest image of vb.x;
if(vavb.x halfBoxSize.x) vavb.x -= boxSize.x;
if(vavb.x < -halfBoxSize.x) vavb.x += boxSize.x;
// find closest image of vb.y;
if(vavb.y halfBoxSize.y) vavb.y -= boxSize.y;
if(vavb.y < -halfBoxSize.y) vavb.y += boxSize.y;
// find closest image of vb.z;
if(vavb.z halfBoxSize.z) vavb.z -= boxSize.z;
if(vavb.z < -halfBoxSize.z) vavb.z += boxSize.z;
}
inline virtual double getDistance(
const Maths::dvector &va,
const Maths::dvector &vb
{
Maths::dvector vavb;
getVector(va,vb,vavb);
return vavb.mag();
}
)
Simulate( Space* mySpace )
{
// Do some simulating ...
for( int i = 0; i < xxx; i++ )
mySpace->getDistance( blaA, blaB );
}