#include <alberta.h>
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
//# include <alberta_inlines.h>
//#include <alberta_util_inlines.h>
# include "alberta1_wrapper.h"
#endif 
 
 #include "newalberta.hh"
 /****************************************************************************/
 #include "do_on_el.hh"
 #include "do_elfunc_on_el.hh"
//#include "public_do_elfunc_on_el.hh"
#include "prototype_fem_elfunc.hh"
#include "fem_elfunc.hh"
 #include "fem_base.hh"
 #include "traverse.hh"
 #include "est.hh"
 #include "ellipt_est.hh"
 /****************************************************************************/
 /*                                                                          */
 /* error estimator for (nonlinear) heat equation:                           */
 /*              u_t - div A grad u + f(x,t,u,grad u) = 0                    */
 /*                                                                          */
 /* eta_h = C[0]*||h^2 ((U - Uold)/tau - div A grad U + f(x,t,U,grad U))||   */
 /*           + C[1]*|||h^1.5 [A grad U]|||                                  */
 /* eta_c = C[2]*||(Uold - Uold_coarse)/tau||                                */
 /* eta_t = C[3]*||U - Uold||                                                */
 /*                                                                          */
 /* heat_est() return value is the TIME DISCRETIZATION ESTIMATE, eta_t       */
 /*                                                                          */
 /****************************************************************************/
 //static const BAS_FCTS  *lagrange=get_lagrange(0);
//const  FE_SPACE *	est<ellipt_est>::const_fe_space;


 /*--------------------------------------------------------------------------*/
 /* element residual:  C2*h_S^2*|| U_t -div A nabla u^h + r ||_L^2(S)        */
 /*--------------------------------------------------------------------------*/
 /* time residual:  C4*|| U - Uold ||_L^2(S)                                 */
 /*--------------------------------------------------------------------------*/
 /* quadrature:     C5*h_S^2*||nabla(R)||_L^2(S)                             */
 /*--------------------------------------------------------------------------*/
 /* source:         C6*||f - In fn||_L^2(S)                                  */
 /*--------------------------------------------------------------------------*/


 /*--------------------------------------------------------------------------*/
 /* element residual:  C0*h_S^2*|| U_t -div A nabla u^h + r ||_L^2(S)        */
 /*--------------------------------------------------------------------------*/
 /* time residual:  C3*|| U - Uold ||_L^2(S)  neu aus estimator.c                               */
 /*--------------------------------------------------------------------------*/
 //dies fuer die Komponenten ohne Zeitableitung. fast clone heat_el_res. 
 /*vorher: element residual:  C0*h_S^2*||u_t -   f_h -div A nabla u^h  ||_L^2(S)        */
 /* jetzt: element residual contribution vector:  u_t -   f_h  -	div A nabla u^h  ,
 	ggf u_t = 0 wenn stationaeres Problem (u_old = u_h)      */


REAL  est_el_res_contrib::calc(/*const REAL * const lambda,*/ const int iq)
 {
   REAL            val = 0.0;
   int             i, j;
   REAL       fh_qp=0.0, order0_qp = 0.0;
 const QUAD      *elquad = quad_fast_uh->quad;

// MSG("res(u_t): %e\n",uh_qp[iq] - uh_old_qp[iq]); 
    if (prob_data_ptr->f_sources)
		  fh_qp	=	prob_data_ptr->f_sources->calc( elquad->lambda[iq]);
	 if(prob_data_ptr->order0func)
		 {order0_qp =	prob_data_ptr->order0func->calc(elquad->lambda[iq]);
		 }
     val = (uh_qp[iq] - uh_old_qp[iq]) / *timestep - fh_qp
	 /*- ist richtig, siehe S. 266,und es fehlt noch: */ 
		 + order0_qp *uh_qp[iq] ;
	prob_data_ptr->diffmat->set_at_bary( elquad->lambda[iq]);
// MSG("(f): %e\n",-prob_data_ptr->f_sources->calc( lambda)); 

//     if (D2uhqp)
   if (quad_fast_uh->bas_fcts->degree > 1)
     {REAL debug=0.0;
       if (is_diag)
       {
	 for (i = 0; i < DIM_OF_WORLD; i++)
	   val -= prob_data_ptr->diffmat->getcomp(i,i)*D2uhqp[iq][i][i];
	   debug -= prob_data_ptr->diffmat->getcomp(i,i)*D2uhqp[iq][i][i];
       }
       else
       {
	 for (i = 0; i < DIM_OF_WORLD; i++)
	   for (j = 0; j < DIM_OF_WORLD; j++)
	     val -= prob_data_ptr->diffmat->getcomp(i,j)*D2uhqp[iq][i][j];
       }
// MSG("divDgrad: %e\n",debug); 
     }
// MSG("res: %e\n",val); 

   return(val);
 }


int	est_el_res_contrib::set_at_el(const EL_INFO * const el_info, REAL eval_time)
{
   prob_data_ptr->diffmat->set_at_el(el_info, eval_time);//elementwise Initialisation
	 if(prob_data_ptr->order0func) 
	 		prob_data_ptr->order0func->set_at_el(el_info,  eval_time);
   if (prob_data_ptr->f_sources)
		  	prob_data_ptr->f_sources->set_at_el( el_info,  eval_time);
   if (quad_fast_uh->bas_fcts->degree > 1)
      D2_uh_at_qp(quad_fast_uh, el_info->el_geom_cache.Lambda, uh_el, D2uhqp);
   uh_at_qp(quad_fast_uh, uh_old_el, 	uh_old_qp);
   uh_at_qp(quad_fast_uh, uh_el,	uh_qp);
   return(0);
}

est_el_res_contrib::est_el_res_contrib(	 const BAS_FCTS   * const bas_fcts,  int degree
						,  const  REAL *const timestep)
	: prototype_fem_elfunc(bas_fcts, degree,  timestep)
{   
   D2uhqp = new REAL_DD[quad_fast_uh->n_points];
}

 /****************************************************************************/

 #if DIM > 1
 /*--------------------------------------------------------------------------*/
 /*  face residuals:  C1*h_Gamma*||[A(u_h)]||_L^2(Gamma)^2                   */
 /*  Since det_S = det_Gamma*h_Gamma we use for det_Gamma*h_Gamma the term   */
 /*  0.5(det_S + det_S')                                                     */
 /*--------------------------------------------------------------------------*/

 int ellipt_est::heat_jump_res2(const EL_INFO *el_info, int face,
			     REAL* vals,
			    REAL *valg /*estc*/)
 {
   EL_INFO        neigh_info[1];
  const EL_GEOM_CACHE *geom_cache= &el_info->el_geom_cache;
  const QUAD_FAST 	*this_wall_quad         = wall_quad_fast->quad_fast[face];
  const QUAD_FAST *neigh_wall_quad      = get_neigh_quad_fast(el_info, wall_quad_fast,
  						face);
  EL             *neigh = el_info->neigh[face];
//   int            opp_v  = el_info->opp_vertex[face];
   int            i, j,  iq;
   REAL_D         jump, jumpg; 
   REAL_D	  grd_uh_el[this_wall_quad->quad->n_points_max], grd_uh_neigh[neigh_wall_quad->quad->n_points_max]; 
   REAL_D	  Lambda_neigh[DIM+1];
   const REAL     *uh_neigh;
   REAL           det_neigh, val = 0.0, h3det;

 /*--------------------------------------------------------------------------*/
 /* orient the edge/face => same quadrature nodes from both sides!           */
 /*--------------------------------------------------------------------------*/

//   sort_face_indices(el_info->el, face, face_ind_el);
 //  sort_face_indices(neigh, opp_v, face_ind_neigh);

   neigh_info->mesh = el_info->mesh;
   neigh_info->el = neigh;
   neigh_info->fill_flag = FILL_COORDS;

  fill_neigh_el_info(el_info, face, el_info->el_geom_cache.rel_orientation[face], neigh_info);

   det_neigh = el_grd_lambda(neigh_info, Lambda_neigh);
   uh_neigh = sol_bas_fcts->get_real_vec(neigh, uh_ptr, nil);
   REAL det = 0.5*(  geom_cache->det + det_neigh);
   h3det = h2_from_det(det)*det;

 /*--------------------------------------------------------------------------*/
 /*  now eval the jump at all quadrature nodes                               */
 /*--------------------------------------------------------------------------*/

//??     lambda[face] = 0.0;
//     for (i = 0; i < DIM; i++)
 //      lambda[face_ind_el[i]] = quad->lambda[iq][i];
		//vorher     eval_grd_uh(lambda,  ass_el_data->geom_cache->Lambda, uh_el, bas_fcts, grd_uh_el);
   grd_uh_at_qp(this_wall_quad, geom_cache->Lambda, uh_el, grd_uh_el);
		//hier stand dasselbe fuern Nachbarn. Nun:
   grd_uh_at_qp(neigh_wall_quad, Lambda_neigh, uh_neigh, grd_uh_neigh);
   for (val = iq = 0; iq < this_wall_quad->n_points; iq++)
   {
	prob_data_ptr->diffmat->set_at_bary( this_wall_quad->quad->lambda[iq]);
     for (i = 0; i < DIM_OF_WORLD; i++) 
     {
	 	jumpg[i] = grd_uh_el[iq][i] - grd_uh_neigh[iq][i];
     }
     if (is_diag) 
     {
	 	for (i = 0; i < DIM_OF_WORLD; i++)
	     	jump[i] = prob_data_ptr->diffmat->getcomp(i,i)*jumpg[i];
     }
     else
     {
       for (i = 0; i < DIM_OF_WORLD; i++)
	   	for (jump[i] = j = 0; j < DIM_OF_WORLD; j++)
	       jump[i] += prob_data_ptr->diffmat->getcomp(i,j) * jumpg[j];
     }
     vals[iq] = 	h3det * SCP_DOW(jump,jump);
     valg[iq] = 	h3det * SCP_DOW(jumpg,jumpg);
   }

	return(0);
 }



 /*--------------------------------------------------------------------------*/
 /*  neuman residual:  C1*h_Gamma*||A(u_h).normal||_L^2(Gamma)^2             */
 /*  Since det_S = det_Gamma*h_Gamma we use for det_Gamma*h_Gamma the term   */
 /*  det_S                                                                   */
 /*--------------------------------------------------------------------------*/

 int ellipt_est::heat_neumann_res2(const EL_INFO *el_info, int face, 
				 REAL* vals  )
 {
  const QUAD_FAST 	*this_wall_quad         = wall_quad_fast->quad_fast[face];
   int            i, j, iq;
   REAL           /*lambda[DIM+1],*/ n_A_grd_uh;
   REAL_D         normal,  A_grd_uh;
   REAL_D	  grd_uh[this_wall_quad->quad->n_points_max] ;
//   get_wall_normal(el_info, face, normal);
  get_wall_normal_dim(DIM, el_info, face, normal);
//war vorher genau wie oben in jump_res
  grd_uh_at_qp(this_wall_quad, el_info->el_geom_cache.Lambda, uh_el, grd_uh);
   for ( iq = 0; iq < this_wall_quad->n_points; iq++)
   {
	prob_data_ptr->diffmat->set_at_bary( this_wall_quad->quad->lambda[iq]);
     	if (is_diag) 
     	{
 	      for (i = 0; i < DIM_OF_WORLD; i++)
		 A_grd_uh[i] = prob_data_ptr->diffmat->getcomp(i,i)*grd_uh[iq][i];


	}
	else
	     {
	       for (i = 0; i < DIM_OF_WORLD; i++)
		 for (A_grd_uh[i] = j = 0; j < DIM_OF_WORLD; j++)
	   		A_grd_uh[i] += prob_data_ptr->diffmat->getcomp(i,j)*grd_uh[iq][j]; 


	     }
     n_A_grd_uh = SCP_DOW(normal, A_grd_uh);
 //    val += quad->w[iq]*SQR(n_A_grd_uh);
	 vals[iq]= SQR(n_A_grd_uh);
   }
 //  return(est_data->C1*h2_from_det(ass_el_data->det)*ass_el_data->det*val);
   return(0);
 //ooch vaeinfacht gem. estimator.c
 }
 #endif

 /*--------------------------------------------------------------------------*/
int ellipt_est::set_at_el(const EL_INFO * const el_info,REAL eval_time)
{
   fill_el_geom_cache(el_info, 0U); // scheinbar noetig??
   fill_el_geom_cache(el_info, FILL_EL_DET|FILL_EL_LAMBDA);
   const_fe_space->bas_fcts->get_dof_indices(el_info->el
	               ,err_estimates[0]->fe_space->admin, dof);               //Baustelle.
   sol_bas_fcts->get_real_vec(el_info->el, uh_ptr,    uh_el);
		   //uh_old_el: das ist der einzige Unterschied zu parab_est. Damit u-u_old=0
   sol_bas_fcts->get_real_vec(el_info->el, uh_ptr, uh_old_el);
   est_el_res_contrib::set_at_el(el_info, op_arg_info->eval_time);
  return(0);
}

REAL ellipt_est::calc(/*const REAL* const lambda,*/ const int qp)
{
   REAL val = est_el_res_contrib::calc(/*lambda,*/ qp);
   return(val);
}


// void ellipt_est::el_fct(const EL_INFO *el_info)
 int ellipt_est::calc(const EL_INFO *el_info)
 {
//   EL       *el = el_info->el;
   REAL      est_el 	= 0.0;
   REAL    estc_el 	= 0.0;
   REAL    	val 	= 0.0;
 #if DIM > 1
   int      wall, iq;
   EL       *neigh;
#endif
 REAL h2	=	0.0; 
 const QUAD      *elquad = quad_fast_uh->quad;

   h2 = h2_from_det(el_info->el_geom_cache.det);

 /*---  element and time residual  ------------------------------------------*/
 

   if (C0 /*|| C3*/)
	 {val = 0.0;
		//      	 est_t_sum += heat_el_res2(el_info, lambda_det_ptr, contrib_qp);
 	 for (iq = 0; iq < quad_fast_uh->n_points; iq++)
  		 {REAL res = calc(/*elquad->lambda[iq],*/ iq);
		 val += quad_fast_uh->w[iq]*SQR(res);
		 }
	 est_el += val * C0*h2*h2*el_info->el_geom_cache.det; //alles Integration
	 }
 
   if (C3) 
   {
   REAL riq;
     for (val = iq = 0; iq < elquad->n_points; iq++)
     {
       riq = (uh_qp[iq] - uh_old_qp[iq]);
       val += elquad->w[iq]*SQR(riq);
     }
     est_t_sum += C3*el_info->el_geom_cache.det*val;
   }
 #if DIM > 1
 /*---  face residuals  -----------------------------------------------------*/
//fallen aus dem Schema der elfunc, da sie Kanten behandeln. wall_el_func schreiben?
   if (C1 || C2)
   {
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
     for (wall = 0; wall < N_NEIGH(DIM); wall++)
#else
     for (wall = 0; wall < N_NEIGH; wall++)
#endif     
     {
	 const QUAD_FAST 	*this_wall_quad         = wall_quad_fast->quad_fast[wall];

       if ((neigh = el_info->neigh[wall]))
       {
        DOF neigh_dof[1];
        const_fe_space->bas_fcts->get_dof_indices(neigh
                                       , err_estimates[0]->fe_space->admin, neigh_dof);  //Baustelle.
 /*--------------------------------------------------------------------------*/
 /*  if rw_est is nil, compute jump for both neighbouring elements           */
 /*                    only this allows correct computation of est_max       */
 /*  if rw_est is not nil, compute jump only once for each edge/face         */
 /*                    if neigh->mark: estimate not computed on neighbour!   */
 /*  contribution for the element and for neighbour: 0.5*jump!               */
 /*--------------------------------------------------------------------------*/
//	 	if (  neigh->mark)
	 	if (mark_vec[ *neigh_dof])
	 	{
	   	REAL estc =0.0;
	   	REAL est = 0.0;
      	 fill_el_geom_cache(el_info, FILL_EL_WALL_REL_ORIENTATION(wall));
      	 fill_quad_el_cache(el_info, this_wall_quad->quad,FILL_EL_DET|FILL_EL_LAMBDA/*wall_flags*/);
	 		heat_jump_res2(el_info, wall,jump_contrib_qp,jumpg_contrib_qp);
 	 		for ( iq = 0; iq < this_wall_quad->n_points; iq++)
  		 	{
				est += this_wall_quad->w[iq]*jump_contrib_qp[iq];
		 		estc += this_wall_quad->w[iq]*jumpg_contrib_qp[iq];
		 	}
	 		estc 	*= 	C2; // * h3det * valg	schon passiert
	 		est 	*=		C1;//	"
 //koennte man anders machen als element residuum, da die Funktion auch so wiederverwertet werden kann.
	   	est_el 	+= est;
	   	estc_el 	+= estc;
 /*--  if rw_est, add neighbour contribution to neigbour indicator  ---------*/

//  	  *rw_el_est(neigh)	+= est;
 // 	  *rw_el_estc(neigh)	+= estc; //s.u
        est_vec[*neigh_dof]    += est;
        est_c_vec[*neigh_dof]  += estc; //s.u
	 	}
  }
 #if DIM==3
     else if (IS_NEUMANN(el_info->edge_bound[wall]))
 #else
     else if (IS_NEUMANN(el_info->wall_bound[wall]))
 #endif
    	 {
	 		REAL est = 0.0;
	 		heat_neumann_res2(el_info, wall, jump_contrib_qp);
 	 		for ( iq = 0; iq < this_wall_quad->n_points; iq++)
		 		{est += this_wall_quad->w[iq]*jump_contrib_qp[iq];
		 		}
	 		est_el +=est * C1*h2_from_det(el_info->el_geom_cache.det)*el_info->el_geom_cache.det;
     	 }
     }
   }
 #endif

 #if DIM==1
 /*--  if rw_estc, calculate coarsening error estimate  ---------------------*/
   if (rw_estc && C2)
   {
        est_c_vec[*dof]= heat_estc_el(el_info, (void *) Lambda,
					       det, est_data);
   }
 #endif
 /*--  immer! write indicator to element  -------------------------------*/
//   	  *rw_el_est(el)	+= est_el; //vorher = und nicht +=, denn es stand ja schon was
 // 	  *rw_el_estc(el)	+= estc_el;//dito
       est_vec[*dof]  	+= est_el;
        est_c_vec[*dof]	+= estc_el; //s.u

//MSG("estc_el: %g \n", estc_el); //Baustelle debug

 /*--  if rw_est, write indicator to element  -------------------------------*/
   //if (heat_data->rw_est) 
 //	*(rw_el_est)(el) = est_el; war ne Altlast...
 // wat is mit estc??
   est_sum +=  est_vec[*dof];//get_el_est(el);                                  //est_el;
   est_max = MAX(est_max, est_vec[*dof]);//get_el_est(el));
//wurscht   el_info->el->mark = 0; /*--- all contributions are computed!  ------------*/
	mark_vec[ *dof]=0;
   return 0;
 }

  /*--------------------------------------------------------------------------*/

 /****************************************************************************/

 /****************************************************************************/
 /****************************************************************************/

 REAL ellipt_est::estimator( ADAPT_INSTAT *adapt/*, ungut so const REAL given_time, const REAL tau*/ )
 {
   FUNCNAME("ellipt_est::estimator");
   FLAGS              fill_flag;
   clear_mark clearer;
   if (adapt)
   {
	if (adapt->strategy)
	  if(C3==0.0) 
		MSG("%s: adapt->strategy=%d, (time adaptivity on) but C3 = %e (no time est) is senseless\n",
		err_estimates[0]->name,adapt->strategy,C3 );
   }
//est_t_sum ist natuerlich nur fuer die Erben gut und hier Null.
 /*---  clear error indicators & marks (because of jump contributions)  -----------------------------*/

   traverse( const_fe_space->mesh, -1, CALL_LEAF_EL, &clearer);
//   clear_indicator(const_fe_space->mesh);
for (int comp=0; comp < ncomps; comp++ )
  {
   dof_set(0.0, err_estimates[comp]);
   if (err_c_estimates[comp])
               dof_set(0.0, err_c_estimates[comp]);
   dof_set(1, marks[comp]);
  }
   est_sum 	= est_max = est_t_sum = 0.0;
   op_arg_info->eval_time	=  *time;
	 prob_data_ptr = op_arg_infos[0]->prob_data_ptr;
	uh_ptr 	= u_h[0];			//Vorsorgemassnahme fuer Systemschaetzung
				//wird auch im Konstruktor gemacht fuer sys_line_est....
       est_vec = err_estimates[0]->vec;
       est_c_vec= err_c_estimates[0]->vec; //s.u
       mark_vec = marks[0]->vec; 
   fill_flag 	= FILL_NEIGH|FILL_COORDS|FILL_OPP_COORDS|FILL_BOUND|CALL_LEAF_EL|FILL_COORDS|
   	       FILL_EL_DET|FILL_EL_LAMBDA;
//FILL_EL_WALL_DETS
   traverse( const_fe_space->mesh, -1, fill_flag, this);
/*das geht nicht fuer Systeme. Muessen uns aufs Quadrat einigen
   est_sum   = sqrt(est_sum);
   est_t_sum = sqrt(est_t_sum);
*/
   if (adapt)
   {
     adapt->adapt_space->err_sum += est_sum;	// geaendert 30.7 += 
     adapt->adapt_space->err_max = MAX(est_max, adapt->adapt_space->err_max);
 /*     adapt->err_t = est_data->est_t_sum; */
   }

   return(est_t_sum);
 }

void ellipt_est::get_C(const char *const name)
{FUNCNAME("get_C");
  char  key[128];
	REAL C[4] = {-1.0, -1.0, -1.0, -1.0};
	for (int i=0; i<4; i++)
		{
		sprintf(key, "%s estimator C%d", name,i);
    		GET_PARAMETER(1, key /*"phase estimator C0"*/, "%f", &C[i]);
		}
     C0    = C[0] > 1.e-25 ? SQR(C[0]) : 0.0;
     C1    = C[1] > 1.e-25 ? SQR(C[1]) : 0.0;
     C2    = C[2] > 1.e-25 ? SQR(C[2]) : 0.0;
//     C3    = C[3] > 1.e-25 ? SQR(C[3]) : 0.0; macht keinen Sinn fuer ellipt_est
}
int	ellipt_est::common_construct_func(int quad_degree)
{
  FLAGS              fill_flag;
   const WALL_QUAD *wall_quad = NULL;
  int uh_size_el=0, uh_size_qp=0,uh_size_max=0;

   quad	= get_quadrature(u_h[0]->fe_space->bas_fcts->dim, quad_degree);
  for (int row_comp =0; row_comp<ncomps; row_comp++)
  {
   	if (u_h[row_comp]->fe_space->bas_fcts->degree > 1)
   	  fill_flag = INIT_PHI|INIT_GRD_PHI|INIT_D2_PHI| FILL_EL_QUAD_LAMBDA;
   	else
     	fill_flag = INIT_PHI|INIT_GRD_PHI| FILL_EL_QUAD_LAMBDA;
	quad_fasts[row_comp] 
	   	= get_quad_fast(u_h[row_comp]->fe_space->bas_fcts, quad , fill_flag);//fuer Elemente
	uh_size_el 	+= 	u_h[row_comp]->fe_space->bas_fcts->n_bas_fcts;
	uh_size_max	= MAX(uh_size_max,u_h[row_comp]->fe_space->bas_fcts->n_bas_fcts);
	uh_size_qp 	+= quad_fasts[row_comp]->n_points;
   }

 #if DIM > 1
//  if (degree < 0) degree = 2*u_h[0]->fe_space->bas_fcts->degree;
    get_vertex_admin(u_h[0]->fe_space->mesh, ADM_PERIODIC);
      wall_quad = get_wall_quad(DIM, quad_degree);
    wall_quad_fast =
      get_wall_quad_fast(u_h[0]->fe_space->bas_fcts, wall_quad,
			 INIT_GRD_PHI|INIT_UH);
	uh_ptr 	= u_h[0];
 jump_contrib_qp =	new REAL[ wall_quad->n_points_max];
 jumpg_contrib_qp=	new REAL[ wall_quad->n_points_max];
 #endif

    uh_el    	=   new REAL[uh_size_el];
    uh_old_el   = 	new REAL[uh_size_el];
 
   uh_qp	= new REAL[uh_size_qp];
   uh_old_qp	= new REAL[uh_size_qp];
   return 0;
}

 ellipt_est::ellipt_est(const char *const name, const fem_base* discrete_prob
 			, const  REAL *const timestep,int degree)
	 :
	    	est(discrete_prob/*, degree, time,timestep*/),
	 	est_el_res_contrib(u_h[0]->fe_space->bas_fcts, degree
					,  timestep),
		quad_fasts( 	new const QUAD_FAST* [ncomps]),
		C0(1.0), C1(1.0), C2(1.0), C3(0.0)
	 {
   FUNCNAME("ellipt_est constructor");

   char  key[128];
  int max_degree	=0;
//  int uh_size_el=0, uh_size_qp=0,uh_size_max=0;
    TEST_EXIT(const_fe_space,"no const_fe_space\n");
    get_C(name);
	 prob_data_ptr = op_arg_infos[0]->prob_data_ptr;
  for (int i =0; i < ncomps; i++)
  {
       sprintf(key, "%s%02d_est_h",name,i);
       err_estimates[i] = get_dof_real_vec(key, const_fe_space);
       dof_set(0.0,err_estimates[i]);
       sprintf(key, "%s%02d_estc_h",name,i);
       err_c_estimates[i] = get_dof_real_vec(key, const_fe_space);
       dof_set(0.0,err_c_estimates[i]);
       sprintf(key, "%s%02d_mark",name,i);
       max_degree = MAX(u_h[i]->fe_space->bas_fcts->degree, max_degree);
       marks[i] = get_dof_int_vec(key, const_fe_space);
       dof_set(0,marks[i]);
   } 

   if (degree < max_degree+2)		//vorher 2*max_degree.
   {
	 degree = max_degree+2;		//diskutabel
	 MSG("est quad degree reset to %d\n", degree);
   }
   common_construct_func(degree);
}

//fuer line_est_ptr
 ellipt_est::ellipt_est(const char *const name, const fem_base* discrete_prob,
                         DOF_REAL_VEC *  * const err_ests,
                         DOF_REAL_VEC *  * const err_c_ests,
                         const REAL * const timestep, REAL C[4], int degree)
        :      est(discrete_prob, err_ests, err_c_ests),
		est_el_res_contrib(u_h[0]->fe_space->bas_fcts, degree,  timestep),
		quad_fasts( 	new const QUAD_FAST* [ncomps]), //1 normal
	     C0(C[0]), C1(C[1]), C2(C[2]), C3(C[3])

{
   FUNCNAME("ellipt_est constructor");
   char  key[128];
   int max_degree	=0;
    TEST_EXIT(const_fe_space,"no const_fe_space\n");
 //  sprintf(key, "%s_est_h",name);
  for (int i =0; i < ncomps; i++)
  {
       max_degree = MAX(u_h[i]->fe_space->bas_fcts->degree, max_degree);
       sprintf(key, "%s%02d_mark",name,i);
       marks[i] = get_dof_int_vec(key, const_fe_space);
       dof_set(0,marks[i]);
   } 
  if (degree < max_degree+2)		//vorher 2*max_degree.
   {
	 degree = max_degree+2;		//diskutabel
	 MSG("est quad degree reset to %d\n", degree);
   }
 prob_data_ptr = op_arg_infos[0]->prob_data_ptr;
   common_construct_func(degree);

 }

