void TimestepSchemeARS222::Step(
	bool fFirstStep,
	bool fLastStep,
	const Time & time,
	double dDeltaT
) {
	// Get a copy of the grid
	Grid * pGrid = m_model.GetGrid();

	// Get a copy of the HorizontalDynamics
	HorizontalDynamics * pHorizontalDynamics = m_model.GetHorizontalDynamics();

	// Get a copy of the VerticalDynamics
	VerticalDynamics * pVerticalDynamics = m_model.GetVerticalDynamics();

	// u2 explicit evaluation combination
	m_du2fCombo[0] = 1.0 - m_dExpCf[1][0] / m_dExpCf[0][0];
	m_du2fCombo[1] = m_dExpCf[1][0] / m_dExpCf[0][0] - 
					 m_dImpCf[1][0] / m_dImpCf[0][0];
	m_du2fCombo[2] = m_dImpCf[1][0] / m_dImpCf[0][0];
	m_du2fCombo[3] = 0.0;

	//std::cout << "Entering substages at the timestep... \n";

	// STAGE 1
	// Compute uf1 into index 1
	pGrid->CopyData(0, 1, DataType_State);
	pGrid->CopyData(0, 1, DataType_Tracers);
	pHorizontalDynamics->StepExplicit(
		0, 1, time, m_dExpCf[0][0] * dDeltaT);
	pVerticalDynamics->StepExplicit(
		0, 1, time, m_dExpCf[0][0] * dDeltaT);
	pGrid->PostProcessSubstage(1, DataType_State);
	pGrid->PostProcessSubstage(1, DataType_Tracers);

	// Compute u1 into index 2
	pGrid->CopyData(1, 2, DataType_State);
	pGrid->CopyData(1, 2, DataType_State);
	pVerticalDynamics->StepImplicit(
		2, 2, time, m_dImpCf[0][0] * dDeltaT);
	pGrid->PostProcessSubstage(2, DataType_State);
	pGrid->PostProcessSubstage(2, DataType_Tracers);

	// STAGE 2
	// Compute uf2 from u1 (index 2) into index 3
	pGrid->LinearCombineData(m_du2fCombo, 3, DataType_State);
	pGrid->LinearCombineData(m_du2fCombo, 3, DataType_Tracers);
	pHorizontalDynamics->StepExplicit(
		2, 3, time, m_dExpCf[1][1] * dDeltaT);
	pVerticalDynamics->StepExplicit(
		2, 3, time, m_dExpCf[1][1] * dDeltaT);
	pGrid->PostProcessSubstage(3, DataType_State);
	pGrid->PostProcessSubstage(3, DataType_Tracers);

	// Compute u2 from uf2 (index 3) into index 2
	pVerticalDynamics->StepImplicit(
		3, 3, time, m_dImpCf[1][1] * dDeltaT);
	pGrid->PostProcessSubstage(3, DataType_State);
	pGrid->PostProcessSubstage(3, DataType_Tracers);

	// Apply hyperdiffusion at the end of the explicit substep (ask Paul)
	pGrid->CopyData(3, 2, DataType_State);
	pGrid->CopyData(3, 2, DataType_Tracers);
	pHorizontalDynamics->StepAfterSubCycle(2, 1, 3, time, dDeltaT);
	pGrid->CopyData(1, 0, DataType_State);
	pGrid->CopyData(1, 0, DataType_Tracers);
}
void TimestepSchemeSSP3332::Step(
	bool fFirstStep,
	bool fLastStep,
	const Time & time,
	double dDeltaT
) {
	// Get a copy of the grid
	Grid * pGrid = m_model.GetGrid();

	// Get a copy of the HorizontalDynamics
	HorizontalDynamics * pHorizontalDynamics = m_model.GetHorizontalDynamics();

	// Get a copy of the VerticalDynamics
	VerticalDynamics * pVerticalDynamics = m_model.GetVerticalDynamics();

	// u2 explicit evaluation combination
	m_du2fCombo[0] = 1.0 - m_dImpCf[1][0] / m_dImpCf[0][0];
	m_du2fCombo[1] = 0.0;
	m_du2fCombo[2] = m_dImpCf[1][0] / m_dImpCf[0][0];
	m_du2fCombo[3] = 0.0;
	m_du2fCombo[4] = 0.0;
	m_du2fCombo[5] = 0.0;
	m_du2fCombo[6] = 0.0;
	m_du2fCombo[7] = 0.0;

	// u3 explicit evaluation combination
	m_du3fCombo[0] = 1.0 + m_dImpCf[1][0] / m_dImpCf[0][0] *
						   m_dExpCf[2][0] / m_dExpCf[1][0] -
						   m_dExpCf[2][0] / m_dExpCf[1][0] -
						   m_dImpCf[2][0] / m_dImpCf[0][0];
	m_du3fCombo[1] = 0.0;
	m_du3fCombo[2] = m_dImpCf[2][0] / m_dImpCf[0][0] - 
					 m_dImpCf[1][0] / m_dImpCf[0][0] *
					 m_dExpCf[2][0] / m_dExpCf[1][0];
	m_du3fCombo[3] = m_dExpCf[2][0] / m_dExpCf[1][0];
	m_du3fCombo[4] = 0.0;
	m_du3fCombo[5] = 0.0;
	m_du3fCombo[6] = 0.0;
	m_du3fCombo[7] = 0.0;
	m_du3fCombo[8] = 0.0;
	
	// u4 explicit evaluation combination
	m_du4fCombo[0] = 1.0 - m_dExpCf[3][0] / m_dImpCf[0][0];
	m_du4fCombo[1] = 0.0;
	m_du4fCombo[2] = m_dImpCf[3][0] / m_dImpCf[0][0];
	m_du4fCombo[3] = m_dExpCf[3][0] / m_dExpCf[1][0] - 
					 m_dImpCf[3][1] / m_dImpCf[1][1];
	m_du4fCombo[4] = m_dImpCf[3][1] / m_dImpCf[1][1];
	m_du4fCombo[5] = m_dExpCf[3][1] / m_dExpCf[2][1] - 
					 m_dImpCf[3][2] / m_dImpCf[2][2];
	m_du4fCombo[6] = m_dImpCf[3][2] / m_dImpCf[2][2];
	m_du4fCombo[7] = -m_dExpCf[3][0] / m_dExpCf[1][0];
	m_du4fCombo[8] = -m_dExpCf[3][1] / m_dExpCf[2][1];

	// STAGE 1
	// Compute u1 into index 2
	pGrid->CopyData(0, 2, DataType_State);
	pGrid->CopyData(0, 2, DataType_State);
	pVerticalDynamics->StepImplicit(
		2, 2, time, m_dImpCf[0][0] * dDeltaT);
	pGrid->PostProcessSubstage(2, DataType_State);
	pGrid->PostProcessSubstage(2, DataType_Tracers);

	// STAGE 2
	// Compute uf1 from u0 (index 2) into index 7
	pGrid->LinearCombineData(m_du2fCombo, 7, DataType_State);
	pGrid->LinearCombineData(m_du2fCombo, 7, DataType_Tracers);
	pGrid->CopyData(7, 3, DataType_State);
	pGrid->CopyData(7, 3, DataType_Tracers);

	pHorizontalDynamics->StepExplicit(
		2, 3, time, m_dExpCf[1][0] * dDeltaT);
	pVerticalDynamics->StepExplicit(
		2, 3, time, m_dExpCf[1][0] * dDeltaT);
	pGrid->PostProcessSubstage(3, DataType_State);
	pGrid->PostProcessSubstage(3, DataType_Tracers);

	// Compute u2 from uf2 (index 3) into index 4
	pGrid->CopyData(3, 4, DataType_State);
	pGrid->CopyData(3, 4, DataType_State);
	pVerticalDynamics->StepImplicit(
		4, 4, time, m_dImpCf[1][1] * dDeltaT);
	pGrid->PostProcessSubstage(4, DataType_State);
	pGrid->PostProcessSubstage(4, DataType_Tracers);

	// STAGE 3
	// Compute uf3 from u2 (index 4) into index 8
	pGrid->LinearCombineData(m_du3fCombo, 8, DataType_State);
	pGrid->LinearCombineData(m_du3fCombo, 8, DataType_Tracers);
	pGrid->CopyData(8, 5, DataType_State);
	pGrid->CopyData(8, 5, DataType_Tracers);
	pHorizontalDynamics->StepExplicit(
		4, 5, time, m_dExpCf[2][1] * dDeltaT);
	pVerticalDynamics->StepExplicit(
		4, 5, time, m_dExpCf[2][1] * dDeltaT);
	pGrid->PostProcessSubstage(5, DataType_State);
	pGrid->PostProcessSubstage(5, DataType_Tracers);

	// Compute u3 from uf3 (index 3) into index 6
	pGrid->CopyData(5, 6, DataType_State);
	pGrid->CopyData(5, 6, DataType_State);
	pVerticalDynamics->StepImplicit(
		6, 6, time, m_dImpCf[2][2] * dDeltaT);
	pGrid->PostProcessSubstage(6, DataType_State);
	pGrid->PostProcessSubstage(6, DataType_Tracers);

	// STAGE 4
	// Compute uf4 from u3 (index 6) into index 9
	pGrid->LinearCombineData(m_du4fCombo, 1, DataType_State);
	pGrid->LinearCombineData(m_du4fCombo, 1, DataType_Tracers);
	pHorizontalDynamics->StepExplicit(
		6, 1, time, m_dExpCf[3][2] * dDeltaT);
	pVerticalDynamics->StepExplicit(
		6, 1, time, m_dExpCf[3][2] * dDeltaT);
	pGrid->PostProcessSubstage(1, DataType_State);
	pGrid->PostProcessSubstage(1, DataType_Tracers);

	// NO IMPLICIT STEP ON THE LAST STAGE

	// Apply hyperdiffusion at the end of the explicit substep (ask Paul)
	pGrid->CopyData(1, 2, DataType_State);
	pGrid->CopyData(1, 2, DataType_Tracers);
	pHorizontalDynamics->StepAfterSubCycle(2, 1, 3, time, dDeltaT);
	pGrid->CopyData(1, 0, DataType_State);
	pGrid->CopyData(1, 0, DataType_Tracers);
}
void TimestepSchemeARK4::Step(
	bool fFirstStep,
	bool fLastStep,
	const Time & time,
	double dDeltaT
) {
	// Get a copy of the grid
	Grid * pGrid = m_model.GetGrid();

	// Get a copy of the HorizontalDynamics
	HorizontalDynamics * pHorizontalDynamics = m_model.GetHorizontalDynamics();

	// Get a copy of the VerticalDynamics
	VerticalDynamics * pVerticalDynamics = m_model.GetVerticalDynamics();
	
	// K0 combination
	m_dK0Combo[0] = -1.0 / (dDeltaT * m_dImpCf[0][0]);;
    m_dK0Combo[1] = 1.0 / (dDeltaT * m_dImpCf[0][0]);;
    m_dK0Combo[2] = 0.0;
	m_dK0Combo[3] = 0.0;

	// u1 implicit evaluation combination
    m_du1fCombo[0] = 1.0;
    m_du1fCombo[1] = 0.0;
    m_du1fCombo[2] = 0.0;
    m_du1fCombo[3] = dDeltaT * m_dImpCf[1][0];

    // Kh1 combination
    m_dKh1Combo[0] = -1.0 / (dDeltaT * m_dExpCf[1][0]);
    m_dKh1Combo[1] = 1.0 / (dDeltaT * m_dExpCf[1][0]);
	m_dKh1Combo[2] = 0.0;
	m_dKh1Combo[3] = -m_dImpCf[0][0] / m_dExpCf[1][0];
	m_dKh1Combo[4] = 0.0;

    // K1 combination
    m_dK1Combo[0] = -1.0 / (dDeltaT * m_dImpCf[1][1]);
    m_dK1Combo[1] = 0.0;
    m_dK1Combo[2] = 1.0 / (dDeltaT * m_dImpCf[1][1]);
	m_dK1Combo[3] = -m_dImpCf[0][0] / m_dImpCf[1][1];
	m_dK1Combo[4] = -m_dExpCf[1][0] / m_dImpCf[1][1];
	m_dK1Combo[5] = 0.0;

    // u2 implicit evaluation combination
    m_du2fCombo[0] = 1.0;
    m_du2fCombo[1] = 0.0;
    m_du2fCombo[2] = 0.0;
    m_du2fCombo[3] = dDeltaT * m_dImpCf[2][0];
    m_du2fCombo[4] = dDeltaT * m_dExpCf[2][0];
	m_du2fCombo[5] = dDeltaT * m_dImpCf[2][1];

    // K2 combination
    m_dK2Combo[0] = -1.0 / (dDeltaT * m_dImpCf[2][2]);
    m_dK2Combo[1] = 0.0;
    m_dK2Combo[2] = 1.0 / (dDeltaT * m_dImpCf[2][2]);
    m_dK2Combo[3] = -m_dImpCf[1][0] / m_dImpCf[2][2];
    m_dK2Combo[4] = -m_dExpCf[2][0] / m_dImpCf[2][2];
    m_dK2Combo[5] = -m_dImpCf[2][1] / m_dImpCf[2][2];
    m_dK2Combo[6] = -m_dExpCf[2][1] / m_dImpCf[2][2];
	m_dK2Combo[7] = 0.0;

    // Kh2 combination
    m_dKh2Combo[0] = -1.0 / (dDeltaT * m_dExpCf[2][1]);
    m_dKh2Combo[1] = 1.0 / (dDeltaT * m_dExpCf[2][1]);
    m_dKh2Combo[2] = 0.0;
    m_dKh2Combo[3] = -m_dImpCf[2][0] / m_dExpCf[2][1];
    m_dKh2Combo[4] = -m_dExpCf[2][0] / m_dExpCf[2][1];
	m_dKh2Combo[5] = -m_dImpCf[2][1] / m_dExpCf[2][1];
	m_dKh2Combo[6] = 0.0;

    // u3 implicit evaluation combination
    m_du3fCombo[0] = 1.0;
    m_du3fCombo[1] = 0.0;
    m_du3fCombo[2] = 0.0;
    m_du3fCombo[3] = dDeltaT * m_dImpCf[3][0];
    m_du3fCombo[4] = dDeltaT * m_dExpCf[3][0];
    m_du3fCombo[5] = dDeltaT * m_dImpCf[3][1];
    m_du3fCombo[6] = dDeltaT * m_dExpCf[3][1];
	m_du3fCombo[7] = dDeltaT * m_dImpCf[3][2];

    // K3 combination
    m_dK3Combo[0] = -1.0 / (dDeltaT * m_dImpCf[3][3]);
    m_dK3Combo[1] = 0.0;
    m_dK3Combo[2] = 1.0 / (dDeltaT * m_dImpCf[3][3]);
    m_dK3Combo[3] = -m_dImpCf[3][0] / m_dImpCf[3][3];
    m_dK3Combo[4] = -m_dExpCf[3][0] / m_dImpCf[3][3];
    m_dK3Combo[5] = -m_dImpCf[3][1] / m_dImpCf[3][3];
    m_dK3Combo[6] = -m_dExpCf[3][1] / m_dImpCf[3][3];
    m_dK3Combo[7] = -m_dImpCf[3][2] / m_dImpCf[3][3];
    m_dK3Combo[8] = -m_dExpCf[3][2] / m_dImpCf[3][3];
	m_dK3Combo[9] = 0.0;

    // Kh3 combination
    m_dKh3Combo[0] = -1.0 / (dDeltaT * m_dExpCf[3][2]);
    m_dKh3Combo[1] = 1.0 / (dDeltaT * m_dExpCf[3][2]);
    m_dKh3Combo[2] = 0.0;
    m_dKh3Combo[3] = -m_dImpCf[3][0] / m_dExpCf[3][2];
    m_dKh3Combo[4] = -m_dExpCf[3][0] / m_dExpCf[3][2];
    m_dKh3Combo[5] = -m_dImpCf[3][1] / m_dExpCf[3][2];
    m_dKh3Combo[6] = -m_dExpCf[3][1] / m_dExpCf[3][2];
	m_dKh3Combo[7] = -m_dImpCf[3][2] / m_dExpCf[3][2];
	m_dKh3Combo[8] = 0.0;

    // uf4 explicit evaluation combination
    m_du4fCombo[0] = 1.0;
    m_du4fCombo[1] = 0.0;
    m_du4fCombo[2] = 0.0;
    m_du4fCombo[3] = dDeltaT * m_dImpCf[4][0];
    m_du4fCombo[4] = dDeltaT * m_dExpCf[4][0];
    m_du4fCombo[5] = dDeltaT * m_dImpCf[4][1];
    m_du4fCombo[6] = dDeltaT * m_dExpCf[4][1];
    m_du4fCombo[7] = dDeltaT * m_dImpCf[4][2];
    m_du4fCombo[8] = dDeltaT * m_dExpCf[4][2];
	m_du4fCombo[9] = dDeltaT * m_dImpCf[4][3];

	// K4 combination
    m_dK4Combo[0] = -1.0 / (dDeltaT * m_dImpCf[4][4]);
    m_dK4Combo[1] = 0.0;
    m_dK4Combo[2] = 1.0 / (dDeltaT * m_dImpCf[4][4]);
    m_dK4Combo[3] = -m_dImpCf[4][0] / m_dImpCf[4][4];
    m_dK4Combo[4] = -m_dExpCf[4][0] / m_dImpCf[4][4];
    m_dK4Combo[5] = -m_dImpCf[4][1] / m_dImpCf[4][4];
    m_dK4Combo[6] = -m_dExpCf[4][1] / m_dImpCf[4][4];
    m_dK4Combo[7] = -m_dImpCf[4][2] / m_dImpCf[4][4];
    m_dK4Combo[8] = -m_dExpCf[4][2] / m_dImpCf[4][4];
	m_dK4Combo[9] = -m_dImpCf[4][3] / m_dImpCf[4][4];
    m_dK4Combo[10] = -m_dExpCf[4][3] / m_dImpCf[4][4];
	m_dK4Combo[11] = 0.0;

    // Kh4 combination
    m_dKh4Combo[0] = -1.0 / (dDeltaT * m_dExpCf[4][3]);
    m_dKh4Combo[1] = 1.0 / (dDeltaT * m_dExpCf[4][3]);
    m_dKh4Combo[2] = 0.0;
    m_dKh4Combo[3] = -m_dImpCf[4][0] / m_dExpCf[4][3];
    m_dKh4Combo[4] = -m_dExpCf[4][0] / m_dExpCf[4][3];
    m_dKh4Combo[5] = -m_dImpCf[4][1] / m_dExpCf[4][3];
    m_dKh4Combo[6] = -m_dExpCf[4][1] / m_dExpCf[4][3];
	m_dKh4Combo[7] = -m_dImpCf[4][2] / m_dExpCf[4][3];
	m_dKh4Combo[8] = -m_dExpCf[4][2] / m_dExpCf[4][3];
	m_dKh4Combo[9] = -m_dImpCf[4][3] / m_dExpCf[4][3];
	m_dKh4Combo[10] = 0.0;

	// uf5 explicit evaluation combination
    m_du5fCombo[0] = 1.0;
    m_du5fCombo[1] = 0.0;
    m_du5fCombo[2] = 0.0;
    m_du5fCombo[3] = dDeltaT * m_dImpCf[5][0];
    m_du5fCombo[4] = dDeltaT * m_dExpCf[5][0];
    m_du5fCombo[5] = dDeltaT * m_dImpCf[5][1];
    m_du5fCombo[6] = dDeltaT * m_dExpCf[5][1];
    m_du5fCombo[7] = dDeltaT * m_dImpCf[5][2];
    m_du5fCombo[8] = dDeltaT * m_dExpCf[5][2];
	m_du5fCombo[9] = dDeltaT * m_dImpCf[5][3];
	m_du5fCombo[10] = dDeltaT * m_dExpCf[5][3];
	m_du5fCombo[11] = dDeltaT * m_dImpCf[5][4];

	// K5 combination
    m_dK5Combo[0] = -1.0 / (dDeltaT * m_dImpCf[5][5]);
    m_dK5Combo[1] = 0.0;
    m_dK5Combo[2] = 1.0 / (dDeltaT * m_dImpCf[5][5]);
    m_dK5Combo[3] = -m_dImpCf[5][0] / m_dImpCf[5][5];
    m_dK5Combo[4] = -m_dExpCf[5][0] / m_dImpCf[5][5];
    m_dK5Combo[5] = -m_dImpCf[5][1] / m_dImpCf[5][5];
    m_dK5Combo[6] = -m_dExpCf[5][1] / m_dImpCf[5][5];
    m_dK5Combo[7] = -m_dImpCf[5][2] / m_dImpCf[5][5];
    m_dK5Combo[8] = -m_dExpCf[5][2] / m_dImpCf[5][5];
	m_dK5Combo[9] = -m_dImpCf[5][3] / m_dImpCf[5][5];
    m_dK5Combo[10] = -m_dExpCf[5][3] / m_dImpCf[5][5];
	m_dK5Combo[11] = -m_dImpCf[5][4] / m_dImpCf[5][5];
    m_dK5Combo[12] = -m_dExpCf[5][4] / m_dImpCf[5][5];
	m_dK5Combo[13] = 0.0;

    // Kh5 combination
    m_dKh5Combo[0] = -1.0 / (dDeltaT * m_dExpCf[5][4]);
    m_dKh5Combo[1] = 1.0 / (dDeltaT * m_dExpCf[5][4]);
    m_dKh5Combo[2] = 0.0;
    m_dKh5Combo[3] = -m_dImpCf[5][0] / m_dExpCf[5][4];
    m_dKh5Combo[4] = -m_dExpCf[5][0] / m_dExpCf[5][4];
    m_dKh5Combo[5] = -m_dImpCf[5][1] / m_dExpCf[5][4];
    m_dKh5Combo[6] = -m_dExpCf[5][1] / m_dExpCf[5][4];
	m_dKh5Combo[7] = -m_dImpCf[5][2] / m_dExpCf[5][4];
	m_dKh5Combo[8] = -m_dExpCf[5][2] / m_dExpCf[5][4];
	m_dKh5Combo[9] = -m_dImpCf[5][3] / m_dExpCf[5][4];
	m_dKh5Combo[10] = -m_dExpCf[5][3] / m_dExpCf[5][4];
	m_dKh5Combo[11] = -m_dImpCf[5][4] / m_dExpCf[5][4];
	m_dKh5Combo[12] = 0.0;

	// uf6 explicit evaluation combination
    m_du6fCombo[0] = 1.0;
    m_du6fCombo[1] = 0.0;
    m_du6fCombo[2] = 0.0;
    m_du6fCombo[3] = dDeltaT * m_dImpCf[6][0];
    m_du6fCombo[4] = dDeltaT * m_dExpCf[6][0];
    m_du6fCombo[5] = dDeltaT * m_dImpCf[6][1];
    m_du6fCombo[6] = dDeltaT * m_dExpCf[6][1];
    m_du6fCombo[7] = dDeltaT * m_dImpCf[6][2];
    m_du6fCombo[8] = dDeltaT * m_dExpCf[6][2];
	m_du6fCombo[9] = dDeltaT * m_dImpCf[6][3];
	m_du6fCombo[10] = dDeltaT * m_dExpCf[6][3];
	m_du6fCombo[11] = dDeltaT * m_dImpCf[6][4];
	m_du6fCombo[12] = dDeltaT * m_dExpCf[6][4];
	m_du6fCombo[13] = dDeltaT * m_dImpCf[6][5];

	// PRE-STAGE 1 - Implicit solve to start
	Time timeSub0 = time;
    double dtSub0 = m_dImpCf[0][0] * dDeltaT;
    pGrid->CopyData(0, 1, DataType_State);
    pHorizontalDynamics->StepImplicit(0, 1, timeSub0, dtSub0);
	pVerticalDynamics->StepImplicit(0, 1, timeSub0, dtSub0);
    pGrid->PostProcessSubstage(1, DataType_State);
    pGrid->PostProcessSubstage(1, DataType_Tracers);

    // Store the evaluation K1 to index 3
    pGrid->LinearCombineData(m_dK0Combo, 3, DataType_State);

    // SUBSTAGE 1
    // Compute the explicit step to index 1
    Time timeSub1 = time;
    double dtSub1 = m_dExpCf[1][0] * dDeltaT;
    pGrid->LinearCombineData(m_du1fCombo, 1, DataType_State);
    pHorizontalDynamics->StepExplicit(0, 1, timeSub1, dtSub1);
	pVerticalDynamics->StepExplicit(0, 1, timeSub1, dtSub1);
    pGrid->PostProcessSubstage(1, DataType_State);
    pGrid->PostProcessSubstage(1, DataType_Tracers);

    // Store the evaluation Kh1 to index 4
    pGrid->LinearCombineData(m_dKh1Combo, 4, DataType_State);

    // Compute implicit step based on known data to index 2
    pGrid->CopyData(1, 2, DataType_State);
    dtSub1 = m_dImpCf[1][1] * dDeltaT;
    pVerticalDynamics->StepImplicit(1, 2, timeSub1, dtSub1);
    pGrid->PostProcessSubstage(2, DataType_State);
    pGrid->PostProcessSubstage(2, DataType_Tracers);

    // Store the evaluation K1 to index 3
    pGrid->LinearCombineData(m_dK1Combo, 5, DataType_State);

    //std::cout << "Substage 1 done ... \n";

    // SUBSTAGE 2
    // Compute uf2
    Time timeSub2 = time;
    double dtSub2 = m_dExpCf[2][1] * dDeltaT;
    pGrid->LinearCombineData(m_du2fCombo, 1, DataType_State);
    pHorizontalDynamics->StepExplicit(2, 1, timeSub2, dtSub2);
    pVerticalDynamics->StepExplicit(2, 1, timeSub2, dtSub2);
    pGrid->PostProcessSubstage(1, DataType_State);
    pGrid->PostProcessSubstage(1, DataType_Tracers);

    // Store the evaluation Kh2 to index 6
    pGrid->LinearCombineData(m_dKh2Combo, 6, DataType_State);

    // Compute u2 from uf2 and store it to index 2 (over u1)
    dtSub2 = m_dImpCf[2][2] * dDeltaT;
    pGrid->CopyData(1, 2, DataType_State);
    pVerticalDynamics->StepImplicit(1, 2, timeSub2, dtSub2);
    pGrid->PostProcessSubstage(2, DataType_State);
    pGrid->PostProcessSubstage(2, DataType_Tracers);

    // Store the evaluation K2 to index 7
    pGrid->LinearCombineData(m_dK2Combo, 7, DataType_State);

    //std::cout << "Substage 2 done ... \n";

    // SUBSTAGE 3
    // Compute uf3
    Time timeSub3 = time;
    double dtSub3 = m_dExpCf[3][2] * dDeltaT;
    pGrid->LinearCombineData(m_du3fCombo, 1, DataType_State);
    pHorizontalDynamics->StepExplicit(2, 1, timeSub2, dtSub2);
    pVerticalDynamics->StepExplicit(2, 1, timeSub2, dtSub2);
    pGrid->PostProcessSubstage(1, DataType_State);
    pGrid->PostProcessSubstage(1, DataType_Tracers);

    // Store the evaluation Kh3 to index 8
    pGrid->LinearCombineData(m_dKh3Combo, 8, DataType_State);

    // Compute u3 from uf3 and store it to index 2 (over u2)
    dtSub3 = m_dImpCf[3][3] * dDeltaT;
    pGrid->CopyData(1, 2, DataType_State);
    pVerticalDynamics->StepImplicit(1, 2, timeSub3, dtSub3);
    pGrid->PostProcessSubstage(2, DataType_State);
    pGrid->PostProcessSubstage(2, DataType_Tracers);

    // Store the evaluation K3 to index 9
    pGrid->LinearCombineData(m_dK3Combo, 9, DataType_State);

	//std::cout << "Substage 3 done ... \n";

    // SUBSTAGE 4 - MODIFIED DUE TO EXPLICIT ZERO EVALUATION
    // Compute uf4 from u3 and store it to index 2
    Time timeSub4 = time;
    double dtSub4 = m_dExpCf[4][3] * dDeltaT;
    pGrid->LinearCombineData(m_du4fCombo, 1, DataType_State);
    pHorizontalDynamics->StepExplicit(2, 1, timeSub4, dtSub4);
    pVerticalDynamics->StepExplicit(2, 1, timeSub4, dtSub4);
    pGrid->PostProcessSubstage(1, DataType_State);
    pGrid->PostProcessSubstage(1, DataType_Tracers);

	// Store the evaluation Kh4 to index 10
    pGrid->LinearCombineData(m_dKh4Combo, 10, DataType_State);

    // Compute u4 from uf4 and store it to index 2 (over u3)
    dtSub4 = m_dImpCf[4][4] * dDeltaT;
    //pGrid->CopyData(1, 2, DataType_State);
	// Start with the previous data sum here because of the explicit zero
	pGrid->LinearCombineData(m_du4fCombo, 2, DataType_State);
    pVerticalDynamics->StepImplicit(2, 2, timeSub4, dtSub4);
    pGrid->PostProcessSubstage(2, DataType_State);
    pGrid->PostProcessSubstage(2, DataType_Tracers);

	// Store the evaluation K4 to index 11
    pGrid->LinearCombineData(m_dK4Combo, 11, DataType_State);

	//std::cout << "Substage 4 done ... \n";

    // SUBSTAGE 5
    // Compute uf5 from u4 and store it to index 2
    Time timeSub5 = time;
    double dtSub5 = m_dExpCf[5][4] * dDeltaT;
    pGrid->LinearCombineData(m_du5fCombo, 1, DataType_State);
    pHorizontalDynamics->StepExplicit(2, 1, timeSub5, dtSub5);
    pVerticalDynamics->StepExplicit(2, 1, timeSub5, dtSub5);
    pGrid->PostProcessSubstage(1, DataType_State);
    pGrid->PostProcessSubstage(1, DataType_Tracers);

	// Store the evaluation Kh5 to index 12
    pGrid->LinearCombineData(m_dKh5Combo, 12, DataType_State);

    // Compute u5 from uf5 and store it to index 2 (over u4)
    dtSub5 = m_dImpCf[5][5] * dDeltaT;
    pGrid->CopyData(1, 2, DataType_State);
    pVerticalDynamics->StepImplicit(1, 2, timeSub5, dtSub5);
    pGrid->PostProcessSubstage(2, DataType_State);
    pGrid->PostProcessSubstage(2, DataType_Tracers);

	// Store the evaluation K5 to index 13
    pGrid->LinearCombineData(m_dK5Combo, 13, DataType_State);

	//std::cout << "Substage 5 done ... \n";

    // SUBSTAGE 6
    // Compute uf6 from u5 and store it to index 2
    Time timeSub6 = time;
    double dtSub6 = m_dExpCf[6][5] * dDeltaT;
    pGrid->LinearCombineData(m_du6fCombo, 1, DataType_State);
    pHorizontalDynamics->StepExplicit(2, 1, timeSub6, dtSub6);
    pVerticalDynamics->StepExplicit(2, 1, timeSub6, dtSub6);
    pGrid->PostProcessSubstage(1, DataType_State);
    pGrid->PostProcessSubstage(1, DataType_Tracers);

    // Compute u5 from uf5 and store it to index 2 (over u4)
    dtSub5 = m_dImpCf[6][6] * dDeltaT;
    pGrid->CopyData(1, 2, DataType_State);
    pVerticalDynamics->StepImplicit(1, 2, timeSub6, dtSub6);
    pGrid->PostProcessSubstage(2, DataType_State);
    pGrid->PostProcessSubstage(2, DataType_Tracers);

    // Apply hyperdiffusion at the end of the explicit substep (ask Paul)
	pGrid->CopyData(2, 1, DataType_State);
	pHorizontalDynamics->StepAfterSubCycle(2, 1, 3, time, dDeltaT);
	pGrid->CopyData(1, 0, DataType_State);
	//*/
}
void TimestepSchemeStrang::Step(
	bool fFirstStep,
	bool fLastStep,
	const Time & time,
	double dDeltaT
) {
	// Get a copy of the grid
	Grid * pGrid = m_model.GetGrid();

	// Get a copy of the HorizontalDynamics
	HorizontalDynamics * pHorizontalDynamics =
		m_model.GetHorizontalDynamics();

	// Get a copy of the VerticalDynamics
	VerticalDynamics * pVerticalDynamics =
		m_model.GetVerticalDynamics();

	// Half a time step
	double dHalfDeltaT = 0.5 * dDeltaT;

	// Vertical timestep
	if (fFirstStep) {
		pVerticalDynamics->StepImplicit(0, 0, time, dHalfDeltaT);

	} else {
		pGrid->LinearCombineData(m_dCarryoverCombination, 0, DataType_State);
	}

	// Forward Euler
	if (m_eExplicitDiscretization == ForwardEuler) {
		pGrid->CopyData(0, 4, DataType_State);
		pHorizontalDynamics->StepExplicit(0, 4, time, dDeltaT);
		pVerticalDynamics->StepExplicit(0, 4, time, dDeltaT);
		pGrid->PostProcessSubstage(4, DataType_State);
		pGrid->PostProcessSubstage(4, DataType_Tracers);

	// Explicit fourth-order Runge-Kutta
	} else if (m_eExplicitDiscretization == RungeKutta4) {
		pGrid->CopyData(0, 1, DataType_State);
		pHorizontalDynamics->StepExplicit(0, 1, time, dHalfDeltaT);
		pVerticalDynamics->StepExplicit(0, 1, time, dHalfDeltaT);
		pGrid->PostProcessSubstage(1, DataType_State);
		pGrid->PostProcessSubstage(1, DataType_Tracers);

		pGrid->CopyData(0, 2, DataType_State);
		pHorizontalDynamics->StepExplicit(1, 2, time, dHalfDeltaT);
		pVerticalDynamics->StepExplicit(1, 2, time, dHalfDeltaT);
		pGrid->PostProcessSubstage(2, DataType_State);
		pGrid->PostProcessSubstage(2, DataType_Tracers);

		pGrid->CopyData(0, 3, DataType_State);
		pHorizontalDynamics->StepExplicit(2, 3, time, dDeltaT);
		pVerticalDynamics->StepExplicit(2, 3, time, dDeltaT);
		pGrid->PostProcessSubstage(3, DataType_State);
		pGrid->PostProcessSubstage(3, DataType_Tracers);

		pGrid->LinearCombineData(m_dRK4Combination, 4, DataType_State);

		pHorizontalDynamics->StepExplicit(3, 4, time, dDeltaT / 6.0);
		pVerticalDynamics->StepExplicit(3, 4, time, dDeltaT / 6.0);
		pGrid->PostProcessSubstage(4, DataType_State);
		pGrid->PostProcessSubstage(4, DataType_Tracers);

	// Explicit strong stability preserving third-order Runge-Kutta
	} else if (m_eExplicitDiscretization == RungeKuttaSSP3) {

		pGrid->CopyData(0, 1, DataType_State);
		pHorizontalDynamics->StepExplicit(0, 1, time, dDeltaT);
		pVerticalDynamics->StepExplicit(0, 1, time, dDeltaT);
		pGrid->PostProcessSubstage(1, DataType_State);
		pGrid->PostProcessSubstage(1, DataType_Tracers);

		pGrid->LinearCombineData(m_dSSPRK3CombinationA, 2, DataType_State);
		pHorizontalDynamics->StepExplicit(1, 2, time, 0.25 * dDeltaT);
		pVerticalDynamics->StepExplicit(1, 2, time, 0.25 * dDeltaT);
		pGrid->PostProcessSubstage(2, DataType_State);
		pGrid->PostProcessSubstage(2, DataType_Tracers);

		pGrid->LinearCombineData(m_dSSPRK3CombinationB, 4, DataType_State);
		pHorizontalDynamics->StepExplicit(2, 4, time, (2.0/3.0) * dDeltaT);
		pVerticalDynamics->StepExplicit(2, 4, time, (2.0/3.0) * dDeltaT);
		pGrid->PostProcessSubstage(4, DataType_State);
		pGrid->PostProcessSubstage(4, DataType_Tracers);

	// Explicit Kinnmark, Gray and Ullrich third-order five-stage Runge-Kutta
	} else if (m_eExplicitDiscretization == KinnmarkGrayUllrich35) {

		pGrid->CopyData(0, 1, DataType_State);
		pHorizontalDynamics->StepExplicit(0, 1, time, dDeltaT / 5.0);
		pVerticalDynamics->StepExplicit(0, 1, time, dDeltaT / 5.0);
		pGrid->PostProcessSubstage(1, DataType_State);
		pGrid->PostProcessSubstage(1, DataType_Tracers);

		pGrid->CopyData(0, 2, DataType_State);
		pHorizontalDynamics->StepExplicit(1, 2, time, dDeltaT / 5.0);
		pVerticalDynamics->StepExplicit(1, 2, time, dDeltaT / 5.0);
		pGrid->PostProcessSubstage(2, DataType_State);
		pGrid->PostProcessSubstage(2, DataType_Tracers);

		pGrid->CopyData(0, 3, DataType_State);
		pHorizontalDynamics->StepExplicit(2, 3, time, dDeltaT / 3.0);
		pVerticalDynamics->StepExplicit(2, 3, time, dDeltaT / 3.0);
		pGrid->PostProcessSubstage(3, DataType_State);
		pGrid->PostProcessSubstage(3, DataType_Tracers);

		pGrid->CopyData(0, 2, DataType_State);
		pHorizontalDynamics->StepExplicit(3, 2, time, 2.0 * dDeltaT / 3.0);
		pVerticalDynamics->StepExplicit(3, 2, time, 2.0 * dDeltaT / 3.0);
		pGrid->PostProcessSubstage(2, DataType_State);
		pGrid->PostProcessSubstage(2, DataType_Tracers);

		pGrid->LinearCombineData(
			m_dKinnmarkGrayUllrichCombination, 4, DataType_State);
		pHorizontalDynamics->StepExplicit(2, 4, time, 3.0 * dDeltaT / 4.0);
		pVerticalDynamics->StepExplicit(2, 4, time, 3.0 * dDeltaT / 4.0);
		pGrid->PostProcessSubstage(4, DataType_State);
		pGrid->PostProcessSubstage(4, DataType_Tracers);

	// Explicit strong stability preserving five-stage third-order Runge-Kutta
	} else if (m_eExplicitDiscretization == RungeKuttaSSPRK53) {

		const double dStepOne = 0.377268915331368;

		pGrid->CopyData(0, 1, DataType_State);
		pHorizontalDynamics->StepExplicit(0, 1, time, dStepOne * dDeltaT);
		pVerticalDynamics->StepExplicit(0, 1, time, dStepOne * dDeltaT);
		pGrid->PostProcessSubstage(1, DataType_State);
		pGrid->PostProcessSubstage(1, DataType_Tracers);

		pGrid->CopyData(1, 2, DataType_State);
		pHorizontalDynamics->StepExplicit(1, 2, time, dStepOne * dDeltaT);
		pVerticalDynamics->StepExplicit(1, 2, time, dStepOne * dDeltaT);
		pGrid->PostProcessSubstage(2, DataType_State);
		pGrid->PostProcessSubstage(2, DataType_Tracers);

		const double dStepThree = 0.242995220537396;

		pGrid->LinearCombineData(m_dSSPRK53CombinationA, 3, DataType_State);
		pHorizontalDynamics->StepExplicit(2, 3, time, dStepThree * dDeltaT);
		pVerticalDynamics->StepExplicit(2, 3, time, dStepThree * dDeltaT);
		pGrid->PostProcessSubstage(3, DataType_State);
		pGrid->PostProcessSubstage(3, DataType_Tracers);

		const double dStepFour = 0.238458932846290;

		pGrid->LinearCombineData(m_dSSPRK53CombinationB, 0, DataType_State);
		pHorizontalDynamics->StepExplicit(3, 0, time, dStepFour * dDeltaT);
		pVerticalDynamics->StepExplicit(3, 0, time, dStepFour * dDeltaT);
		pGrid->PostProcessSubstage(0, DataType_State);
		pGrid->PostProcessSubstage(0, DataType_Tracers);

		const double dStepFive = 0.287632146308408;

		pGrid->LinearCombineData(m_dSSPRK53CombinationC, 4, DataType_State);
		pHorizontalDynamics->StepExplicit(0, 4, time, dStepFive * dDeltaT);
		pVerticalDynamics->StepExplicit(0, 4, time, dStepFive * dDeltaT);
		pGrid->PostProcessSubstage(4, DataType_State);
		pGrid->PostProcessSubstage(4, DataType_Tracers);

	// Invalid explicit discretization
	} else {
		_EXCEPTIONT("Invalid explicit discretization");
	}

	// Apply hyperdiffusion
	pGrid->CopyData(4, 1, DataType_State);
	pHorizontalDynamics->StepAfterSubCycle(4, 1, 2, time, dDeltaT);

	// Vertical timestep
	double dOffCenterDeltaT = 0.5 * (1.0 + m_dOffCentering) * dDeltaT;

	pGrid->CopyData(1, 0, DataType_State);
	pVerticalDynamics->StepImplicit(0, 0, time, dOffCenterDeltaT);

	pGrid->LinearCombineData(m_dOffCenteringCombination, 0, DataType_State);

	if (!fLastStep) {
		pGrid->LinearCombineData(m_dCarryoverFinal, 1, DataType_State);
	}

	//pGrid->CopyData(0, 1, DataType_State);
	//pVerticalDynamics->StepExplicit(0, 1, time, dDeltaT);
	//pVerticalDynamics->StepImplicit(0, 0, time, dDeltaT);
/*
	if (0) {
	//if (fLastStep) {
		DataVector<double> dDifference;
		dDifference.Initialize(2);
		dDifference[0] = -1.0;
		dDifference[1] = 1.0;
		pGrid->LinearCombineData(dDifference, 0, DataType_State);
	} else {
		pGrid->CopyData(4, 0, DataType_State);
	}
*/
}