package sim.physics2D.integrator;
import sim.physics2D.*;
import sim.physics2D.constraint.ConstraintEngine;
import sim.physics2D.forceGenerator.ForceEngine;
/** Implements a Runge-Kutta ordinary differential equation solver. The runge-kutta solver
* reduces errors over the euler integrator by adding terms in the taylor series expansion.
*/
public class ODERungeKuttaSolver implements ODESolver
{
private ConstraintEngine objCE;
private ForceEngine objFE;
private PhysicsState physicsState;
public ODERungeKuttaSolver()
{
physicsState = PhysicsState.getInstance();
this.objCE = ConstraintEngine.getInstance();
this.objFE = ForceEngine.getInstance();
}
private sim.util.matrix.Vector ODEFunction(sim.util.matrix.Vector state)
{
int stateRowDimension = state.m;
int halfStateRowDimension = stateRowDimension / 2;
// Update the physics engine so it thinks this is the current state
physicsState.setStateVector(state);
objFE.addForces();
sim.util.matrix.Vector externalForcesVector = physicsState.getExternalForcesVector();
sim.util.matrix.Vector totalForces;
// this is for resting contact
/*
if (physicsState.lcp.contacts.numObjs == 0)
{
matrix.Vector constraintForces = objPE.calculateConstraintForces(externalForcesMatrix);
matrix.Vector constraintForces = objPE.calculateConstraintForces(externalForcesVector);
// Solve for total forces and accelerations
totalForces = constraintForces.plus(externalForcesVector);
}
else
totalForces = externalForcesVector;
*/
sim.util.matrix.Vector constraintForces = objCE.calculateConstraintForces(externalForcesVector);
totalForces = constraintForces.plus(externalForcesVector);
sim.util.matrix.Vector acc = physicsState.getMassInverseMatrix().times(totalForces);
// Set the first half of the stateDot matrix to velocity
// (second half of state matrix) and the second half of the
// stateDot matrix to the accelerations just calculated
sim.util.matrix.Vector stateDot = new sim.util.matrix.Vector(stateRowDimension);
for (int i = 0; i < halfStateRowDimension; i++)
{
stateDot.vals[i] = state.vals[i + halfStateRowDimension];
stateDot.vals[i + halfStateRowDimension] = acc.vals[i];
}
return stateDot;
}
public void solve(double stepSize)
{
// Make a copy of the state at the start of the current step
sim.util.matrix.Vector stepState = physicsState.getStateVectorCopy();
sim.util.matrix.Vector f1 = ODEFunction(stepState).times(stepSize);
sim.util.matrix.Vector f2 = ODEFunction(stepState.plus(f1.times(0.5))).times(stepSize);
sim.util.matrix.Vector f3 = ODEFunction(stepState.plus(f2.times(0.5))).times(stepSize);
sim.util.matrix.Vector f4 = ODEFunction(stepState.plus(f3)).times(stepSize);
// Update the step to be the new state at the end of this step
physicsState.setStateVector(stepState.plus(f1.plus(f2.times(2)).plus(f3.times(2)).plus(f4).times((double)1/6)));
}
}