/*
 * ADAPT2D : a software for automatic mesh adaptation in 2D
 *
 * AUTHOR : Manuel J. Castro Diaz(e-mail:castro@gamba.cie.uma.es)
 * ADAPTED FOR FREEFEM : Prud'homme Christophe (e-mail:prudhomm@ann.jussieu.fr) 
 *
 * this code is public domain
 * 
 * You may copy freely these files and use it for    
 * teaching or research. These or part of these may   
 * not be sold or used for a commercial purpose without
 * our consent
 * 
 * Any problems should be reported to the AUTHOR
 * at the following address : castro@gamba.cie.uma.es
 */


#include <header.hxx>
#include <m_t0.hxx>

/*
                   DER2 subroutine

    Hessian Matrix computation at every mesh vertex.


    Input:
    -----   sol      : Solution field (P1 interpolation).
            malla    : Mesh.
            nsol     : dimention of the solution field.

    Output:
    ------    hes  : Hessian metrix field at every vertex of mesh.

                     hes(k*nbs*3+pos0*3+0)=Dxx .
                     hes(k*nbs*3+pos0*3+1)=Dxy=Dyx .
                     hes(k*nbs*3+pos0*3+2)=Dyy .
                          k= solution at field k,
                           nbs= total number of vertices.
                           pos0= vertex at postion pos0. 

         

                             /' d^2 sol          _
                             |  ------- * fb(i) dx
          d^2 sol           '/  dx^2
          ------- [i] = -----------------------------
          dx^2                   /'        _
                                 |  fb(i) dx
                                '/

  fb(i) = base function of i-th node.


*/
extern Scalar* gradfb(Mallado_T0*);

void der2(Scalar* sol,Mallado_T0* malla,Scalar* hes,int nsol) {

  Triangulo_T0_dlist* t_vec;
  Triangulo_T0* t0;
  Vertice_T0* so,*s_ini=malla->saca_sommet(0);
  Scalar areat;
  Scalar dx,dy;
  Scalar* asop,*gfb;
  int nbs=malla->nbss();
  int nbt=malla->nbtt();
  int i,j,k;
  int pos0;

  asop=new Scalar[nbs];
  if (asop==NIL) ERROR();

  for (i=0; i<nbs*nsol*3; i++) hes[i]=0;
  
  //   gradient of base function.
  gfb=gradfb(malla);
  //    Area of the support of base functions.
  for (i=0; i<nbs; i++) {
    so=malla->saca_sommet(i);
    t_vec=new Triangulo_T0_dlist;
    if (t_vec==NIL) ERROR();
    t_vecinos(so,*t_vec);
    asop[i]=t_vec->area();
    delete t_vec;
  }
  for (i=0; i<nbt; i++) {
    t0=malla->saca_triangle(i);
    areat=t0->area();
    if (areat<1e-30) {
      cerr<<"Eror. degenerated triangle. Area:"<<areat<<endl;
      cerr<<"Error in subroutine  der2."<<endl;
      exit(1);
    }
//    Derivative is constant at each triangle.
    for (k=0; k<nsol; k++) {
      dx=0;
      dy=0;
      for (j=0; j<3; j++) {
        pos0=t0->s[j]-s_ini;
        if(pos0<0 || pos0>=nbs) {
          cerr<<"Sorry. Pointer error.:"<<pos0<<endl;
          cerr<<"Error in subroutine der2."<<endl;
          exit(1);
        }
        dx=dx+sol[pos0*nsol+k]*gfb[i*6+j*2];
        dy=dy+sol[pos0*nsol+k]*gfb[i*6+j*2+1];
      }
//    averages over the base function supports.
      for (j=0; j<3; j++) {
        pos0=t0->s[j]-s_ini;
        if (pos0<0 || pos0>=nbs) {
          cerr<<"Sorry. Pointer error.:"<<pos0<<endl;
          cerr<<"Error in subroutine der2."<<endl;
          exit(1);
        }
        hes[k*nbs*3+pos0*3+0]=hes[k*nbs*3+pos0*3+0]-3*gfb[i*6+j*2+0]*dx*areat/asop[pos0];
        hes[k*nbs*3+pos0*3+1]=hes[k*nbs*3+pos0*3+1]-3*gfb[i*6+j*2+0]*dy*areat/asop[pos0];
        hes[k*nbs*3+pos0*3+2]=hes[k*nbs*3+pos0*3+2]-3*gfb[i*6+j*2+1]*dy*areat/asop[pos0];
      }
    }
  }
  
  for (i=0; i<nbs*nsol*3; i++) if (fabs(hes[i])<1e-30) hes[i]=0.0;
  if (gfb) delete[] gfb;
  if (asop)delete[] asop;
}
