#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 "prototype_fem_elfunc.hh"
#include "fem_elfunc.hh"
#include "traverse.hh"
#include "fem_base.hh"
#include "build_stat.hh"
#include "operator_parts.hh"

//nur wegen int dof_ApB(DOF_MATRIX A, DOF_MATRIX B, DOF_SCHAR_VEC   *bound)
//gehoert eigentlich vom logischen nich hierher, ist aber wegen der Verfuegbarkeit hier
//Matrixaddition B=B+A:
#if 0
braucht man glaub ich nicht
int dof_ApB(const DOF_MATRIX* A, DOF_MATRIX* B,const  DOF_SCHAR_VEC   *bound)
{
  	FUNCNAME("dof_ApB");
	MATRIX_ROW *rowA, *rowB;
	S_CHAR *bvec;
	int j;
// Alberta 2.0 has row and col fe spaces
//	TEST_EXIT(A->fe_space->admin == B->fe_space->admin,"A and B must be of same fe_space");//oder nur fe_space?
	bvec = bound ? bound->vec : nil; 
	FOR_ALL_DOFS
	(
	A->fe_space->admin,
	if ( !bvec || bvec[dof] < DIRICHLET) //Rand: diag. =1 in A und B. Addition waere falsch!
		{
		for (rowA = A->matrix_row[dof]; rowA; rowA = rowA->next)	
			{
			rowB = B->matrix_row[dof];
			for (j=0; j<ROW_LENGTH; j++)
				{
				if (ENTRY_USED(rowA->col[j]))//unsicher...
					{rowB->entry[j] += rowA->entry[j];
					}
				else if (rowA->col[j] == NO_MORE_ENTRIES)
					{break;
					}
				}
			}
		}
	);
	return(0);
}

 //weiss noch nich wo die Deklaration hin soll
#endif
/*this function is not state of the art of alberta2.1, but seems to work.
Unfortunately, Robin is the only boundary condition at the moment, no standard inhomogeneous Neumann
possible without changes*/
int build_stat::robin(const EL_INFO *el_info, const int face, S_CHAR face_bound, const REAL eval_time)
{
  FUNCNAME("robin");
  const QUAD_FAST 	*this_wall_quad         = wall_quad_fast->quad_fast[face];
  int   i, j, iq;//, i1, i2;
  const REAL 	*lambda;		//[DIM+1], 
  REAL	ec=0.0, fc=0.0, sol_ext_iq=0.0, coef=0.0;	
  const REAL *world;
  REAL  col_phi_at_qp[test_quad_fast->n_bas_fcts];
  REAL  row_phi_at_qp[sol_bas_fcts->n_bas_fcts];

  for (i = 0; i < test_quad_fast->n_bas_fcts; i++) 
  	{el_f[i] = 0.0;
    	for (j = 0; j < sol_bas_fcts->n_bas_fcts; j++)
	      	el_mat[i][j] = 0.0;
  	}
   for ( iq = 0; iq < this_wall_quad->n_points; iq++)
   {
    lambda	= this_wall_quad->quad->lambda[iq];
    world = coord_to_world(el_info, lambda, nil);
    sol_ext_iq = prob_data_ptr->g_Dirich(world,eval_time);         /*das ist externer Wert f
									Flussbedingung...*/
    coef      = prob_data_ptr->g_Neumann(world,eval_time, face_bound);
		
    for (i = 0; i < sol_bas_fcts->n_bas_fcts; i++) 
      row_phi_at_qp[i] =  sol_bas_fcts->phi[i](lambda); 
    for (i = 0; i < test_quad_fast->n_bas_fcts; i++) 
      col_phi_at_qp[i] =  test_quad_fast->phi[i][j]; 
//besser jetzt! 12.11      col_phi_at_qp[i] =  test_bas_fcts->phi[i](lambda); 
  	

    ec = this_wall_quad->quad->w[iq] * coef * el_info->el_geom_cache.wall_det[face];
    fc = ec * sol_ext_iq;

    for (i = 0; i < test_quad_fast->n_bas_fcts; i++) {
      el_f[i] += fc * col_phi_at_qp[i];
      for (j = 0/*i*/; j < sol_bas_fcts->n_bas_fcts; j++)
        el_mat[i][j] += ec * col_phi_at_qp[i] * row_phi_at_qp[j];
    }		//[j][i] ?sind hier durcheinandergekommen. Koennte verkehrt sein. Zettel? Baustelle
  }
//  for (i = 0; i < n; i++) {
//    f_vec[dof[i]] += el_f[i];
//  }
//  for (i = 0; i < n_bas_fcts; i++)
//   for (j = 0; j < i; j++)
//    el_mat[i][j] = el_mat[j][i];
  return(0);
}
#if 0
bei Bedarf neu programmieren.
keine Missions-Prioritaet
REAL build_stat::integrate_inflow(const REAL time, const REAL theta)
{
  FUNCNAME("integrate_inflow");
}

#endif
/*taktische angelegenheit:
bound = nil haengt davon ab, ob die fe_spaces gleich oder verschieden sind wegen add_el_matrix.
Also haengt die Moeglichkeit des Einbindens von Randbedingungen davon ab, ob
row_fe_space=col_fe_space.
=>	fuer den Diagonalblock eines gekoppelten Systems muesste row_fe_space=col_fe_space
gelten, was hoffentlich ok ist.
Was passiert mit Nebendiagonalbloecken bei Dirichlet-RW's ??? Kann eigentlich nicht gut gehen,
denn add_el_matrix weiss nix davon und fuellt munter die betreffende Zeile.
Vorschlag: Matrizen nach assemblierung nachbehandeln
Dies bis zur Klaerung nicht loeschen!!! Baustelle!
12.11.07: Ohne dass ich weiss wie werden die Zeilen der Nebendiagonalbloecke geloescht.
add_el_matrix weiss irgendweshalb bescheid.
Ein Schritt zur besseren Behandlung: Abhaengigkeit der boundary-Behandlung von if
(... &prob_data_ptr->g_dirichlet)	So vereinfacht man die Behandlung der offdiag-Bloecke
*/
/*only called in one-component mode (nrofcomps=1)*/
int build_stat::set_at_el(const EL_INFO * const el_info, REAL eval_time)//lambda_det_ptr)
{
	   fill_el_geom_cache(el_info, 0U); // scheinbar noetig??
//   	   fill_el_geom_cache(el_info, FILL_EL_DET|FILL_EL_LAMBDA);	//ahem... hier ist  das Agument const wie oben
	   //auch... demnach darf der Aufruf nix bewirken. 
	   //fill_el_geom_cache macht ne Typumwandlung in nichtconst...
	if (prob_data_ptr->f_sources)
		prob_data_ptr->f_sources->set_at_el(el_info, eval_time);
	if (bound)  // !bound means different fe-spaces
		GET_BOUND( test_quad_fast->bas_fcts, el_info, bound);
		//bound ist jetzt	BNDRY_FLAGS *bndry_bits	
   	sol_bas_fcts->get_dof_indices(el_info->el, 	u_h[0]->fe_space->admin, row_dof);		
      	sol_bas_fcts->get_real_vec(el_info->el, 	u_old[0], 	uh_old_el);
   	if (row_dof != col_dof)	
		test_quad_fast->bas_fcts->get_dof_indices(el_info->el
				, f_h[0]->fe_space->admin, col_dof);		
	return( fem_elfunc::set_at_el( el_info, eval_time/*&(op_arg_info->lambda_det)*/));
}

int build_stat::calc(const EL_INFO *el_info)	//el_fct(const EL_INFO *el_info)
{
  FUNCNAME("build_stat::calc");
	int i=0, j=0, wall=0;
	REAL *lagrangenodes  
	   //Vektor, keine Matrix!!
   			=(REAL *)(test_quad_fast->bas_fcts->bas_fcts_data);
    a_mat 	= 	(matrix_info->el_matrix_fct)	(el_info, matrix_info->fill_info);  //bound length n_row
    add_element_matrix(matrix, theta, test_quad_fast->n_bas_fcts,sol_bas_fcts->n_bas_fcts, row_dof, col_dof, a_mat,
    						bound); /*theta-Methode rhs_n_bas_fcts,sol_n_bas_fcts,s.u*/
    for (i = 0; i < test_quad_fast->n_bas_fcts; i++) //rhs not sol!!
	{
     	if (!bound || bound[i] < DIRICHLET) // !bound means different fe-spaces
		{
		 if (prob_data_ptr->f_sources)
			{
			REAL val = 0.0;
    			for (int j = 0; j < test_quad_fast->quad->n_points; j++) 
				{		//MSG("quad->lambda[%d]= %f\n", j,	quad->lambda[j]);
						//	MSG("lambda[%d][0]= %f,  lambda[%d][1]= %f, lambda[%d][2]= %f\n", j,	(quad->lambda[j])[0], j,
						//(quad->lambda[j])[1],j,	(quad->lambda[j])[2]);
				REAL source_at_phik 
					= prob_data_ptr->f_sources->calc( test_quad_fast->quad->lambda[j]);
					val += test_quad_fast->quad->w[j]*source_at_phik
				*test_quad_fast->phi[j][i]; //Col_phi!!
          			}
			f_vec[col_dof[i]]	+= el_info->el_geom_cache.det*val;
			}
/****************************************************************************/
/*  f += { - (1-theta)*Matrix} u_old      theta-Methode                               */
/****************************************************************************/
  		INFO(info_level,10,"f_vec[[%d]]%e\n", col_dof[i], f_vec[col_dof[i]]);
    		REAL val = 0.0;		//INFO(info_level,8,"\n a_mat[%d]: ",i);
    		for (j = 0; j < sol_bas_fcts->n_bas_fcts; j++)
    			{//INFO(info_level,8,"%g ",a_mat[i][j]);
 			val += ( -	(1.0-theta)*a_mat[i][j])*uh_old_el[j];
			}
    		f_vec[col_dof[i]] += val;
			INFO(info_level,10,"uh_old_el[%d]]%e\n",i,uh_old_el[i]);
		}
	else if (bound && bound[i] >= DIRICHLET && op_arg_info->prob_data_ptr->g_Dirich/*5.10.07*/)	// Dirichlet-Punkt
		{
			//f_vec[dof[i]]=prob_data->g_Dirich(el_info->coord[i] ,time); falsch fuer P2!!
		 REAL_D x;
		coord_to_world(el_info,&lagrangenodes[i*(DIM+1)] ,x );		//siehe oben. dashat nur sinn fuer Diagonal-Bloecke.
		f_vec[col_dof[i]]	=	u_vec[col_dof[i]]	
		 =	op_arg_info->prob_data_ptr->g_Dirich( x ,*time);
		}
	if (bound)	b_vec[col_dof[i]]	= bound[i];/* muessen uns noch Gedanken machen ueber Dirichlet-Werte fuer 
							neben-Diag-Eintraege, So ist es Falsch. Baustelle!*/
    	}

    if (op_arg_info->prob_data_ptr->g_Neumann)/*5.10.07*/
    {
#if (defined(ALBERTA_VER) && (ALBERTA_VER==2))
	for (wall = 0; wall < N_NEIGH(DIM); wall++)
#else
	for (wall = 0; wall < N_NEIGH; wall++)
#endif     
     	{ 
//alt     	if (el_info->boundary[k] && (el_info->boundary[k]->bound <= NEUMANN)) /*before <= NEUMANN */
#if (DIM > 2)
   		if (IS_NEUMANN(el_info->edge_bound[wall]))
#else	
   		if (IS_NEUMANN(el_info->wall_bound[wall]))
#endif
//alt	if (IS_NEUMANN(bound[wall]))
	      	{
	        	fill_el_geom_cache(el_info, FILL_EL_WALL_REL_ORIENTATION(wall)| FILL_EL_WALL_DET(wall));
	      		fill_quad_el_cache(el_info, wall_quad_fast->quad_fast[wall]->quad,FILL_EL_DET|FILL_EL_LAMBDA/*wall_flags*/); //ok
#if (DIM > 2)
	        	robin(el_info, wall, el_info->edge_bound[wall]//el_info->boundary[k]->bound,
              			  , op_arg_info->lambda_det.eval_time);
#else	
	        	robin(el_info, wall, el_info->wall_bound[wall]//el_info->boundary[k]->bound,
              			  , op_arg_info->eval_time);
#endif
  			add_element_matrix(matrix, 1.0, test_quad_fast->n_bas_fcts, sol_bas_fcts->n_bas_fcts,  row_dof, col_dof,
					 el_mat, bound);
					//rhs_n_bas_fcts,sol_n_bas_fcts, 	29.5. zu dokumentieren
//  		add_element_vec(f_h,  1.0, rhs_n_bas_fcts,col_dof, el_f, nil);//(*timestep): mal Zeitschrittweite
	    		for (i = 0; i < /*rhs_*/test_quad_fast->n_bas_fcts; i++) //rhs not sol!!
			{		//sollte aequivalent sein
				f_vec[col_dof[i]]	+=	el_f[i];
			}
		}
    	}
    }
 }

//build_diff
int build_stat::assemble()
{
  FUNCNAME("assemble");

  const FLAGS          fill_flag= CALL_LEAF_EL|FILL_COORDS|FILL_BOUND|FILL_NEIGH;
					//letzteres f. Robin
/****************************************************************************/
/*  init functions for matrix assembling                                    */
/****************************************************************************/
 const REAL	eval_time_f = (*time) - (1-theta)*(*timestep);
    op_arg_infos[0]->eval_time	=	eval_time_f;
 /****************************************************************************/
/*  and now assemble the matrix and right hand side                         */
/****************************************************************************/
  prob_data_ptr = op_arg_infos[0]->prob_data_ptr;
  matrix = matrix_blocks[0];
  matrix_info = &matrix_infos[0];
  clear_dof_matrix(matrix);
  f_vec	= f_h[0]->vec;
  b_vec	= bound_vec[0]->vec; //ok
  u_vec	= u_h[0]->vec;

  INFO(info_level, 5,
	"%s diffcoeff(0,0) of el 0: %g\n",matrix->name,prob_data_ptr->diffmat->getcomp(0,0)
			 );//vielleicht wieder wegschmeissen dann

  traverse(u_h[0]->fe_space->mesh, -1, fill_flag, this);
/*dirichlet_bound(g_D, fh, u_h, nil); */
  return(0);
}
#if 0
zur Erinnerung/to remember
//#define DIFFMAT_SYMMETRIC    (1 << 0)
#define DIFFMAT_PW_CONST (1 << 1)
#define LB0_SYMMETRIC    (1 << 2)
#define LB_PW_CONST (1 << 3)
#define ORDER0_PW_CONST (1 << 4)
#define MASS_CONST (1 << 5)
#define DIFFMAT_FULL    (1 << 6)
#define DIFFMAT_DIAG    (1 << 7)
#define DIFFMAT_ISOTROP    (1 << 8)
#endif
int build_stat::set_std_op_info(int row, int col)
{ 	FUNCNAME("build_stat::set_std_op_info");
	OP_ARG_INFO *oai = op_arg_infos[row*ncomps + col];
	const PROB_DATA_DIFF* prob_data_ptr =oai->prob_data_ptr; 
	memset(&op_info, 0,sizeof(OPERATOR_INFO));
	op_info.user_data 	= oai;
	op_info.row_fe_space = u_h[row]->fe_space;
	op_info.col_fe_space = f_h[col]->fe_space;
	//nach bestem Wissen, aber nicht ausprobiert. Baustelle
	//wuerd  sagen: row - vektor x, column vektor rhs
	if (!(prob_data_ptr->diffmat || prob_data_ptr->order0func))
	{
		MSG("No op_arg_info[%d*ncomps + %d]->prob_data_ptr->... any operator\n",row,col);
		return(1);
	}
	op_info.init_element 	= &init_element;
	op_info.quad[2] = op_info.quad[0] = quad; //test_quad_fasts[row]->quad;	//get_quadrature(DIM, 2*fe_space->bas_fcts->degree);
	/*I think that all components should have equal integration formula degree*/
	//Grad row_fe_space + col_fe_space - 2 waere ok f. quad[2]
	if (prob_data_ptr->diffmat )
	{
//		op_info.LALt 	= 	LALt; // geaendert 24.9. wg elast. Harrt konzept.
//saubere Loesung:
		if (prob_data_ptr->flags &  DIFFMAT_ISOTROP)
		{
			op_info.LALt 	= 	LALt; 
			op_info.LALt_symmetric		= true;
		}	
		else if (prob_data_ptr->flags &  DIFFMAT_DIAG)
		{
			op_info.LALt 		= LALtdiag; 
			op_info.LALt_symmetric	= true;
		}
		else if (prob_data_ptr->flags &  DIFFMAT_FULL)
		{
			op_info.LALt 		= LALtfull; 
			op_info.LALt_symmetric	= false;
		}
		else
		{	MSG("Blockmatrix %d, %d: No diffmat properties speciefied\n", row,col);
			ERROR_EXIT("Set prob_data.flag to one of DIFFMAT_ISOTROP,DIFFMAT_DIAG,DIFFMAT_FULL\n");
		}
		if (prob_data_ptr->flags &  DIFFMAT_PW_CONST)
				op_info.LALt_pw_const	= true;
	}
	else
	{
		MSG("No op_arg_info[%d*ncomps + %d]->prob_data_ptr->diffmat\n",row,col);
//		return(1);
	}
//TODO: Baustelle
	op_info.Lb0		= nil;
	op_info.Lb1		= nil;
	if (prob_data_ptr->order0func)
	{
		op_info.c	=	c_std;
		if (prob_data_ptr->flags & ORDER0_PW_CONST)
		{
			op_info.c_pw_const	= true;
		} 
	}
	if (row==col)
		op_info.use_get_bound	= true;//false;//true;//keine Wirkung...
	else
		op_info.use_get_bound	= false;
	op_info.fill_flag		= CALL_LEAF_EL|FILL_COORDS|FILL_BOUND|FILL_NEIGH;

//debug			op_info.LALt_symmetric	= true;
	return(0);
} //und viell. noch einen f. spezielle ops


int build_stat::common_construct_func(const char *const name, const int quad_degree)
{ 
 FUNCNAME("build_stat common_construct_func");
  char  key[128];
  int  row_comp = 0, col_comp = 0, outcome=0, i=0;
  int sol_size_el=0, rhs_size_el=0, sol_size_max=0, rhs_size_max=0;
  const WALL_QUAD *wall_quad = NULL;
  FLAGS              fill_flag;
   /* if (!quad) Unsinn!*/
    quad=  get_quadrature(u_h[0]->fe_space->mesh->dim, quad_degree);
    			/* We need vertex indices to orient walls. */
    get_vertex_admin(u_h[0]->fe_space->mesh,0U);// ADM_PERIODIC);	//unverstanden und wohl auch
							//    quatsch--admin f. periodische Raender
    wall_quad 		= get_wall_quad(u_h[0]->fe_space->mesh->dim, quad_degree);
    wall_quad_fast =
      		get_wall_quad_fast(u_h[0]->fe_space->bas_fcts, wall_quad,
							 INIT_GRD_PHI|INIT_UH);
    for (row_comp =0; row_comp<ncomps; row_comp++)
    {
	dof_set(0.0, f_h[row_comp]);
   	if (f_h[row_comp]->fe_space->bas_fcts->degree > 1)
   	  fill_flag = INIT_PHI|INIT_GRD_PHI|INIT_D2_PHI;
   	else
     	fill_flag = INIT_PHI|INIT_GRD_PHI;

/*bound = nil haengt davon ab, ob die fe_spaces gleich oder verschieden sind wegen add_el_matrix.
Also haengt die Moeglichkeit des Einbindens von Randbedingungen davon ab, ob
row_fe_space=col_fe_space.
=>	fuer den Diagonalblock eines gekoppelten Systems muesste row_fe_space=col_fe_space
gelten, was hoffentlich ok ist. Deshalb allokation nur der test_quad_fasts[]*/
	test_quad_fasts[row_comp] 
	   	= get_quad_fast(f_h[row_comp]->fe_space->bas_fcts, quad , fill_flag);//fuer Elemente
	rhs_size_el 	+= 	f_h[row_comp]->fe_space->bas_fcts->n_bas_fcts;
	rhs_size_max	= MAX(rhs_size_max,f_h[row_comp]->fe_space->bas_fcts->n_bas_fcts);
//	sol_size_el   += 	u_h[row_comp]->fe_space->bas_fcts->n_bas_fcts; //ahem... viel zu viele!
//	sol_size_max  = MAX(sol_size_max,u_h[row_comp]->fe_space->bas_fcts->n_bas_fcts);
	//richtig weil 1 fe_space, aber auch spaeter immer row_comp & sol_comp=<ncomps.
    	for (col_comp =0; col_comp<ncomps; col_comp++)
  	{
 		sprintf(key, "mat_%s%d%d",name,row_comp, col_comp);
    		matrix_blocks[row_comp*ncomps + col_comp] = get_dof_matrix(key, 
				f_h[row_comp]->fe_space, u_h[col_comp]->fe_space);
			//sieht komisch aus, aber sollte ok sein
		//in fem_base  	op_arg_info[comp] = new OP_ARG_INFO(prob_data[comp]);
		//richtig weil bis auf weiteres row_fe_space[i] == col_fe_space[i].
//		quad_fast = test_quad_fasts[col_comp];	//war fuer set_std_op_info, hoff.obsol.
		if ( (outcome = set_std_op_info( row_comp, col_comp)))
		{	INFO(info_level,6,"No Block %d %d op_info\n", row_comp, col_comp);
		}
		else
		{
			INFO(info_level,6,"Block %d %d set_std_op_info done\n", row_comp, col_comp);
			fill_matrix_info(&op_info
					, &matrix_infos[row_comp*ncomps + col_comp]);
		} 
	 
/*fuer einkomponentige "Systeme" lassen wir verschiedene FE_SPACES zu. So kann man, baut man
 aus mehreren Instanzen ein System, Nebendiagonalbloecke unterschiedlicher sol- u. test-fe_spaces
 realisieren*/
  		if (ncomps ==1 )
  		{	row_dof  = new DOF[u_h[0]->fe_space->bas_fcts->n_bas_fcts];
  			if (u_h[0]->fe_space == f_h[0]->fe_space)
			{
	    			col_dof = row_dof ;  
    				bound 	=   new S_CHAR[f_h[0]->fe_space->bas_fcts->n_bas_fcts]; 
			}
			else
			{
	    		    col_dof 	=   new DOF[f_h[0]->fe_space->bas_fcts->n_bas_fcts];
			    bound 	= nil;//muss sein, siehe Buch S. add_el_matrix
			}
  		}
  		else
  		{ //fuer mehrere lassen wir das nicht zu.
      			TEST_EXIT(f_h[row_comp]->fe_space == u_h[row_comp ]->fe_space,
			"Implemented only f_h[i]->fe_space == u_h[i]->fe_space, comp i=%d mismatches\n ",
			row_comp);
  		}
 	}
  } //Ende Zeilen
    sol_size_el   = rhs_size_el;			
    sol_size_max  = rhs_size_max;			
  el_mat = new REAL*[rhs_size_max]; 			//i.A. zu gross, wurscht. 
  for (i=0; i<rhs_size_max; i++)
  		el_mat[i] = new REAL[sol_size_max];	
  el_f	= new REAL[f_h[0]->fe_space->bas_fcts->n_bas_fcts];

   if (ncomps >1 )
	{
	 row_dof 	=   new DOF[sol_size_el]; 
    	col_dof 	=  row_dof ;	// new DOF[rhs_size_el]; koennen eben kein anderes System
    	bound 	=   new S_CHAR[rhs_size_el]; 
   	}					// zulassen
    uh_el    	=   new REAL[sol_size_el];
    uh_old_el   = 	new REAL[sol_size_el];

  
  prob_data_ptr = op_arg_infos[0]->prob_data_ptr;
//   	sprintf(key, "mat_%s",name);
  matrix      = matrix_blocks[0] ;
  matrix_info = matrix_infos; //damits fuer ncomps =1 ok ist
  test_quad_fast = test_quad_fasts[0];	//damits fuer eine Komponente ok is
  sol_bas_fcts 	= u_h[0]->fe_space->bas_fcts;
//and quad_fast_uh? Baustelle
  return outcome; 

}
//nur fuer eine Komponente getestet,
//  aus Vektoren von DOF_REAL_VECS ein System mahchen

build_stat::build_stat(const char *const name, 
			 DOF_REAL_VEC **u_h, DOF_REAL_VEC   **u_h_old, DOF_SCHAR_VEC** bound_vec
			 		, DOF_REAL_VEC 	 **f_h 
					,const PROB_DATA_DIFF * const* const  prob_data
					,  const int ncomps, int quad_degree
					,REAL const   * const time, REAL const   * const timestep,  const REAL theta)
  :  fem_base( name,  u_h, u_h_old, bound_vec, prob_data, ncomps, time)
  	, fem_elfunc(/*	u_h[0]->fe_space->bas_fcts, wichtig!!  quad_degree,*/ timestep)
	, matrix_infos( new EL_MATRIX_INFO[ncomps*ncomps])
	, matrix_blocks( new DOF_MATRIX*[ncomps*ncomps])
	,test_quad_fasts( 	new const QUAD_FAST* [ncomps])
	, f_h(f_h)
	, theta(theta)
{
  FUNCNAME("build_stat");
  int  row_comp = 0;

//--------------fuer all dies vielleicht eine wall_fem_elfunc schreiben?
//-----------Vernuenftige universelle Implementierung braucht wall_quad_fast[ncomps]
  if (quad_degree < 0)
       for (row_comp =0; row_comp<ncomps; row_comp++)
    	{
		quad_degree = MAX(u_h[row_comp]->fe_space->bas_fcts->degree+2, quad_degree);
	}
  common_construct_func( name, quad_degree);
}


/*der fem_elfunc-konstruktor ist veraltet! bas_fcts fuer ein System haut eh nicht hin*/
 build_stat::build_stat(const char *const name, fem_base const * const base, DOF_REAL_VEC   **f_h
 					,  int quad_degree
					,  const  REAL *const timestep, const REAL theta)
	:fem_base(*base)//, fem_elfunc(	u_h[0]->fe_space->bas_fcts, f_h[0] ->fe_space->bas_fcts, quad_degree, timestep)
			, fem_elfunc(timestep)
				,matrix_infos( new EL_MATRIX_INFO[ncomps*ncomps])
				,  matrix_blocks( new DOF_MATRIX*[ncomps*ncomps])
				,test_quad_fasts( 	new const QUAD_FAST* [ncomps])
					, f_h(f_h), theta(theta)
{//clone von oben
  FUNCNAME("build_stat");
  int  row_comp = 0;
//--------------fuer all dies vielleicht eine wall_fem_elfunc schreiben?
//-----------Vernuenftige universelle Implementierung braucht wall_quad_fast[ncomps]
  if (quad_degree < 0)
       for (row_comp =0; row_comp<ncomps; row_comp++)
    	{
		quad_degree = MAX(u_h[row_comp]->fe_space->bas_fcts->degree+2, quad_degree);
	}
  common_construct_func( name, quad_degree);
 }

/*Konstruktor fuer ein System, alle Komponenten aus einem Raum. Fuer verschiedene Raeume 
muss mans halt noch machen.*/
build_stat::build_stat(const char *const name,  FE_SPACE const *const fe_space,
		       const PROB_DATA_DIFF *const* const prob_data
		       , const int ncomps,  int quad_degree,
				REAL const   * const time, const  REAL *const timestep, 
						 const REAL theta)
  : fem_base(name, fe_space, prob_data, ncomps, time)
  	, fem_elfunc( fe_space->bas_fcts,   quad_degree,timestep)
	,matrix_infos( 	new EL_MATRIX_INFO[ncomps*ncomps])
	,  matrix_blocks( 	new DOF_MATRIX*[ncomps*ncomps])
	,test_quad_fasts( 	new const QUAD_FAST* [ncomps])
	,f_h(new DOF_REAL_VEC* [ncomps])
	,theta(theta)
{
  FUNCNAME("build_stat");
  char  key[128];
  int  row_comp = 0;

  TEST_EXIT(fe_space,"no fe_space\n");
  if (quad_degree < 0) quad_degree = fe_space->bas_fcts->degree+2;
  for (row_comp =0; row_comp<ncomps; row_comp++)
  {
  	sprintf(key, "f_%s%d",name,row_comp);
    	f_h[row_comp]    = get_dof_real_vec(key, fe_space); //u_h[row_comp waere ok]->fe_space
  }
   common_construct_func(name, quad_degree);
}

