int
NewmarkSensitivityIntegrator::formEleResidual(FE_Element *theEle)
{

	if (sensitivityFlag == 0) {  // NO SENSITIVITY ANALYSIS

		this->Newmark::formEleResidual(theEle);

	}
	else {  // (ASSEMBLE ALL TERMS)

		theEle->zeroResidual();

		// Compute the time-stepping parameters on the form
		// udotdot = a1*ui+1 + a2*ui + a3*udoti + a4*udotdoti
		// udot    = a5*ui+1 + a6*ui + a7*udoti + a8*udotdoti
		// (see p. 166 of Chopra)

		// The constants are:
		// a1 = 1.0/(beta*dt*dt)
		// a2 = -1.0/(beta*dt*dt)
		// a3 = -1.0/beta*dt
		// a4 = 1.0 - 1.0/(2.0*beta)
		// a5 = gamma/(beta*dt)
		// a6 = -gamma/(beta*dt)
		// a7 = 1.0 - gamma/beta
		// a8 = 1.0 - gamma/(2.0*beta)

		// We can make use of the data members c2 and c3 of this class. 
		// As long as disp==true, they are defined as:
		// c2 = gamma/(beta*dt)
		// c3 = 1.0/(beta*dt*dt)

		// So, the constants can be computed as follows:
		if (displ==false) {
			opserr << "ERROR: Newmark::formEleResidual() -- the implemented"
				<< " scheme only works if the displ variable is set to true." << endln;
		}
		double a2 = -c3;
		double a3 = -c2/gamma;
		double a4 = 1.0 - 1.0/(2.0*beta);
		double a6 = -c2;
		double a7 = 1.0 - gamma/beta;
		double dt = gamma/(beta*c2);
		double a8 = dt*(1.0 - gamma/(2.0*beta));


		// Obtain sensitivity vectors from previous step
		int vectorSize = U->Size();
		Vector V(vectorSize);
		Vector Vdot(vectorSize);
		Vector Vdotdot(vectorSize);
		int i, loc;

		AnalysisModel *myModel = this->getAnalysisModel();
		DOF_GrpIter &theDOFs = myModel->getDOFs();
		DOF_Group *dofPtr;
		while ((dofPtr = theDOFs()) != 0) {

			const ID &id = dofPtr->getID();
			int idSize = id.Size();
			const Vector &dispSens = dofPtr->getDispSensitivity(gradNumber);	
			for (i=0; i < idSize; i++) {
				loc = id(i);
				if (loc >= 0) {
					V(loc) = dispSens(i);		
				}
			}

			const Vector &velSens = dofPtr->getVelSensitivity(gradNumber);
			for (i=0; i < idSize; i++) {
				loc = id(i);
				if (loc >= 0) {
					Vdot(loc) = velSens(i);
				}
			}

			const Vector &accelSens = dofPtr->getAccSensitivity(gradNumber);	
			for (i=0; i < idSize; i++) {
				loc = id(i);
				if (loc >= 0) {
					Vdotdot(loc) = accelSens(i);
				}
			}
		}


		// Pre-compute the vectors involving a2, a3, etc.
		//Vector tmp1 = V*a2 + Vdot*a3 + Vdotdot*a4;
		Vector tmp1(vectorSize);
		tmp1.addVector(0.0, V, a2);
		tmp1.addVector(1.0, Vdot, a3);
		tmp1.addVector(1.0, Vdotdot, a4);
		//Vector tmp2 = V*a6 + Vdot*a7 + Vdotdot*a8;
		Vector tmp2(vectorSize);
		tmp2.addVector(0.0, V, a6);
		tmp2.addVector(1.0, Vdot, a7);
		tmp2.addVector(1.0, Vdotdot, a8);

		if (massMatrixMultiplicator == 0)
			massMatrixMultiplicator = new Vector(tmp1.Size());
		if (dampingMatrixMultiplicator == 0)
			dampingMatrixMultiplicator = new Vector(tmp2.Size());

		(*massMatrixMultiplicator) = tmp1;
		(*dampingMatrixMultiplicator) = tmp2;


		// Now we're ready to make calls to the FE Element:

		// The term -dPint/dh|u fixed
		theEle->addResistingForceSensitivity(gradNumber); 

		// The term -dM/dh*acc
		theEle->addM_ForceSensitivity(gradNumber, *Udotdot, -1.0);

		// The term -M*(a2*v + a3*vdot + a4*vdotdot)
		theEle->addM_Force(*massMatrixMultiplicator,-1.0);

		// The term -C*(a6*v + a7*vdot + a8*vdotdot)
		theEle->addD_Force(*dampingMatrixMultiplicator,-1.0);

		// The term -dC/dh*vel
		theEle->addD_ForceSensitivity(gradNumber, *Udot,-1.0);
		
	}

	return 0;
}
int 
NewmarkSensitivityIntegrator::saveSensitivity(const Vector & vNew,int gradNum,int numGrads)
{

	// Compute Newmark parameters in general notation
	double a1 = c3;
	double a2 = -c3;
	double a3 = -c2/gamma;
	double a4 = 1.0 - 1.0/(2.0*beta);
	double a5 = c2;
	double a6 = -c2;
	double a7 = 1.0 - gamma/beta;
	double dt = gamma/(beta*c2);
	double a8 = dt*(1.0 - gamma/(2.0*beta));


	// Recover sensitivity results from previous step
	int vectorSize = U->Size();
	Vector V(vectorSize);
	Vector Vdot(vectorSize);
	Vector Vdotdot(vectorSize);
	int i, loc;

	AnalysisModel *myModel = this->getAnalysisModel();
	DOF_GrpIter &theDOFs = myModel->getDOFs();
	DOF_Group *dofPtr;
	while ((dofPtr = theDOFs()) != 0) {
	  
	  const ID &id = dofPtr->getID();
	  int idSize = id.Size();
	  const Vector &dispSens = dofPtr->getDispSensitivity(gradNumber);	
	  for (i=0; i < idSize; i++) {
	    loc = id(i);
	    if (loc >= 0) {
	      V(loc) = dispSens(i);		
	    }
	  }
	  
	  const Vector &velSens = dofPtr->getVelSensitivity(gradNumber);
	  for (i=0; i < idSize; i++) {
	    loc = id(i);
	    if (loc >= 0) {
	      Vdot(loc) = velSens(i);
	    }
	  }
	  
	  const Vector &accelSens = dofPtr->getAccSensitivity(gradNumber);	
	  for (i=0; i < idSize; i++) {
	    loc = id(i);
	    if (loc >= 0) {
	      Vdotdot(loc) = accelSens(i);
	    }
	  }
	}


	// Compute new acceleration and velocity vectors:
	Vector vdotNew(vectorSize);
	Vector vdotdotNew(vectorSize);
	//(*vdotdotNewPtr) = vNew*a1 + V*a2 + Vdot*a3 + Vdotdot*a4;
	vdotdotNew.addVector(0.0, vNew, a1);
	vdotdotNew.addVector(1.0, V, a2);
	vdotdotNew.addVector(1.0, Vdot, a3);
	vdotdotNew.addVector(1.0, Vdotdot, a4);
	//(*vdotNewPtr) = vNew*a5 + V*a6 + Vdot*a7 + Vdotdot*a8;
	vdotNew.addVector(0.0, vNew, a5);
	vdotNew.addVector(1.0, V, a6);
	vdotNew.addVector(1.0, Vdot, a7);
	vdotNew.addVector(1.0, Vdotdot, a8);

	// Now we can save vNew, vdotNew and vdotdotNew
	DOF_GrpIter &theDOFGrps = myModel->getDOFs();
	DOF_Group 	*dofPtr1;
	while ( (dofPtr1 = theDOFGrps() ) != 0)  {
	  dofPtr1->saveSensitivity(vNew,vdotNew,vdotdotNew,gradNum,numGrads);
	}
	
	return 0;
}