const Matrix & PressureIndependMultiYield::getTangent (void)
{
  int loadStage = loadStagex[matN];
  int ndm = ndmx[matN];
  if (ndmx[matN] == 0) ndm = 3;

  if (loadStage == 1 && e2p == 0) elast2Plast();

  if (loadStage!=1) {  //linear elastic
    for (int i=0;i<6;i++)
      for (int j=0;j<6;j++) {
	theTangent(i,j) = 0.;
	if (i==j) theTangent(i,j) += refShearModulus;
	if (i<3 && j<3 && i==j) theTangent(i,j) += refShearModulus;
	if (i<3 && j<3) theTangent(i,j) += (refBulkModulus - 2.*refShearModulus/3.);
      }

  }
  else {
    double coeff;
    static Vector devia(6);

    /*if (committedActiveSurf > 0) {
      //devia = currentStress.deviator()-committedSurfaces[committedActiveSurf].center();
      devia = currentStress.deviator();
      devia -= committedSurfaces[committedActiveSurf].center();

      double size = committedSurfaces[committedActiveSurf].size();
      double plastModul = committedSurfaces[committedActiveSurf].modulus();
      coeff = 6.*refShearModulus*refShearModulus/(2.*refShearModulus+plastModul)/size/size;
    }*/
    if (activeSurfaceNum > 0) {
      //devia = currentStress.deviator()-committedSurfaces[committedActiveSurf].center();
      devia = trialStress.deviator();
      devia -= theSurfaces[activeSurfaceNum].center();

      double size = theSurfaces[activeSurfaceNum].size();
      double plastModul = theSurfaces[activeSurfaceNum].modulus();
      coeff = 6.*refShearModulus*refShearModulus/(2.*refShearModulus+plastModul)/size/size;
    }

    else coeff = 0.;

    for (int i=0;i<6;i++)
      for (int j=0;j<6;j++) {
	theTangent(i,j) = - coeff*devia[i]*devia[j];
        if (i==j) theTangent(i,j) += refShearModulus;
        if (i<3 && j<3 && i==j) theTangent(i,j) += refShearModulus;
	if (i<3 && j<3) theTangent(i,j) += (refBulkModulus - 2.*refShearModulus/3.);
      }
  }

  if (ndm==3)
    return theTangent;
  else {
    static Matrix workM(3,3);
    workM(0,0) = theTangent(0,0);
    workM(0,1) = theTangent(0,1);
    workM(0,2) = theTangent(0,3);
    workM(1,0) = theTangent(1,0);
    workM(1,1) = theTangent(1,1);
    workM(1,2) = theTangent(1,3);
    workM(2,0) = theTangent(3,0);
    workM(2,1) = theTangent(3,1);
    workM(2,2) = theTangent(3,3);
    return workM;
  }
}
const Matrix & PressureIndependMultiYield::getInitialTangent (void)
{
  int ndm = ndmx[matN];
  if (ndmx[matN] == 0) ndm = 3;

  for (int i=0;i<6;i++)
    for (int j=0;j<6;j++) {
      theTangent(i,j) = 0.;
      if (i==j) theTangent(i,j) += refShearModulus;
      if (i<3 && j<3 && i==j) theTangent(i,j) += refShearModulus;
      if (i<3 && j<3) theTangent(i,j) += (refBulkModulus - 2.*refShearModulus/3.);
    }

  if (ndm==3)
    return theTangent;
  else {
    static Matrix workM(3,3);
    workM(0,0) = theTangent(0,0);
    workM(0,1) = theTangent(0,1);
    workM(0,2) = theTangent(0,3);
    workM(1,0) = theTangent(1,0);
    workM(1,1) = theTangent(1,1);
    workM(1,2) = theTangent(1,3);
    workM(2,0) = theTangent(3,0);
    workM(2,1) = theTangent(3,1);
    workM(2,2) = theTangent(3,3);
    return workM;
  }
}
const Vector &
TransformationFE::getC_Force(const Vector &accel, double fact)
{
  this->FE_Element::zeroTangent();    
  this->FE_Element::addCtoTang();    
  const Matrix &theTangent = this->FE_Element::getTangent(0);

  static ID numDOFs(dofData, 1);
  numDOFs.setData(dofData, numGroups);
    
  // DO THE SP STUFF TO THE TANGENT 
  
  // get the transformation matrix from each dof group & number of local dof
  // for original node.
  int numNode = numGroups;
  for (int a = 0; a<numNode; a++) {
    Matrix *theT = theDOFs[a]->getT();
    theTransformations[a] = theT;
    if (theT != 0)
      numDOFs[a] = theT->noRows(); // T^ 
    else
      numDOFs[a] = theDOFs[a]->getNumDOF();
  }
  
  // perform Tt K T -- as T is block diagonal do T(i)^T K(i,j) T(j)
  // where blocks are of size equal to num ele dof at a node
  
  int startRow = 0;
  int noRowsTransformed = 0;
  int noRowsOriginal = 0;
  
  static Matrix localK;
  
  // foreach block row, for each block col do
  for (int i=0; i<numNode; i++) {
    
    int startCol = 0;
    int numDOFi = numDOFs[i];	
    int noColsOriginal = 0;
    
    for (int j=0; j<numNode; j++) {
      
      const Matrix *Ti = theTransformations[i];
      const Matrix *Tj = theTransformations[j];
      int numDOFj = numDOFs[j];	
      localK.setData(localKbuffer, numDOFi, numDOFj);
      
      // copy K(i,j) into localK matrix
      // CHECK SIZE OF BUFFFER	    
      for (int a=0; a<numDOFi; a++)
	for (int b=0; b<numDOFj; b++)
	  localK(a,b) = theTangent(noRowsOriginal+a, noColsOriginal+b);
      
      // now perform the matrix computation T(i)^T localK T(j)
      // note: if T == 0 then the Identity is assumed
      int noColsTransformed = 0;
      static Matrix localTtKT;
      
      if (Ti != 0 && Tj != 0) {
	noRowsTransformed = Ti->noCols();
	noColsTransformed = Tj->noCols();
	// CHECK SIZE OF BUFFFER
	localTtKT.setData(dataBuffer, noRowsTransformed, noColsTransformed);
	//localTtKT = (*Ti) ^ localK * (*Tj);
	localTtKT.addMatrixTripleProduct(0.0, *Ti, localK, *Tj, 1.0);
      } else if (Ti == 0 && Tj != 0) {
	noRowsTransformed = numDOFi;
	noColsTransformed = Tj->noCols();
	// CHECK SIZE OF BUFFFER
	localTtKT.setData(dataBuffer, noRowsTransformed, noColsTransformed);
	// localTtKT = localK * (*Tj);	       
	localTtKT.addMatrixProduct(0.0, localK, *Tj, 1.0);
      } else if (Ti != 0 && Tj == 0) {
	noRowsTransformed = Ti->noCols();
	noColsTransformed = numDOFj;
	// CHECK SIZE OF BUFFFER
	localTtKT.setData(dataBuffer, noRowsTransformed, noColsTransformed);
	//localTtKT = (*Ti) ^ localK;
	localTtKT.addMatrixTransposeProduct(0.0, *Ti, localK, 1.0);
      } else {
	noRowsTransformed = numDOFi;
	noColsTransformed = numDOFj;
	localTtKT.setData(dataBuffer, noRowsTransformed, noColsTransformed);
	localTtKT = localK;
      }
      // now copy into modTangent the T(i)^t K(i,j) T(j) product
      for (int c=0; c<noRowsTransformed; c++) 
	for (int d=0; d<noColsTransformed; d++) 
	  (*modTangent)(startRow+c, startCol+d) = localTtKT(c,d);
      
      startCol += noColsTransformed;
      noColsOriginal += numDOFj;
    }
    
    noRowsOriginal += numDOFi;
    startRow += noRowsTransformed;
  }
  
  // get the components we need out of the vector
  // and place in a temporary vector
  Vector tmp(numTransformedDOF);
  for (int j=0; j<numTransformedDOF; j++) {
    int dof = (*modID)(j);
    if (dof >= 0)
      tmp(j) = accel(dof);
    else
      tmp(j) = 0.0;
  }

  modResidual->addMatrixVector(0.0, *modTangent, tmp, 1.0);

  return *modResidual;
}