 /****************************************************************************/
/* ALBERT:   an Adaptive multi Level finite element toolbox using           */
/*           Bisectioning refinement and Error control by Residual          */
/*           Techniques                                                     */
/****************************************************************************/
/*        authors: Alfred Schmidt and Kunibert G. Siebert                   */
/*                 Institut f"ur Angewandte Mathematik                      */
/*                 Albert-Ludwigs-Universit"at Freiburg                     */
/*                 Hermann-Herder-Str. 10                                   */
/*                 79104 Freiburg                                           */
/*                 Germany                                                  */
/*                                                                          */
/*        email:   alfred,kunibert@mathematik.uni-freiburg.de               */
/*                                                                          */
/*     (c) by A. Schmidt and K.G. Siebert (1996-2000)                       */
/****************************************************************************/

/*Aus Klonkopie von phase_real_sys entstanden. */

#include <alberta.h>
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
# include "alberta1_wrapper.h"
#endif

#include "newalberta.hh"
//#include "phase_elast.hh"
//#include "PE_diff.hh" 
#include "do_on_el.hh"
#include "do_elfunc_on_el.hh"
//#include "public_do_elfunc_on_el.hh"
#include "traverse.hh"
#include "prototype_fem_elfunc.hh"
#include "fem_elfunc.hh"
#include "fem_base.hh"
#include "est.hh"
#include "ellipt_est.hh"
#include "parab_est.hh"
#include "sys_est.hh"
#include "build_stat.hh"
#include "build_diff.hh"
#include "build_sys.hh"
//#include "oem.h"mal sehen
#include "solve_multiphase.h"
#include "operator_parts.hh"
#include "elast_problem.hh"  
/*wegen DIM,prob_datas_elast. Wir verfahren hier anders als bei heat, die
Instanziierung mehrerer Saetze von Phasenfeldern ist sehr unwahrscheinlich, deshalb
vorlaeufig prob_datas_elast global.*/
#include "master.hh"
#include "adapt.hh"	//fuer okmarking
#include "error_c.h"
#include "th_strain_rhs.hh"
//#include "phase.hh" lieber trennen... thermische dehnung ist mehr als genug zum testen
#include "heat.hh"
#define _LOCALDEBUG_  
//nur zum debuggen
#include "graphics.hh"

//static const int 
//#define DIM erstmal schon in phase_problem.hh
extern ADAPT_INSTAT   *adapt_elast;
static const FE_SPACE *fe_space=nil;
//in phase_problem.hh: extern const  PROB_DATA_DIFF* const (prob_datas_elast)[DIM*(DIM+1)/2];
static const  PROB_DATA_DIFF*  (prob_datas_elast)[DIM*DIM];
//static build_stat *build_elast[DIM*DIM]={nil};
static build_sys 	*build_elast={nil};//     
static sys_est 	*est_elast ={nil};
static DOF_REAL_VEC*   u_h[DIM];
static DOF_REAL_VEC*   uh_old[DIM];
static DOF_REAL_VEC*   f_h[DIM];
static DOF_MATRIX*     mat_phase[DIM*DIM];
static DOF_SCHAR_VEC*  bound_vec[DIM];

static DOF_REAL_VEC const *  uh_estimate[DIM];
static DOF_REAL_VEC   *dudt[DIM];            /* holds    lambda dt phase */

static DOF_REAL_VEC *  stress=nil;
static fem_elfunc* 	rhs_el_fct; //brauchen wir ausserhalb von build_elast

/*static immer gut zum debuggen*/ void close_timestep(MESH *mesh, ADAPT_INSTAT *adapt);

static REAL err_L2=0.0, err_H1=0.0;
/****************************************************************************/
/****************************************************************************/

const DOF_REAL_VEC *const * const get_deformation(void)
{
  return((const DOF_REAL_VEC  * const *const)u_h);
}

const DOF_REAL_VEC *const * const get_uh_old(void)
{
  return((const DOF_REAL_VEC  * const *const)uh_old);
}

 
 
/*Punktweise Stress-Berechnung. Das polynomiale test-Problem ohne Mittelung ueber die Elenmente zeigt ein
merkwuerdig pickeliges Bild. Es ist aber alles auf Herz und nieren getestet u die Pickel kommen wohl von
der mangelnden Mittelung.*/

static void stress_assemble()
{
  FUNCNAME("stress_assemble");
  TRAVERSE_STACK *stack;
  const EL_INFO    *el_info; /*meins*/
  const DOF      *dof;
  static REAL    deformTensor[DIM_OF_WORLD][DIM_OF_WORLD];
  static REAL    stressTensor[DIM_OF_WORLD][DIM_OF_WORLD];
  REAL           s=0.0, trace=0.0, trace_s=0.0,  c1=0.0, c2=0.0,nr_of_els=0;
  int            i=0,j=0,k=0;
  REAL           lambda=0.0, mu=0.0,  fac=0.0, *lagrangenodes;
  static const BAS_FCTS *bas_fcts=fe_space->bas_fcts;
  static const  int       n_phi= bas_fcts->n_bas_fcts;
  static const  int       dim = bas_fcts->dim;
  static const DOF  *(*get_dof)(const EL *, const DOF_ADMIN *, DOF *) 
  					= bas_fcts->get_dof_indices;
  static const REAL *(*get_real_vec)(const EL *, const DOF_REAL_VEC *, REAL *) 
  					= bas_fcts->get_real_vec;
  REAL   	u_loc[n_phi];
  REAL  grd_u[dim*n_phi];
  static    DOF_REAL_VEC *nr_of_surrounding_els = get_dof_real_vec("nr_of_surrounding_els", fe_space);
  static    DOF_REAL_VEC *strain[DIM_OF_WORLD*(DIM_OF_WORLD+1)/2];
  static    DOF_REAL_VEC *stresstensor[DIM_OF_WORLD*(DIM_OF_WORLD+1)/2];
/*f. oberflachenintegral der anliegenden Kraefte (zur kontrolle)*/
/*	REAL_D normal;
	REAL_D bound_stress;
	REAL_D normal_stress;
	REAL_D stress_int;
    static FILE *file_int=nil;
*/  const WALL_QUAD     *wall_quad=nil;
  /*brauchen lagrange-Bas-fcts. Weiss aber nicht, wie das abzufragen ist.*/
//  dof_set(0.0, stress);
  
//  TEST_EXIT(N_MESHES == 1,"not yet for N_MESHES > 1\n");
	if (fe_space->bas_fcts->degree > 2)  MSG("untested  for u->degree = %d\n", fe_space->bas_fcts->degree);
/*strain-Komponenten zum Zeichnen*/
	   	dof_set(0.0,nr_of_surrounding_els );
  for (i=0;i<dim*(dim+1)/2;i++)
		{if (!strain[i])
			{char name[15];
			sprintf(name,"%s%d","strain",i);
			strain[i] = get_dof_real_vec(name, fe_space);
			strain[i]->refine_interpol = bas_fcts->real_refine_inter;
	   		strain[i]->coarse_restrict = bas_fcts->real_coarse_inter;
			sprintf(name,"%s%d","stress",i);
			stresstensor[i] = get_dof_real_vec(name, fe_space);
			stresstensor[i]->refine_interpol = bas_fcts->real_refine_inter;
	   		stresstensor[i]->coarse_restrict = bas_fcts->real_coarse_inter;
			}
	   	dof_set(0.0, strain[i]);
	   	dof_set(0.0, stresstensor[i]);
		}
    wall_quad 		= get_wall_quad(DIM, 2*bas_fcts->degree);
    /* wahrsch. unnoetig wall_quad_fast =
      		get_wall_quad_fast(u_h[0]->fe_space->bas_fcts, wall_quad,
							 INIT_GRD_PHI|INIT_UH);
	*/
  lambda = prob_data_s11.physconstants[LAMBDA]*prob_data_s11.physconstants[MU_LAMBDA_SCALE]; // prob_data->lambda * prob_data->mu_lambda_scale;
  mu     = prob_data_s11.physconstants[MU]*prob_data_s11.physconstants[MU_LAMBDA_SCALE]; //prob_data->mu     * prob_data->mu_lambda_scale;
//scale im Original da

  stack = get_traverse_stack();
  el_info = traverse_first(stack, fe_space->mesh, -1,
			   CALL_LEAF_EL|FILL_COORDS|FILL_BOUND);
  while (el_info)
    { 
   	fill_el_geom_cache(el_info, FILL_EL_DET|FILL_EL_LAMBDA);	//ahem... hier ist  das Agument const wie oben
	if (rhs_el_fct) rhs_el_fct->set_at_el(el_info, nil);
	dof = (*get_dof)(el_info->el, fe_space->admin, nil);

 /*brauchen lagrange-Bas-fcts. Weiss aber nicht, wie das abzufragen ist.*/
  	lagrangenodes=(REAL *)(bas_fcts->bas_fcts_data); /*ist tasaechlich ein 1x... -Vektor u keine Dim+1x...Matrix*/

	for (k=0;k<n_phi; k++)
		{
/*		MSG("lagrangenodes:	%f, %f, %f\n",lagrangenodes[(DIM+1)*k],lagrangenodes[(DIM+1)*k+1],lagrangenodes[(DIM+1)*k+2]);
		MSG("grd_u: %f, %f, %f, %f \n",grd_u[0][0],grd_u[0][1],grd_u[1][0],grd_u[1][1]);
*/      	trace=0.0;
		/*grd_u[i][j]= d_xi uj*/ 
     		for (i=0; i< dim; i++) 
		{
			 get_real_vec(el_info->el, u_h[i], u_loc);
			eval_grd_uh(&lagrangenodes[(dim +1)*k] ,
				el_info->el_geom_cache.Lambda,(const REAL *) u_loc, bas_fcts, &grd_u[i*dim] ); 
//			deformTensor[i][i] = grd_u[i][i];
			deformTensor[i][i] = grd_u[i*dim + i];
			for (j=0; j<i; j++) 
				{
	  			deformTensor[i][j] = deformTensor[j][i] = 
	    			0.5*(grd_u[i*dim + j] + grd_u[j*dim + i]);
//	    			0.5*(grd_u[i][j] + grd_u[j][i]);
				}
			trace += deformTensor[i][i];
      		} /*das ist also vollstaendiger Verzerrungstensor incl therm. u. Dichteeinfluss*/

//      	aus  = 1.0 - ph_at_el[k] - mh_at_el[k];
 //     	fac1 = prob_data->elast_rhs_th(th_at_phik, aus, ph_at_phik, mh_at_el[k]);
//    	fac2 = prob_data->elast_rhs_rho(th_at_phik, aus, ph_at_phik, mh_at_el[k]);
//      	fac = (3*lambda+2*mu)*(fac1 + fac2/3.0);
	 /*Baustelle. Kontrolle ob sachlich richtig. Scheint ok zu sein. Getestet mit Problem 8 u 7.*/
	if (rhs_el_fct) fac = rhs_el_fct->calc((const REAL*const)&lagrangenodes[k*(dim+1)]);
#if 1
//both ways should bear same result
      	c1 = 2 * mu;
      	c2 = lambda * trace - fac;
/* 		MSG("fac,trace : %e, %e , lambda: %e \n", fac,trace,lambda);
 		MSG("c2: %e, lambda: %e,\n", c2,lambda);
*/      	trace_s = 0.0;
      
      	for (i=0; i<DIM_OF_WORLD; i++) 
			{
			for (j=0; j<DIM_OF_WORLD; j++) 
				{
	  			stressTensor[i][j] = c1 * deformTensor[i][j];
				}
			stressTensor[i][i] += c2;
			trace_s += stressTensor[i][i];
      	}
#else
//it should be like this :(still wrong)
     	for (int s_row=0; s_row< dim; s_row++) //tension row
	{
		for (int s_col=0; s_col<=s_row; s_col++) //dx_j
		{
			stressTensor[s_row][s_col] =0.0;
			for (int e_row=0; e_row<dim; e_row++) 
			{
				for (int e_col=0; e_col<dim; e_col++) 
				{
				REAL elasticpart;
				if (e_row==e_col) 	elasticpart = deformTensor[e_row][e_row] -fac;
				else 		elasticpart = deformTensor[e_row][e_col];
				stressTensor[s_row][s_col] 
					= (prob_datas_elast)[s_row*dim+e_row]->diffmat->getcomp(s_col,e_col) *
				elasticpart;
				}
			}
			stressTensor[s_row][s_col] *=prob_data_s11.physconstants[MU_LAMBDA_SCALE];
	  		stressTensor[s_col][s_row] = stressTensor[s_row][s_col]; 
		
		}
	trace_s += stressTensor[i][i];
	}

#endif
         s = 0.0;
     for (i=0; i<DIM_OF_WORLD; i++) 
		{
		for (j=0; j<DIM_OF_WORLD; j++) 
			{
	  		s += SQR(stressTensor[i][j]);//nicht von Mises!
			}
		}
	/* mitteln ueber alle Elemente, die an einen Knoten grenzen. */
	nr_of_surrounding_els->vec[dof[k]]+=1.0;
	stress->vec[dof[k]] += s;
#if DIM_OF_WORLD==2
     strain[0]->vec[dof[k]]+=deformTensor[0][0];
     strain[1]->vec[dof[k]]+=deformTensor[0][1];
     strain[2]->vec[dof[k]]+=deformTensor[1][1];
#else 
#if DIM_OF_WORLD==3
     strain[0]->vec[dof[k]]+=deformTensor[0][0];
     strain[1]->vec[dof[k]]+=deformTensor[0][1];
     strain[2]->vec[dof[k]]+=deformTensor[0][2];
     strain[3]->vec[dof[k]]+=deformTensor[1][1];
     strain[4]->vec[dof[k]]+=deformTensor[1][2];
     strain[5]->vec[dof[k]]+=deformTensor[2][2];
#endif
#endif
#if DIM_OF_WORLD==2
     stresstensor[0]->vec[dof[k]]+=stressTensor[0][0];
     stresstensor[1]->vec[dof[k]]+=stressTensor[0][1];
     stresstensor[2]->vec[dof[k]]+=stressTensor[1][1];
#else 
#if DIM_OF_WORLD==3
     stresstensor[0]->vec[dof[k]]+=stressTensor[0][0];
     stresstensor[1]->vec[dof[k]]+=stressTensor[0][1];
     stresstensor[2]->vec[dof[k]]+=stressTensor[0][2];
    	stresstensor[3]->vec[dof[k]]+=stressTensor[1][1];
    	stresstensor[4]->vec[dof[k]]+=stressTensor[1][2];
    	stresstensor[5]->vec[dof[k]]+=stressTensor[2][2];
#endif
#endif
	}/*ende schleife Knoten  k*/
    el_info = traverse_next(stack, el_info);
  }
  free_traverse_stack(stack);
/*Mittelung*/
 FOR_ALL_DOFS( fe_space->admin,
		nr_of_els=nr_of_surrounding_els->vec[dof];
	stress->vec[dof]/=nr_of_els;
	stress->vec[dof] =sqrt(stress->vec[dof]);//neu-vergessen? 
  for (i=0; i<dim*(dim+1)/2; i++)
  {
     strain[i]->vec[dof]/=nr_of_els;
     stresstensor[i]->vec[dof]/=nr_of_els;
  }
	);
/*
  for (k=0; k<N_NEIGH; k++) 
	{  
      if (el_info->boundary[k] && (el_info->boundary[k]->bound <= NEUMANN)) 
		{
		bound_int_d(el_info,  stresstensor, stress_int , k, wall_quad,
			 /*u_h->fe_space*/
/* bas_fcts, n_phi, dof);
		}
	}


 */
#if 0
  MSG("sigmaxx after multi mesh traverse:\n");
  print_dof_real_vec(stresstensor[0]);
  MSG("sigmaxy after multi mesh traverse:\n");
  print_dof_real_vec(stresstensor[1]);
  MSG("sigmayy after multi mesh traverse:\n");
  print_dof_real_vec(stresstensor[2]);
#endif
}
const DOF_REAL_VEC *const get_stress(void)
{
/* Initialisierung war auskommentiert. Erlaube mir, sie einzusetzen*/
 FUNCNAME("get_stress");
  if (!stress)
        {
	 const FE_SPACE *fe_space=build_elast->get_sol()->fe_space;

	MSG("called and initialized with zeros\n");
        stress = get_dof_real_vec("stress", fe_space);
        stress->refine_interpol = fe_space->bas_fcts->real_refine_inter;
        stress->coarse_restrict = fe_space->bas_fcts->real_coarse_inter;
        dof_set(0.0, stress);
        } //Baustelle (bez. fe_space)
  return((const DOF_REAL_VEC *const)stress);
}

 void calc_stress()
{
  FUNCNAME("calc_stress");
  REAL   norm;
 /*Initialisierung: stress = So gehts nicht wegen const*/
  get_stress(); 
  stress_assemble( ); /* stress damals norm und projektionsmatrix */
// valgrind mekkert: enthaelt stress sinnvolles? EP
   //  MSG("min and max stress: %e %e\n", dof_min(stress), dof_max(stress));
}

const DOF_REAL_VEC *const * const get_dudt(void)
{
  return((const DOF_REAL_VEC  * const *const)dudt);
}

const DOF_REAL_VEC *const  * const get_uh_estimate(void) 
{
  return(/*(const DOF_REAL_VEC * const *const)*/uh_estimate);
}
/****************************************************************************/
/****************************************************************************/


/****************************************************************************/
/* init_dof_admin(): init DOFs for Lagrange elements of order               */
/*                   <polynomial degree>, called by GET_MESH()              */
/****************************************************************************/

void init_elast_dof_admin(MESH *mesh)
{
  FUNCNAME("init_elast_dof_admin");
  int             degree = 1;
  const BAS_FCTS  *lagrange;
  GET_PARAMETER(1, "elast polynomial degree", "%d", &degree);
  FLAGS periodic = 0U, flag = 0U;
  GET_PARAMETER(2, "periodic", "%d", &periodic);
  if (periodic) 	{flag = ADM_PERIODIC ;}
	else 				{flag = 0U;}

  lagrange = get_lagrange(DIM,degree);
  TEST_EXIT(lagrange,"no lagrange BAS_FCTS\n");
  fe_space = get_fe_space(mesh, lagrange->name, nil, lagrange, flag);

  return;
}

/****************************************************************************/
// der darf nur fuer Graphik sein.
static REAL get_el_est(EL *el)
{ int i; REAL out=0.0; 
  if (IS_LEAF_EL(el))
	{
      for (i=0; i<DIM; i++) {
	out += (est_elast->get_el_est)(el,i);
//		MSG("phase %d estimator: %f\n", i,out);
					};
    	return(out);
	}
  else
    return(0.0);
}


static REAL get_el_estc(EL *el)
{
  int i; REAL out=0; 
  if (IS_LEAF_EL(el))
	{
    for (i=0; i<DIM; i++) {out += *(est_elast->rw_el_estc(el,i));}
	return(out);
	}
  else
    return(0.0);
}

void 	clear_indicator_elast(MESH * mesh)
{  
     est_elast->clear_indicator( mesh);
}

/****************************************************************************/
/*  interpolation is solve on the initial grid                              */
/****************************************************************************/

static void init_elast_timestep(MESH *mesh, ADAPT_INSTAT *adapt)
{
 build_elast->init_timestep();
  return;
}


static void close_elast_timestep(MESH *mesh, ADAPT_INSTAT *adapt)
{
  FUNCNAME("close_elast_timestep");
  static REAL err_L2H1 = 0.0;
  static REAL err_LinftyL2 = 0.0;
  
  err_LinftyL2 = MAX(err_LinftyL2, err_L2);
  
  err_L2H1 += adapt->timestep * err_H1*err_H1;
  
  MSG("Elast LinftyL2 error: %.3le  L2H1 error: %.3le\n", /* total error: %.3le\n",*/
      err_LinftyL2, sqrt(err_L2H1));
//      err_LinftyL2*(1.0+sqrt((*prob_datas_elast)[0]->physconstants[SMALL] /*->relax*/))
//      + sqrt(err_L2H1 * (*prob_datas_elast)[0]->diffkoeff)); Weiss nich, was das soll
//Baustelle das is natuerlich noch mist....
//debugging: Nuetzlich
//	graphics(mesh, nil, build_elast->get_rhs(0),  nil,	4);  
  return;
}

/****************************************************************************/
/* build(): assemblage of the linear system: matrix, load vector,           */
/*          boundary values, called by adapt_method_stat()                  */
/*          on the first call initialize u_h, f_h, matrix and information   */
/*          for assembling the system matrix                                */
/*                                                                          */
/* struct op_info: structure for passing information from init_element() to */
/*                 LALt()                                                   */
/* init_element(): initialization on the element; calculates the            */
/*                 coordinates and |det DF_S| used by LALt; passes these    */
/*                 values to LALt via user_data,                            */
/*                 called on each element by update_matrix()                */
/* LALt():         implementation of -Lambda id Lambda^t for -Delta u,      */
/*                 called by update_matrix()                                */
/* c():            implementation of 1/tau*m(,)                             */
/****************************************************************************/
/****************************************************************************/

static void build(MESH *mesh, U_CHAR flag)
{
  FUNCNAME("build (elast)");
	int i,j, dim = mesh->dim; 
  dof_compress(mesh);
   INFO(adapt_elast->adapt_space->info, 3,
    "%d DOFs for %s\n", fe_space->admin->size_used, fe_space->name);
  for (i=0;i< dim;i++)
	{
	dof_set(0.0, build_elast->get_rhs(i));
  	}
							//noch. Baustelle
  build_elast->assemble();
  for (i=0;i<dim;i++)		
  	{
	for (j=0;j<dim; j++)
	{ 
		mat_phase[i*dim	+ j]	= build_elast->get_mat_block(i,j);
		if (adapt_elast->adapt_space->info >= 9)
		{	
			if (mat_phase[i*dim + j])
			{	MSG("Block Matrix row %d  col %d after multi mesh traverse:\n",i,j);
		 		print_dof_matrix(mat_phase[i*dim + j]);
			}
		}
	}
	if (adapt_elast->adapt_space->info >= 8)
		{
	 	print_dof_real_vec(u_h[i]);
	 	print_dof_real_vec(build_elast->get_rhs(i));
//	 	print_dof_real_vec(f_h[i]);
		}
	}
			//	 hier war viel debuggen angesagt
  return;
}

/****************************************************************************/
/* solve(): solve the linear system, called by adapt_method_stat()          */
/****************************************************************************/
/*solve_diag: this function implements solving of the coupled system with all off-diagonal matrix
 blocks multiplied with old sol and added to rhs. For testing purposes.
This now must be implemented via theta =0 !!!*/

static void solve_system(MESH *mesh)
{
  FUNCNAME("solve_system");
  static REAL        omega = 1.0;
  static int        solver=-1,i;
  static SOLVE_DATA 	    sd = {1e-8, 999, -1000, 2};
  
  build(mesh, 1);

  if (solver<0) 
  {
    solver=1;
    GET_PARAMETER(1, "elast solver", "%d", &solver);
      	GET_PARAMETER(1, "elast solver tolerance", "%f", &(sd.tolerance));
      	GET_PARAMETER(1, "elast solver max iteration", "%d", &(sd.max_iter));
      	GET_PARAMETER(1, "elast solver info", "%d", &(sd.info));
      	GET_PARAMETER(1, "elast solver omega", "%f", &omega);
  }


  if (solver) 
	cg_multi(&sd, DIM, mat_phase, f_h, u_h);

  else 
	{//TEST_EXIT(prob_data_phase->sol_ex,"neither exact sol nor solver\n"); 
//	 eval_time_ph = adapt_elast->time;
	for (i=0; i<DIM;i++)
   		{
		int diag_ind = i*DIM + i;
		if ((prob_datas_elast)[/*(i+1)*(i+2) - 1*/diag_ind ]->sol_ex) 
			interpol((prob_datas_elast)[diag_ind]->sol_ex, u_h[i]);/*ok Baustelle*/
		else MSG("heat solver switched off, but no ex_sol given\n");
		}
	}

  for (i=0; i<DIM;i++)
    {
#if 0
  print_dof_real_vec(build_elast->get_sol(i));
  print_dof_real_vec(u_h[i]);
  print_dof_matrix(build_elast[i]->get_mat(i,i));
  WAIT;
#endif
      dof_copy(	build_elast->get_sol(i), dudt[i]);/*ok Baustelle*/
      dof_axpy(-1.0, 	build_elast->get_old_sol(i),	dudt[i]);
  	 dof_scal(/*prob_data->prob_data_heat.latent_heat*/1.0/adapt_elast/*PE*/->timestep, dudt[i]);
    }/*Baustelle, die Zeiten muessen gesetzt sein!!!!*/
    return;
}

static void interpol0(MESH *mesh)
{   FUNCNAME("interpol0 (elast)");
 //interpol(prob_data_heat->sol_0,base_heat->get_sol() );
 int i,j,n;
	dof_compress(mesh);
  TEST_EXIT(fe_space,"no fe_space yet\n");
  TEST_EXIT(fe_space->mesh,"no fe_space->mesh yet\n");
    n =fe_space->bas_fcts->n_bas_fcts;
  for (i=0; i<DIM; i++)
    {
		dof_set(0.0,build_elast->get_sol(i));
		dof_set(0.0,build_elast->get_old_sol(i));
    }
  for (j=0; j<DIM; j++)
 {
	if ((prob_datas_elast)[j*DIM + j]->sol_0)
	{
		MSG("(prob_datas_elast)[...]->sol_0 will be used\n");
		interpol((prob_datas_elast)[j*DIM + j]->sol_0,build_elast->get_sol(j));
	}
	else ERROR("No prob_datas_elast)[%d *DIM + %d]->sol_0!\n",j,j );
  }
  if (adapt_elast->adapt_space->info >= 8)
  {
  	for (i=0; i<DIM;i++)
    {
	 	print_dof_real_vec(build_elast->get_rhs(i));
		if (adapt_elast->adapt_space->info >= 9)
  		for ( j=0; j<DIM; j++)
			print_dof_matrix(build_elast->get_mat_block(i ,j));MSG("\n");
	 }
  }

	init_elast_timestep(mesh, nil);
  INFO(adapt_elast->adapt_initial->info, 2,
	 "time:%f\n", get_time());
    return;
}

/****************************************************************************/
/* Functions for error estimate:                                            */
/* estimate():   calculates error estimate via heat_est()                   */
/*               calculates exact error also (only for test purpose),       */
/*               called by adapt_method_stat()                              */
/****************************************************************************/
//Baustelle!!
static REAL estimate_phase(MESH *mesh, ADAPT_STAT *adapt)
{
  FUNCNAME("estimate_phase");
  static int     i,degree;

  adapt_elast->adapt_space->err_sum = 0.0 ;
  adapt_elast->adapt_space->err_max = 0.0 ;
//wir werden sehen

  est_elast->clear_indicator( mesh);

  degree = 2*fe_space->bas_fcts->degree; /*Vorsicht! evtl u_h[?] nehmen*/
  err_L2 = 0.0;
  err_H1 = 0.0;
  time_est +=est_elast->estimator(adapt_elast);
  for (i=0;i<DIM;i++)
	{
//Debugging:
//  print_dof_real_vec(est_elast[i]->err_estimate);
//	graphics(mesh,  adapt_elast->adapt_space->get_el_est/*( EL *el)*/,  nil, nil,  1);
	if ((prob_datas_elast)[i*DIM + i]->sol_ex) 
		{
    		err_L2 += L2_err((prob_datas_elast)[i]->sol_ex, build_elast->get_sol(i), nil, false, false, nil, nil);
    		INFO(adapt_elast->info, 2,
      	"time=%.4le  ||u-uh||L2 = %.8le\n", adapt_elast->time, err_L2);
  		} 
	else 
		{
    		err_L2 = 0.0;
  		}
/* ersma so 
  	if ((*prob_datas_elast)[i]->grd_sol_ex) 
		{
    		err_H1 += H1_err((*prob_datas_elast)[i]->grd_sol_ex,build_elast[i]->get_sol(), nil, 0, nil, nil);
  		} 
	else 
	{
    err_H1 = 0.0;*/
  }

  INFO(adapt_elast->info, 2,
    "time=%.4le,  adapt_space->: err_sum^2  = %.8le, tolerance = %.8le  max^2=%.3le\n", adapt_elast->time, 
     adapt_elast->adapt_space->err_sum,adapt_elast->adapt_space->tolerance, adapt_elast->adapt_space->err_max);
  INFO(adapt_elast->info, 2,"time est: %8le\n", time_est);
  return(adapt_elast->adapt_space->err_sum);
}

/****************************************************************************/
#if 0
static REAL est_initial_phase(MESH *mesh, ADAPT_STAT *adapt)
{
  FUNCNAME("est_initial_phase");
  static REAL C = -1.0;
  
  if (C < 0.0) {
    C = 1.0;
    GET_PARAMETER(1, "elast estimator C0", "%f", &C);
  }
  
  adapt->err_sum = L2_err_c(prob_data_phase->sol_0, u_h[0],
			    nil, rw_el_est, &adapt->err_max,
			    C * sqrt(prob_data_phase->physconstants[SMALL]));
/*Baustelle. Evtl rausschmeissen u mehrmals f. Zeitschrittweite 0 loesen.   u_h[0] kann evtl falsch werden*/
  MSG("L2_err = %.3le\n", adapt->err_sum);
  
  return(adapt->err_sum);
}
#endif
/****************************************************************************/

void init_elast(ADAPT_INSTAT *adapt_elast, const fem_elfunc* rhs_el_func_ptr,
	const  PROB_DATA_DIFF* const (*prob_datas_elast_ptr)[DIM*DIM])
{
  FUNCNAME("init_elast");
  int            i,j=0, rhs_nr=0;
  int quad_degree = 2*fe_space->bas_fcts->degree;
  char  key[128];
  REAL theta;
// public_do_elfunc_on_el* 	
 rhs_el_fct = (fem_elfunc*) rhs_el_func_ptr; 
   TEST_EXIT(adapt_elast,"no adapt_elast\n");
  TEST_EXIT((*prob_datas_elast_ptr),"surely no prob_datas_elast\n");
  GET_PARAMETER(1, "parameter theta", "%e", &theta);
  if (theta < 0.5)
  {
    WARNING("You are using the explicit Euler scheme\n");
    WARNING("Use a sufficiently small time step size!!!\n");
  }

 for (i=0;i<DIM;i++)//Zeile
 {
   for (j=0;j<DIM;j++) 
  	{ prob_datas_elast[i*DIM + j] = (*prob_datas_elast_ptr)[i*DIM + j]; 
  	TEST_EXIT(prob_datas_elast[i*DIM + j],"no prob_datas_elast[%d]\n",i*DIM + j);
			MSG("elast %d %d diffcoeff[0][0]: %f, [0][1]: %f\n",i,j, (* prob_datas_elast_ptr)[i*DIM+j]->diffmat->getcomp(0,0),
					(* prob_datas_elast_ptr)[i*DIM+j]->diffmat->getcomp(0,1) );
	}
   sprintf(key, "u_h%d",i);
   u_h[i] 	= get_dof_real_vec(key, fe_space);
   sprintf(key, "ef_h%d",i);
   f_h[i]	= get_dof_real_vec(key, fe_space);
   sprintf(key, "uh_old%d",i);
   uh_old[i] 	= get_dof_real_vec(key, fe_space);
   sprintf(key, "uh_bound%d", i);
   bound_vec[i]  = get_dof_schar_vec(key, fe_space);
   sprintf(key, "dudt%d",i);
   dudt[i] 	= get_dof_real_vec(key, fe_space);
   dudt[i]->refine_interpol = u_h[i]->refine_interpol 	= f_h[i]->refine_interpol 	= uh_old[i]->refine_interpol 
  				= fe_space->bas_fcts->real_refine_inter;
   dudt[i]->coarse_restrict = u_h[i]->coarse_restrict 	= f_h[i]->coarse_restrict 	= uh_old[i]->coarse_restrict
  				= fe_space->bas_fcts->real_coarse_inter;
   dof_set(0.0, dudt[i]);
  
 }
  build_elast	= new build_sys("u_h",  u_h, uh_old, bound_vec
			 , f_h //eigentlich Bloedsinn!
			,  prob_datas_elast
			,rhs_el_fct
			,DIM, -1// quad_degree
			,&(adapt_elast->time), &(adapt_elast->timestep),theta);
 est_elast= new sys_est("uh", build_elast, 
				 &(adapt_elast->time), &(adapt_elast->timestep), /*int degree*/-1);
 for (i=0;i<DIM;i++)//Zeile
	{
	uh_estimate[i] = est_elast->get_err_estimate(i);
	}

 adapt_elast->set_time  = set_time;	//in master.cc

 adapt_elast->init_timestep  = init_elast_timestep;
  adapt_elast->close_timestep = close_elast_timestep;
/*    adapt_elast->get_time_est   = get_time_est; */

  adapt_elast->adapt_initial->solve      = interpol0;
  adapt_elast->adapt_initial->estimate   = estimate_phase; /*est_initial_phase;*/
  adapt_elast->adapt_initial->get_el_est = get_el_est;
  adapt_elast->adapt_initial->marking =	okmarking; /* wrapper, adapt.c Standard. */

//    adapt_elast->adapt_space->build_after_coarsen = build; geht im Allgemeinen nicht
  adapt_elast->adapt_space->solve       =solve_system;
  adapt_elast->adapt_space->estimate    = estimate_phase;
  adapt_elast->adapt_space->get_el_est  = get_el_est;  /* static in PE_phase!"*/
  adapt_elast->adapt_space->get_el_estc = get_el_estc;/* static in PE_phase !"*/
//  adapt_elast->adapt_space->marking =	okmarking; /* wrapper, adapt.c Standard. */
  return;
}
