/*
   Project: Adun

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   This application 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.

   This application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
/** \file **/
#ifndef SIMULATOR_INTERFACE
#define SIMULATOR_INTERFACE

#include <stdio.h>
#include "AdunKernel/AdUpdating.h"
#include "AdunKernel/AdunObject.h"
#include "AdunKernel/AdunTimer.h"
#include "AdunKernel/AdunForceFieldManager.h"
#include "AdunKernel/AdunDefinitions.h"
#include "AdunKernel/AdunSystemNode.h"

/*!
\ingroup Inter
The AdSimulator class is the base class from which all simulators in Adun inherit. 
It handles integration of the coordinates and velocities of a collection of subsystems represented
by an AdSystemNode object using the forces acting on those subsystems as 
calculated by an AdForceFieldManager object.

The integration is performed by calling the production method. The number of integration
steps that the AdSimulator::production method performs is determined by the value of AdSimulator::numberOfSteps.
At the completion of each step the simulator sends an update message to the AdSystemNode
allowing it to update each subsystems state to reflect the changes due to the integration
(current time, kinetic energy etc).

AdSimulator includes an AdTimer object which it updates every step. Other objects can
access the timer and add messages to it in order for them to perform necessary operations 
at defined intervals during the simulation procedure.

AdSimulator monitors the numerical stability of the simulation by checking for IEEE
floating point errors. 

Note: AdSimulator only performs the intergration on the \e active subsystems of the AdSystemNode.
All simulators register for AdSystemStatusDidChangeNotification from the AdSystemNode allowing
them to immediatly adapt to a change in system state.

Subclassing Notes:

<e> To follow </e>

\todo Factor out the thermostating methods to their own class
\todo init methods should accept AdForceFieldManager and AdSystemNode as arguements.
\todo Check that force field is using same system
*/

@interface AdSimulator: AdObject <AdAbstractFactory>
{
	BOOL endSimulation;
	int no_of_steps;		//!< The number of steps to be taken
	int currentStep;		//!< The current step
	double target_temperature; 	//!< The target temperature
	int checkFPErrorInterval;	//!< Interval at which to check for floating point errors
	double time_step;		//!< The time step
	double timefac;			//!< Half the time step
	double timefac_sq;		//!< timefac squared
	AdSystemNode* system;
	AdForceFieldManager* forceField;
	AdTimer* timer;			//!< Scheduler that is incremented every simulation loop
	NSAutoreleasePool* pool;	//!< An autorelease pool for the simulation loops
	NSArray* subsystems;
}

/**
Performs a number of intergration steps on the active subsystems
in \e system.
*/
- (void) production;
/**
Ends the running simulation i.e. causes AdSimulator::production to exit.
*/
- (void) endSimulation;
/*
Checks for floating point errors by
examining the floating point status word for raised exceptions.
On detecting FE_INVALID, FE_OVERFLOW or FE_DIVBYZERO this method
raises an exception. Otherwise it does nothing.
\note This behaviour may change
*/
- (void) checkFloatingPointErrors;
/**
Temporary method necessary while AdTimer still retains
strong references to the objects it sends messages to. If the message
is not called it is impossible for any AdSimulator instance to
be deallocated
*/
- (void) clearTimer;

/**
Sets the system to be simulated to \object.
The simulator observes AdSystemStatusDidChangeNotification's from the systems
it is simulating.
\param object An AdSystemNode instance. 
*/
- (void) setSystem: (AdSystemNode*) object;
/**
Sets the force field to use for calculating the accelerations.
\param object An AdForceFieldManager instance working on the same
AdSystemNode instance as the simulator (as set using AdSimulator::setSystem: above).
*/
- (void) setForceField: (AdForceFieldManager*) object;
/**
Returns the time step used for the integration in femtoseconds
*/
- (double) timeStep;
/**
The currentStep (out of AdSimulator::numberOfSteps) that the AdSimulator::production method just
performed.
*/
- (int) currentStep;
/**
Returns the number of integration steps performed when AdSimulator::production is called
*/
- (int) numberOfSteps;
/**
Returns the AdTimer instance that sits in the integration loop.
You can add messages to this timer to be sent at designated intervals
while the production loop is running.
*/
- (AdTimer*) timer;
/**
Returns the system the simulator is currently working on
*/
- (AdSystemNode*) system;
/**
Returns the force field manager the simulator is currently using
*/
- (AdForceFieldManager*) forceField;
/**
Returns the target temperature for the simulation in Kelvin.
(may not be appicable to all subclasses - Hence may be removed
to only those where it is required i.e. required for LangevinSimulator
while NewtonianSimulator could use a variety of thermostat objects and
need no reference to the temperature itself.
*/
- (double) targetTemperature;
/**
Sets the target temperature to \e aValue
*/
- (void) setTargetTemperature: (double) aValue;
/**
Sets the time step to be used for the integration. Value must
be in femtoseconds.
*/
- (void) setTimeStep: (double) stepSize;
/**
Method called when AdSystemNode posts a AdSystemStatusDidChangeNotification
*/
- (void) handleChangeInSystemStatus: (NSNotification*) aNotification;
@end

#endif
