/* Fesslix - Stochastic Analysis
 * Copyright (C) 2010-2016 Wolfgang Betz
 *
 * Fesslix is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Fesslix is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Fesslix.  If not, see <http://www.gnu.org/licenses/>. 
 */

#include "flxfem_elements_kl.h"
// #include "flxrandomFEM.h"

tdouble *flxElement_KL_base::GX = NULL;
tdouble *flxElement_KL_base::GY = NULL;
tdouble *flxElement_KL_base::GZ = NULL;
tdouble *flxElement_KL_base::GX2 = NULL;
tdouble *flxElement_KL_base::GY2 = NULL;
tdouble *flxElement_KL_base::GZ2 = NULL;
	              //                             0  1   2    3      4     5      6      7       8       9        10       11       12       13        14        15        16         17         18         19
const tdouble flxElement_KL_base::dha[MAXTREEDEPTH]={1.,0.5,0.25,0.125,0.0625,1./32.,1./64.,1./128.,1./256.,1./512.,1./1024.,1./2048.,1./4096.,1./8192.,1./16384.,1./32768.,1./65536.,1./131072.,1./262144.,1./524288.};


void flxElement_KL_base::set_Const()
{
  GX = ConstantBox->get("gx",true);
  GY = ConstantBox->get("gy",true);
  GZ = ConstantBox->get("gz",true);
  GX2 = ConstantBox->get("gx2",true);
  GY2 = ConstantBox->get("gy2",true);
  GZ2 = ConstantBox->get("gz2",true);
}

const tdouble flxElement_KL_base::get_error(const tdouble& lxV, const tdouble& lyV, const tdouble& lzV, const int errMeasure) const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  const tdouble* EVp = ptrEigenvalues->get_tmp_vptr_const();
  flxVec tr(DIM);	// vector of precomputed coefficients
  if (errMeasure==1) {
    // compute some coefficients (for second term)
      flxVec tri(DIM);
      flxVec trr(DIM); const tdouble* trrp = trr.get_tmp_vptr_const();
      update_globalConst_o(lxV,lyV,lzV);
      const tdouble sDx = ptrFunSigma->calc();
      flxElement_KL_base *curEl;
      const size_t beS = ptrboxEL_vec->size();
      for (tuint i=0;i<beS;++i) {
	curEl = (*ptrboxEL_vec)[i];
	curEl->get_error_1i_el(curEl==this,tr,tri);
	trr += tr;
      }
    // compute first term
      pdouble t = ZERO;
      tdouble* trp = tr.get_tmp_vptr();
      for (tuint i=0;i<DIM;++i) {
	trp[i] = calc_djNj((ptrEigenvectors->operator[](i)).get_tmp_vptr_const(),lxV,lyV,lzV);
	t+=pow2(EVp[i]*trp[i]);
      }
    // compute second term
      for (register tuint i=0;i<DIM;++i) {
	t -= 2.0*sDx*trp[i]*trrp[i];
      }
    t/=pow2(sDx);
    t+=ONE;
    return t.cast2double();
  } else if (errMeasure == 3 || errMeasure == 101) {
    register tdouble t = ZERO;
    for (register tuint i=0;i<DIM;++i) {
      t+=pow2(EVp[i]*calc_djNj((ptrEigenvectors->operator[](i)).get_tmp_vptr_const(),lxV,lyV,lzV));
    }
    t/=pow2(ptrFunSigma->calc());
    if (errMeasure==3) return fabs(ONE-t);
    else return ONE-t;
  } else if (errMeasure==2) {
    update_globalConst_o(lxV,lyV,lzV);
    return get_error_2i(lxV,lyV,lzV,tr);
  } else {
    std::ostringstream ssV;
    ssV << "Unknown error measure (" << errMeasure << ")";
    throw FlxException("flxElement_KL_base::get_error", ssV.str() );
  }
}

const tdouble flxElement_KL_base::get_error_2i(const tdouble& lxV, const tdouble& lyV, const tdouble& lzV, flxVec& tr) const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  // precompute some coefficients
    get_error_2i_assemble_tr(DIM,lxV,lyV,lzV,tr);
    const tdouble sDx = ptrFunSigma->calc();
  // integration (staggered Gaussian)
    tdouble integ_Err=ZERO, integ_Cov=ZERO;
    flxElement_KL_base *curEl;
    const size_t beS = ptrboxEL_vec->size();
    for (size_t i=0;i<beS;++i) {
      curEl = (*ptrboxEL_vec)[i];
      curEl->get_error_2i_el(curEl==this,integ_Cov,integ_Err,sDx,tr);
    }
  return integ_Err/integ_Cov;
}

flxElement_KL_base::flxElement_KL_base(FlxFunction* geo_fun, const bool is_empty)
: is_empty(is_empty),ptrFunSigma(NULL),ptrFunRho(NULL), ptrEigenvectors(NULL), ptrEigenvalues(NULL),ptrboxEL_vec(NULL),geo_fun(geo_fun)
{

}

flxElement_KL_base::~flxElement_KL_base()
{
  if (geo_fun) delete geo_fun;
}

const tdouble flxElement_KL_base::err_var_domain_sep() const
{
  throw FlxException_NotImplemented("flxElement_KL_base::err_var_domain_sep");
}

const tdouble flxElement_KL_base::get_error_2i_EOLE(flxVec& Hx, flxVec& tr, const std::vector< flxPoint >& pointVec, const flxVec& sdVec) const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  // precompute some coefficients
    tdouble sDx = ZERO;
    assemble_Hx_EOLE(Hx,sDx,pointVec,sdVec); 
    for (register tuint i=0; i<DIM; ++i) {
      tr[i] = (ptrEigenvectors->operator[](i)*Hx) * pow2(ptrEigenvalues->operator[](i));
    }
  // integration (staggered Gaussian)
    tdouble integ_Err=ZERO, integ_Cov=ZERO;
    flxElement_KL_base *curEl;
    const size_t beS = ptrboxEL_vec->size();
    for (size_t i=0;i<beS;++i) {
      curEl = (*ptrboxEL_vec)[i];
      curEl->get_error_2i_el_EOLE(curEl==this,integ_Cov,integ_Err,sDx,tr,pointVec,sdVec,Hx);
    }
  return integ_Err/integ_Cov;
}

void flxElement_KL_base::assemble_Hx_EOLE(flxVec& Hx, tdouble& sD_curr_x, const std::vector< flxPoint >& pointVec, const flxVec& sdVec) const
{
  sD_curr_x = ptrFunSigma->calc();
  const tuint Ndof = Hx.get_N();
  tdouble* Hxp = Hx.get_tmp_vptr();
  const tdouble* sdVecp = sdVec.get_tmp_vptr_const();
  const tdouble GX2_t = *(GX2+0);
  const tdouble GY2_t = *(GX2+1);
  const tdouble GZ2_t = *(GX2+2);
  for (register tuint i=0;i<Ndof;++i) {
    pointVec[i].set_global2_dist();
    Hxp[i] = sD_curr_x * sdVecp[i] * ptrFunRho->calc();
  }
  *(GX2+0) = GX2_t;
  *(GX2+1) = GY2_t;
  *(GX2+2) = GZ2_t;
}

void flxElement_KL_base::get_error_2i_assemble_tr(const tuint DIM, const tdouble& lxV, const tdouble& lyV, const tdouble& lzV, flxVec& tr) const
{
  const tdouble *evp = ptrEigenvalues->get_tmp_vptr_const();
  tdouble *trp = tr.get_tmp_vptr();
  for (tuint i=0;i<DIM;++i) { 
    trp[i] = pow2(evp[i]) * calc_djNj((ptrEigenvectors->operator[](i)).get_tmp_vptr_const(),lxV,lyV,lzV); 
  }
}

flxElement_KL_1D::flxElement_KL_1D(flxEdge* edge, const tuint& pOrder, const tuint& DegCorr, const tuint& DegStd, const std::vector< tdouble >& IntervalVec1, const std::vector< bool >& IntervalVec1_geo, const std::vector< tdouble >& IntervalVec2, const std::vector< bool >& IntervalVec2_geo, const std::vector< tdouble >& IntervalVecO, const std::vector< bool >& IntervalVecO_geo, const std::vector< tdouble >& IntervalVec_e2_i1, const std::vector< bool >& IntervalVec_e2_i1_geo, const std::vector< tdouble >& IntervalVec_e2_i2, const std::vector< bool >& IntervalVec_e2_i2_geo, const std::vector< tdouble >& IntervalVec_e2_o, const std::vector< bool >& IntervalVec_e2_o_geo, const std::vector< tdouble >& IntervalVec_Geo, const std::vector< bool >& IntervalVec_GeoB, FlxFunction* geo_fun)
: flxElement_KL_base(geo_fun,IntervalVec_Geo.empty()), pOrder(pOrder), DegCorr(DegCorr), DegStd(DegStd), NGPi(GI->pDegree2GPs(pOrder+DegStd+DegCorr)), GPi(NULL), GWi(NULL), edge(edge), 
IntervalVec1(IntervalVec1), IntervalVec1_geo(IntervalVec1_geo), IntervalVec2(IntervalVec2), IntervalVec2_geo(IntervalVec2_geo), IntervalVecO(IntervalVecO), IntervalVecO_geo(IntervalVecO_geo), 
IntervalVec_e2_i1(IntervalVec_e2_i1), IntervalVec_e2_i1_geo(IntervalVec_e2_i1_geo), IntervalVec_e2_i2(IntervalVec_e2_i2), IntervalVec_e2_i2_geo(IntervalVec_e2_i2_geo), 
IntervalVec_e2_o(IntervalVec_e2_o), IntervalVec_e2_o_geo(IntervalVec_e2_o_geo), IntervalVec_Geo(IntervalVec_Geo), IntervalVec_GeoB(IntervalVec_GeoB)
{
  // update kl-edge
    edge->set_DegStd(DegStd);
    edge->set_DegCorr(DegCorr);
    edge->set_KLmesh(IntervalVec1.size(),IntervalVecO.size());
  // check if enough Gauss-points are loaded
    GI->check_GA_polynomialDegree(pOrder*2);
    GI->check_GA(NGPi);
    GI->check_GA_polynomialDegree(DegCorr+DegStd*2);
  // pre-load Gauss-points
    GPi = GI->get_GP(NGPi);
    GWi = GI->get_GW(NGPi);
  // make sure that enough shape functions are available
    XXX_check_order(pOrder);
}

void flxElement_KL_1D::log_report(const tuint rfindex, const std::string& elID, const flxElement_KL_base::rftype rft) const
{
  GlobalVar.slog(4) << "Assigned '" << elID << "' to random field " << rfindex << "." << std::endl << "  ";
  if (rft == rfKLfemGauss) {
    GlobalVar.slog(4) << "pOrder=" << pOrder << "; ";
  }
  
  if (rft == rfKLfemGauss) {
    GlobalVar.slog(4) << "inter_i1=" << (IntervalVec1.empty()?1:(IntervalVec1.size()-1)) << "; ";
    GlobalVar.slog(4) << "inter_i2=" << (IntervalVec2.empty()?1:(IntervalVec2.size()-1)) << "; ";
  }
  if ( rft != rfKLAnaExpCorrGauss1D ) {
    GlobalVar.slog(4) << "inter_o=" << (IntervalVecO.empty()?1:(IntervalVecO.size()-1)) << "; ";
  }
  
  GlobalVar.slog(4) << "degCorr=" << DegCorr << "; ";
  if ( rft != rfKLAnaExpCorrGauss1D ) {
    GlobalVar.slog(4) << "degStd=" << DegStd << "; ";
  }
  
  GlobalVar.slog(4) << "inter_e2_i1=" << (IntervalVec_e2_i1.empty()?1:(IntervalVec_e2_i1.size()-1)) << "; ";
  if ( rft != rfKLAnaExpCorrGauss1D ) {
    GlobalVar.slog(4) << "inter_e2_i2=" << (IntervalVec_e2_i2.empty()?1:(IntervalVec_e2_i2.size()-1)) << "; ";
  }
  GlobalVar.slog(4) << "inter_e2_o=" << (IntervalVec_e2_o.empty()?1:(IntervalVec_e2_o.size()-1)) << "; ";
  
  GlobalVar.slog(4) << std::endl;
}

const tdouble flxElement_KL_1D::calc_domain(const bool considerGeo) const
{
  const tdouble l = calc_length();
  if (considerGeo) {
    if (is_empty) return ZERO;
    tdouble d = ZERO;
    for (tuint k = 0; k < IntervalVec_GeoB.size(); ++k) {
      if (!IntervalVec_GeoB[k]) continue;
      d += (IntervalVec_Geo[k+1]-IntervalVec_Geo[k]);
    }
    return d/2.0 * l;
  } else {
    return l;
  }
}

void flxElement_KL_1D::countDOFs(niMap& nodalM, eiMap& edgeM, fiMap& faceM, std::vector< const flxVertex* >& nV, std::vector< const flxEdge* >& eV, std::vector< const flxFace* >& fV)
{
  if (is_empty) return;
  // deal with vertices
    std::map<const flxVertex*,tnlong>::iterator pos;
    // node 1
      pos = nodalM.find(&(edge->get_vertex_1()));
      if ( pos == nodalM.end() ) {	// vertex is NOT in the list
	std::pair<const flxVertex*,tnlong>Element(&(edge->get_vertex_1()), 0);
	nodalM.insert(Element);
	nV.push_back(&(edge->get_vertex_1()));
      }
    // node 2
      pos = nodalM.find(&(edge->get_vertex_2()));
      if ( pos == nodalM.end() ) {	// vertex is NOT in the list
	std::pair<const flxVertex*,tnlong>Element(&(edge->get_vertex_2()), 0);
	nodalM.insert(Element);
	nV.push_back(&(edge->get_vertex_2()));
      }
  // deal with edge
    std::map<const flxEdge*,eiMap_sec>::iterator posE;
    posE = edgeM.find(edge);
    if ( posE == edgeM.end() ) {	// vertex is NOT in the list
      eiMap_sec ems; ems.dofindex=0; ems.count = pOrder-1;
      std::pair<const flxEdge*,eiMap_sec>Element(edge,ems);
      edgeM.insert(Element);
      eV.push_back(edge);
    } else {				// vertex is already in the list
      throw FlxException("flxElement_KL_1D::countDOFs","There is something wrong with the geometrical definition of the random field.");
    }
}

void flxElement_KL_1D::assembleDOFs(const niMap& nodalM, const eiMap& edgeM, fiMap& faceM)
{
  if (is_empty) return;
  // deal with vertices
    std::map<const flxVertex*,tnlong>::const_iterator pos;
    // node 1
      pos = nodalM.find(&(edge->get_vertex_1()));
      #if FLX_DEBUG
	if ( pos == nodalM.end() ) { throw FlxException_Crude("flxElement_KL_1D::assembleDOFs_1"); }
      #endif
      mapGlobal[0] = pos->second;
    // node 2
      pos = nodalM.find(&(edge->get_vertex_2()));
      #if FLX_DEBUG
	if ( pos == nodalM.end() ) { throw FlxException_Crude("flxElement_KL_1D::assembleDOFs_2"); }
      #endif
      mapGlobal[1] = pos->second;
  // deal with edges
      std::map<const flxEdge*,eiMap_sec>::const_iterator posE;
      posE = edgeM.find(edge);
      #if FLX_DEBUG
	if ( posE == edgeM.end() ) { throw FlxException_Crude("flxElement_KL_1D::assembleDOFs_3"); }
      #endif
      mapGlobal[2] = (posE->second).dofindex;
}

void flxElement_KL_1D::calc_local_MassMatrix_KLE(FlxMtxSym& Mmtx)
{
  if (is_empty) return;
  const tuint Ni = pOrder+1;	// Number of DOFs of the element
  flxVec d((pow2(Ni)+Ni)/2);		// stores the local mass matrix
  flxVec di(d.get_N());			// for the inner integration loop
  // perform the integration of the local mass matrix
    flxVec s(Ni);				// stores precomputed shape functions
    tnlong c;
    const tuint N = GI->pDegree2GPs(pOrder*2);	// Number of Gauss points
    const tdouble* GP = GI->get_GP(N);
    const tdouble* GW = GI->get_GW(N);
    const tdouble* sp = s.get_tmp_vptr_const();
    tdouble* dip = di.get_tmp_vptr();
    tdouble f,lx,dx;
    for (tuint k = 0; k < IntervalVec_GeoB.size(); ++k) {
      if (!IntervalVec_GeoB[k]) continue;
      di.set_zero();
      dx = (IntervalVec_Geo[k+1]-IntervalVec_Geo[k])/2.0;
      for (register tuint p=0;p<N;++p) {
	lx = IntervalVec_Geo[k] + dx + dx* GP[p];  	// seems to be numerically better
	XXX_vec(s,lx);				// calculate shape functions
	c=0;
	for (tuint i=0;i<Ni;++i) {
	  f = GW[p]*sp[i];
	  for (tuint j=0;j<=i;++j) {
	    dip[c++]+=f*sp[j];  
	  }
	}
      }
      di*=dx;
      d+=di;
    }
    d*= calc_length() / 2.0;
  // map the local matrix to the global matrix
    const tdouble* dp = d.get_tmp_vptr_const();
    Mmtx.add_value(mapGlobal[0],mapGlobal[0],dp[0]);
    Mmtx.add_value(mapGlobal[1],mapGlobal[0],dp[1]);
    Mmtx.add_value(mapGlobal[1],mapGlobal[1],dp[2]);
    for (tuint k=0;k<pOrder-1;++k) {
      Mmtx.add_value(mapGlobal[2]+k,mapGlobal[0],dp[(k*k+5*k)/2+3]);
      Mmtx.add_value(mapGlobal[2]+k,mapGlobal[1],dp[(k*k+5*k)/2+4]);
      for (tuint l=0;l<=k;++l) {
	Mmtx.add_value(mapGlobal[2]+k,mapGlobal[2]+l,dp[(k*k+5*k)/2+5+l]);
      }
    }
}

void flxElement_KL_1D::calc_local_collocMtx(const tnlong nid, FlxMtx& Amtx, const tdouble& sd)
{
  #if FLX_DEBUG
    if (pOrder!=1) throw FlxException_Crude("flxElement_KL_1D::calc_local_collocMtx");
  #endif
  // perform the integration
    flxVec t(2);
    calc_local_corrMtx_KLE_inner(t,false);
    t*=sd;
    t*=calc_length()/2.;
  // assemble the nid'th matrix row
    Amtx.add_value(nid,mapGlobal[0],t[0]);
    Amtx.add_value(nid,mapGlobal[1],t[1]);
}

void flxElement_KL_1D::calc_local_corrMtx_KLE(FlxMtxSym& Cmtx, std::vector< flxElement_KL_base* >& ElVec) const
{
  if (is_empty) return;
  const tuint Ni1 = pOrder+1;		// equal to number of shape functions of this element
  size_t Ni2;
  tdouble sigma_eval, dx, lx;
  flxVec s(Ni1);	const tdouble* sp = s.get_tmp_vptr_const();				// stores precomputed shape functions
  flxElement_KL_1D* ce;
  for (tuint i=0;i<ElVec.size();++i) {				// perform the integration for each element
    ce = dynamic_cast<flxElement_KL_1D*>(ElVec[i]);
    if (ce==NULL) {
      throw FlxException("flxElement_KL_1D::calc_local_corrMtx_KLE", "There seems to be a problem with the geometrical definition of the random field.");
    }
    Ni2 = ce->pOrder+1;						// equal to number of shape functions of referenced element
    flxVec d(Ni1*Ni2); const tdouble* dp = d.get_tmp_vptr_const();	// Ni1=rows; Ni2=columns
    flxVec r(Ni1*Ni2); tdouble* rp = r.get_tmp_vptr();
    flxVec t(Ni2); const tdouble* tp = t.get_tmp_vptr_const();
    // Gauss points of the outer integration
      const tuint N = GI->pDegree2GPs(max_deg_shape_function()+(1+DegCorr+DegStd));	// Number of Gauss points
      GI->check_GA(N);
      const tdouble* GP = GI->get_GP(N);
      const tdouble* GW = GI->get_GW(N);

    for (tuint q=1;q<IntervalVecO.size();++q) {		// OUTER integration loop
      if (!IntervalVecO_geo[q-1]) continue;
      r = ZERO;
      dx = (IntervalVecO[q]-IntervalVecO[q-1])/2.0;
      for (tuint p=0;p<N;++p) {
	lx = IntervalVecO[q-1] + dx + dx* GP[p];  // seems to be numerically better
	update_globalConst_o(lx);
	sigma_eval = ptrFunSigma->calc() * GW[p];
	s.set_zero();
	XXX_const(s,lx,sigma_eval);		// calculate shape functions
	ce->calc_local_corrMtx_KLE_inner(t,ce==this);
	tuint c=0;
	for (tuint j=0;j<Ni1;++j) {
	  for (tuint k=0;k<Ni2;++k) {
	    rp[c++]+=sp[j]*tp[k];
	  }
	}
      }
      r*=dx;
      d+=r;
    }
    d*= calc_length() * ce->calc_length() / 4.0;
    // map the local matrix to the global matrix
      if (ce==this) {
	Cmtx.add_value(mapGlobal[0],mapGlobal[0],dp[0]);
	Cmtx.add_value(mapGlobal[1],mapGlobal[0],(dp[Ni1]+dp[1])/2.0);
	Cmtx.add_value(mapGlobal[1],mapGlobal[1],dp[Ni1+1]);
	for (tuint k=0;k<pOrder-1;++k) {
	  Cmtx.add_value(mapGlobal[2]+k,mapGlobal[0],(dp[Ni1*(k+2)]+dp[k+2])/2.0);   // Ni1*(k+2)  // k+2
	  Cmtx.add_value(mapGlobal[2]+k,mapGlobal[1],(dp[Ni1*(k+2)+1]+dp[Ni1+k+2])/2.0); // Ni1*(k+2)+1  // Ni1+k+2
	  for (tuint l=0;l<=k;++l) {
	    Cmtx.add_value(mapGlobal[2]+k,mapGlobal[2]+l,(dp[Ni1*(k+2)+2+l]+dp[Ni1*(2+l)+2+k])/2.0);  // Ni1*(k+2)+2+l
	  }
	}
      } else {
	Cmtx.add_value(mapGlobal[0],ce->mapGlobal[0],dp[0]*((mapGlobal[0]==ce->mapGlobal[0])?2.0:ONE));
	Cmtx.add_value(mapGlobal[0],ce->mapGlobal[1],dp[1]*((mapGlobal[0]==ce->mapGlobal[1])?2.0:ONE));
	Cmtx.add_value(mapGlobal[1],ce->mapGlobal[0],dp[Ni2]*((mapGlobal[1]==ce->mapGlobal[0])?2.0:ONE));
	Cmtx.add_value(mapGlobal[1],ce->mapGlobal[1],dp[Ni2+1]*((mapGlobal[1]==ce->mapGlobal[1])?2.0:ONE));
	for (tuint k=0;k<pOrder-1;++k) {
	  Cmtx.add_value(mapGlobal[2]+k,ce->mapGlobal[0],dp[Ni2*(k+2)]);
	  Cmtx.add_value(mapGlobal[2]+k,ce->mapGlobal[1],dp[Ni2*(k+2)+1]);
	}
	for (tuint l=0;l<ce->pOrder-1;++l) {
	  Cmtx.add_value(mapGlobal[0],ce->mapGlobal[2]+l,dp[2+l]);
	  Cmtx.add_value(mapGlobal[1],ce->mapGlobal[2]+l,dp[Ni2+2+l]);
	}
	for (tuint k=0;k<pOrder-1;++k) {
	  for (tuint l=0;l<ce->pOrder-1;++l) {
	    Cmtx.add_value(mapGlobal[2]+k,ce->mapGlobal[2]+l,dp[Ni2*(k+2)+2+l]);
	  }
	}
      }
  }
}

void flxElement_KL_1D::calc_local_corrMtx_KLE_inner(flxVec& t, const bool sameElement) const
{
  if (is_empty) {
    t.set_zero();
    return;
  }
  flxVec r(t.get_N());
  const std::vector<tdouble> &IntervalVec = sameElement?IntervalVec1:IntervalVec2;
  const std::vector<bool> &IntervalVec_geo = sameElement?IntervalVec1_geo:IntervalVec2_geo;
  tdouble sigma_rho_eval;
  tdouble dx,lx;
  const tuint Ii = IntervalVec.size();
  t.set_zero();
  for (tuint i=1;i<Ii;++i) {
    if (!IntervalVec_geo[i-1]) continue;
    r.set_zero();
    dx = (IntervalVec[i]-IntervalVec[i-1])/2.0;
    for (tuint p=0;p<NGPi;++p) {
      lx = IntervalVec[i-1] + dx + dx * GPi[p];  // seems to be numerically better
      update_globalConst_i(lx);
      sigma_rho_eval = ptrFunSigma->calc()*ptrFunRho->calc()*GWi[p];
      XXX_const(r,lx,sigma_rho_eval);
    }
    r*=dx;
    t+=r;
  }
}

void flxElement_KL_1D::get_error_1i_el(const bool sameEl, flxVec& tr, flxVec& tri) const
{
  tr.set_zero();
  if (is_empty) return;
  const size_t DIM = ptrEigenvectors->size();
  // get Gauss-points
    const tuint GN = GI->pDegree2GPs(pOrder+DegStd+DegCorr);		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  const std::vector<tdouble> &iVec = (sameEl)?IntervalVec_e2_i1:IntervalVec_e2_i2;
  const std::vector<bool> &iVec_geo = (sameEl)?IntervalVec_e2_i1_geo:IntervalVec_e2_i2_geo;  
  register tuint i,j,k;
  tdouble dx,lx,t;
  for (i=1;i<iVec.size();++i) {
    if (!iVec_geo[i-1]) continue;
    dx = (iVec[i]-iVec[i-1])/2.0;
    tri = ZERO;
    for (j=0;j<GN;++j) {
      lx = (GP[j]+ONE)*dx+iVec[i-1];
      update_globalConst_i(lx);
      t = ptrFunRho->calc()*ptrFunSigma->calc()*GW[j];
      for (k=0;k<DIM;++k) {
	tri[k] += t*calc_djNj(&(ptrEigenvectors->operator[](k))[0],lx,ZERO,ZERO);
      }
    }
    tri*=dx;
    tr+=tri;
  }
  tr *= calc_length()/2.0;
}

void flxElement_KL_1D::get_error_2i_el(const bool sameEl, tdouble& integ_Cov, tdouble& integ_Err, const tdouble& sDx, const flxVec& tr) const
{
  if (is_empty) return;
  const size_t DIM = ptrEigenvectors->size();
  // get Gauss-points
    const tuint GN = GI->pDegree2GPs(get_pOcovOrder());		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  const std::vector<tdouble> &iVec = (sameEl)?IntervalVec_e2_i1:IntervalVec_e2_i2;
  const std::vector<bool> &iVec_geo = (sameEl)?IntervalVec_e2_i1_geo:IntervalVec_e2_i2_geo;
  tdouble dx,rC,rE,dC=ZERO,dE=ZERO,lx,t;
  register tuint i,j,k;
  for (i=1;i<iVec.size();++i) {
    if (!iVec_geo[i-1]) continue;
    dx = (iVec[i]-iVec[i-1])/2.0;
    rC = ZERO; rE = ZERO;
    for (j=0;j<GN;++j) {
      lx = (GP[j]+ONE)*dx+iVec[i-1];
      update_globalConst_i(lx);
      t = ptrFunRho->calc()*sDx*ptrFunSigma->calc();
      rC += fabs(t)*GW[j];
      for (k=0;k<DIM;++k) {
	t -= tr[k]*calc_djNj((ptrEigenvectors->operator[](k)).get_tmp_vptr_const(),lx,ZERO,ZERO);
      }
      rE += fabs(t)*GW[j];
    }
    rC*=dx; rE*=dx;
    dC+=rC; dE+=rE;
  }
  dC *= calc_length()/2.0;
  dE *= calc_length()/2.0;
  integ_Cov+=dC;
  integ_Err+=dE;
}

void flxElement_KL_1D::get_error_2i_el_EOLE(const bool sameEl, tdouble& integ_Cov, tdouble& integ_Err, const tdouble& sDx, const flxVec& tr, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, flxVec& Hx) const
{
  if (is_empty) return;
  const size_t DIM = ptrEigenvectors->size();
  // get Gauss-points
    const tuint GN = GI->pDegree2GPs(DegCorr+DegStd*2);		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  const std::vector<tdouble> &iVec = (sameEl)?IntervalVec_e2_i1:IntervalVec_e2_i2;
  const std::vector<bool> &iVec_geo = (sameEl)?IntervalVec_e2_i1_geo:IntervalVec_e2_i2_geo;
  register tuint i,j,k;
  tdouble dx,rC,rE,dC=ZERO,dE=ZERO,lx,t,sD_cur_X;
  for (i=1;i<iVec.size();++i) {
    if (!iVec_geo[i-1]) continue;
    dx = (iVec[i]-iVec[i-1])/2.0;
    rC = ZERO; rE = ZERO;
    for (j=0;j<GN;++j) {
      lx = (GP[j]+ONE)*dx+iVec[i-1];
      update_globalConst_i(lx);
      t = ptrFunRho->calc();
      assemble_Hx_EOLE(Hx,sD_cur_X,pointVec,sdVec);
      t*=sDx*sD_cur_X;
      rC += fabs(t)*GW[j];
      for (k=0;k<DIM;++k) {
	t -= tr[k] * (ptrEigenvectors->operator[](k)*Hx);
      }
      rE += fabs(t)*GW[j];
    }
    rC*=dx; rE*=dx;
    dC+=rC; dE+=rE;
  }
  dC *= calc_length()/2.0;
  dE *= calc_length()/2.0;
  integ_Cov+=dC;
  integ_Err+=dE;
}

const tdouble flxElement_KL_1D::err_var_domain_sep() const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  const tdouble* EVp = ptrEigenvalues->get_tmp_vptr_const();
  // get Gauss-points
    const tuint poi = pOrder*2 + DegStd*2; 	// just an approximation!
    const tuint GN = GI->pDegree2GPs(poi);		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  tdouble res=ZERO;
  for (tuint i=1;i<IntervalVecO.size();++i) {
    if (!IntervalVecO_geo[i-1]) continue;
    tdouble dx = (IntervalVecO[i]-IntervalVecO[i-1])/2.0;
    tdouble r = ZERO;
    for (tuint j=0;j<GN;++j) {
      tdouble lx = (GP[j]+ONE)*dx+IntervalVecO[i-1];
      update_globalConst(lx);
      const tdouble sDx = ptrFunSigma->calc();
      // compute the variance of the RF-approximation
	pdouble t = ZERO;
	for (tuint k=0;k<DIM;++k) {
	  t+=pow2(EVp[k]*calc_djNj((ptrEigenvectors->operator[](k)).get_tmp_vptr_const(),lx,ZERO,ZERO));
	}
      t/=pow2(sDx);	// weight it
      t-=ONE;
      r+=fabs(t.cast2double())*GW[j];
    }
    r *=dx;
    res += r;
  }
  res *= calc_length()/2.0;
  return res;
}

const tdouble flxElement_KL_1D::err_var_domain() const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  const tdouble* EVp = ptrEigenvalues->get_tmp_vptr_const();
  flxVec tr(DIM);		// vector of precomputed coefficients
    tdouble* trp = tr.get_tmp_vptr();
  flxVec tri(DIM);	// help-vector (for inner integration)
  flxVec trr(DIM); 
    const tdouble* trrp = trr.get_tmp_vptr_const();
  // get Gauss-points
    const tuint poi = (pOrder*2>=DegCorr+DegStd+1+pOrder)?pOrder*2:(DegCorr+DegStd+1+pOrder)+DegStd*2;
    const tuint GN = GI->pDegree2GPs(poi);		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  tdouble res=ZERO;
  for (tuint i=1;i<IntervalVecO.size();++i) {
    if (!IntervalVecO_geo[i-1]) continue;
    tdouble dx = (IntervalVecO[i]-IntervalVecO[i-1])/2.0;
    tdouble r = ZERO;
    for (tuint j=0;j<GN;++j) {
      tdouble lx = (GP[j]+ONE)*dx+IntervalVecO[i-1];
      update_globalConst_o(lx);
      const tdouble sDx = ptrFunSigma->calc();
      // perform the inner integration
	trr.set_zero();
	flxElement_KL_base *curEl;
	const size_t beS = ptrboxEL_vec->size();
	for (size_t k = 0; k<beS; ++k) {
	  curEl = (*ptrboxEL_vec)[k];
	  curEl->get_error_1i_el(curEl==this,tr,tri);
	  trr += tr;
	}
      // compute first term
	pdouble t = ZERO;
	for (tuint k=0;k<DIM;++k) {
	  trp[k] = calc_djNj(&(ptrEigenvectors->operator[](k))[0],lx,ZERO,ZERO);
	  t+=pow2(EVp[k]*trp[k]);
	}
      // compute second term
	for (tuint k=0;k<DIM;++k) {
	  t -= 2.0*sDx*trp[k]*trrp[k];
	}
      t/=pow2(sDx);
      t+=ONE;
      r+=t.cast2double()*GW[j];
    }
    r *=dx;
    res += r;
  }
  res *= calc_length()/2.0;
  return res;
}

const tdouble flxElement_KL_1D::err_cov_domain() const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  flxVec tr(DIM);	// vector of precomputed coefficients
  // get Gauss-points
    const tuint GN = GI->pDegree2GPs(get_pOcovOrder());		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  
  tdouble res=ZERO, dx, r, lx;
  const size_t IVe2oS = IntervalVec_e2_o.size();
  for (tuint i=1;i<IVe2oS;++i) {
    if (!IntervalVec_e2_o_geo[i-1]) continue;
    dx = (IntervalVec_e2_o[i]-IntervalVec_e2_o[i-1])/2.0;
    r = ZERO;
    for (tuint j=0;j<GN;++j) {
      lx = (GP[j]+ONE)*dx+IntervalVec_e2_o[i-1];
      update_globalConst_o(lx);
      r += get_error_2i(lx,ZERO,ZERO,tr)*GW[j];
    }
    r *=dx;
    res += r;
  }
  res *= calc_length()/2.0;
  return res;
}

const tdouble flxElement_KL_1D::err_cov_domain_EOLE(const std::vector< flxPoint >& pointVec, const flxVec& sdVec) const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  flxVec tr(DIM);	// vector of precomputed coefficients
  flxVec Hx(pointVec.size());
  // get Gauss-points
    const tuint GN = GI->pDegree2GPs(DegCorr+DegStd*2);		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  
  tdouble res=ZERO, dx, r, lx;
  for (tuint i=1;i<IntervalVec_e2_o.size();++i) {
    if (!IntervalVec_e2_o_geo[i-1]) continue;
    dx = (IntervalVec_e2_o[i]-IntervalVec_e2_o[i-1])/2.0;
    r = ZERO;
    for (tuint j=0;j<GN;++j) {
      lx = (GP[j]+ONE)*dx+IntervalVec_e2_o[i-1];
      update_globalConst_o(lx);
      r += get_error_2i_EOLE(Hx,tr,pointVec,sdVec)*GW[j];
    }
    r *=dx;
    res += r;
  }
  res *= calc_length()/2.0;
  return res;
}

const bool flxElement_KL_1D::map2local(const flxPoint& p) const
{
  return edge->map2local(p);
}

void flxElement_KL_1D::plot_el(std::ostream& sout, FlxMtxConstFun* ppdim, const int errMeasure, const int prec, const int fixW, const bool checkTOL) const
{
  if (is_empty) return;
  const size_t DIM = ptrEigenvectors->size();
  tdouble dx,d,DU,i;
  const iVec ppdim_help = ConstMtxBox->get_Vec_cast2tuint(ppdim->eval(),true);;
  if (ppdim_help.size()<1) {
    std::ostringstream ssV;
    ssV << "The dimension of the vector has to be at least '1'.";
    throw FlxException("flxElement_KL_1D::plot_el", ssV.str() );
  }
  const tuint PPDIM = ppdim_help[0];
  tuint j;
  for (tuint k = 0; k < IntervalVec_GeoB.size(); ++k) {
    if (!IntervalVec_GeoB[k]) continue;
    dx = (IntervalVec_Geo[k+1]-IntervalVec_Geo[k]);
    d = dx/PPDIM;
    DU = IntervalVec_Geo[k+1] + d/2;
    for (i=IntervalVec_Geo[k];i<=DU;i+=d) {
      update_globalConst(i);
      sout << GlobalVar.Double2String(*GX,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GY,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GZ,false,prec,fixW) << ' ';
      sout << GlobalVar.Double2String(get_error(i,ZERO,ZERO,errMeasure),checkTOL,prec,fixW);
      for (j=0;j<DIM;++j) {
	sout << ' ' << GlobalVar.Double2String(calc_djNj((ptrEigenvectors->operator[](j)).get_tmp_vptr_const(),i,ZERO,ZERO),true,prec,fixW);
      }
      sout << std::endl;
    }
    sout << std::endl;
  }
}

void flxElement_KL_1D::plotcov_el(std::ostream& sout, const flxPoint& pp, FlxMtxConstFun* ppdim, const flxVec& tr, const int prec, const int fixW) const
{
  if (is_empty) return;
  const size_t DIM = ptrEigenvectors->size();
  // compute standard deviation in base point
    pp.set_global();
    pp.set_global2();
    const tdouble sDpp = ptrFunSigma->calc();
  tdouble dx,d,DU,i,t,tt;
  iVec ppdim_help = ConstMtxBox->get_Vec_cast2tuint(ppdim->eval(),true);
  if (ppdim_help.size()<1) {
    std::ostringstream ssV;
    ssV << "The dimension of the vector has to be at least '1'.";
    throw FlxException("flxElement_KL_1D::plotcov_el", ssV.str() );
  }
  const tuint PPDIM = ppdim_help[0];
  for (tuint k = 0; k < IntervalVec_GeoB.size(); ++k) {
    if (!IntervalVec_GeoB[k]) continue;
    dx = (IntervalVec_Geo[k+1]-IntervalVec_Geo[k]);
    d = dx/PPDIM;
    DU = IntervalVec_Geo[k+1] + d/2;
    for (i=IntervalVec_Geo[k];i<=DU;i+=d) {
      update_globalConst_i(i);
      sout << GlobalVar.Double2String(*GX,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GY,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GZ,false,prec,fixW) << ' ';
      t = ZERO;
      for (tuint j=0;j<DIM;j++) {	// i+1 is odd
	t+=tr[j]*calc_djNj((ptrEigenvectors->operator[](j)).get_tmp_vptr_const(),i,ZERO,ZERO);
      }
      tt = sDpp * ptrFunSigma->calc() * ptrFunRho->calc();
      sout << GlobalVar.Double2String(t,false,prec,fixW) << ' ' << GlobalVar.Double2String(tt,false,prec,fixW) << ' ' << GlobalVar.Double2String(tt-t,false,prec,fixW);
      sout << std::endl;
    }
    sout << std::endl;
  }
}

void flxElement_KL_1D::assembleEOLEpointVec(std::vector< flxPoint >& pointVec, const tuint Npt, tdouble* Nia) const
{
  if (is_empty) return;
  const size_t first_index = pointVec.size();
  flxVec rx(pOrder+1);
  for (tuint i=0;i<IntervalVecO.size();++i) {
    update_globalConst(IntervalVecO[i]);
    flxPoint p(*(GX+0),*(GX+1),*(GX+2));
    // check for double entries
      bool dbl = false;
      for (tuint j=0;j<first_index;++j) {
	if (pointVec[j]==p) {
	  dbl=true; 
	  break;
	}
      }
    if (dbl==false) {
      const tnlong id = pointVec.size();
      pointVec.push_back(p);
      if (Npt>0) {
	XXX_vec(rx,IntervalVecO[i]);
	Nia[mapGlobal[0]*Npt+id] = rx[0];
	Nia[mapGlobal[1]*Npt+id] = rx[1];
	for (tuint j=0;j<pOrder-1;++j) {
	  Nia[(mapGlobal[2]+j)*Npt+id] = rx[2+j];
	}
      }
    }
  }
}

void flxElement_KL_1D::get_PlotPoints(std::vector< flxPoint >& pointVec, std::vector< tuint >& geoVec, FlxMtxConstFun* ppdim) const
{
  pointVec.clear();
  if (is_empty) return;
  tdouble dx,d,DU,i;
  iVec t = ConstMtxBox->get_Vec_cast2tuint(ppdim->eval(),true);
  if (t.size()<1) {
    std::ostringstream ssV;
    ssV << "The dimension of the vector has to be at least '1'.";
    throw FlxException("flxElement_KL_1D::get_PlotPoints", ssV.str() );
  }
  const tuint PPDIM = t[0];
  for (tuint k = 0; k < IntervalVec_GeoB.size(); ++k) {
    if (!IntervalVec_GeoB[k]) {
      geoVec.push_back(pointVec.size());
      continue;
    }
    dx = (IntervalVec_Geo[k+1]-IntervalVec_Geo[k]);
    d = dx/PPDIM;
    DU = IntervalVec_Geo[k+1] + d/2;
    for (i=IntervalVec_Geo[k];i<=DU;i+=d) {
      update_globalConst(i);
      pointVec.push_back(flxPoint(*(GX+0),*(GX+1),*(GX+2)));
    }
  }
}

const tdouble flxElement_KL_1D::err_var_domain_EOLE(flxVec& Hx, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, const bool abs) const
{
  if (is_empty) return ZERO;
  const tuint DIM = ptrEigenvalues->get_N();
  // get Gauss-points
    const tuint GN = GI->pDegree2GPs(DegCorr+DegStd*2);		// of course this won't be an exact integration
    const tdouble* GP = GI->get_GP(GN);
    const tdouble* GW = GI->get_GW(GN);
  
  tdouble res=ZERO, dx, r, lx, t, sD_curr_x_2;
  for (tuint i=1;i<IntervalVecO.size();++i) {
    if (!IntervalVecO_geo[i-1]) continue;
    dx = (IntervalVecO[i]-IntervalVecO[i-1])/2.0;
    r = ZERO;
    for (tuint j=0;j<GN;++j) {
      lx = (GP[j]+ONE)*dx+IntervalVecO[i-1];
      update_globalConst_o(lx);
      assemble_Hx_EOLE(Hx,sD_curr_x_2,pointVec,sdVec);
      sD_curr_x_2 = pow2(sD_curr_x_2);
      t = sD_curr_x_2;
      for (tuint k=0;k<DIM;++k) {	// i+1 is odd
	t -= pow2( ( ptrEigenvectors->operator[](k) * Hx ) * ptrEigenvalues->operator[](k));
      }
      if (abs) t = fabs(t);
      r += t/sD_curr_x_2*GW[j];
    }
    r *=dx;
    res += r;
  }
  res *= calc_length()/2;
  return res;
}

const tdouble flxElement_KL_1D::calc_djNj2(const tdouble* dVec) const
{
  if (is_empty) return ZERO;
  const tdouble c0 = dVec[mapGlobal[0]];
  const tdouble c1 = dVec[mapGlobal[1]];
  const tdouble* cp = &(dVec[mapGlobal[2]]);
  const tuint GN = GI->pDegree2GPs(pOrder*2);
  const tdouble* GP = GI->get_GP(GN);
  const tdouble* GW = GI->get_GW(GN);
  const tdouble l = calc_length();
  tdouble d1=ZERO, d3, dx,lx;
  for (tuint k = 0; k < IntervalVec_GeoB.size(); ++k) {
    if (!IntervalVec_GeoB[k]) continue;
    dx = (IntervalVec_Geo[k+1]-IntervalVec_Geo[k])/2.0;
    d3 = ZERO;
    for (tuint i=0;i<GN;++i) {
      lx = IntervalVec_Geo[k] + dx + dx* GP[i];  // seems to be numerically better
      d3+=pow2(XXX_rlz(pOrder,lx,c0,c1,cp))*GW[i];
    }
    d3*=dx;
    d1+=d3;
  }
  return d1*l/2;  
}

const tdouble flxElement_KL_1D::calc_djNj(const tdouble* dVec, const tdouble& x, const tdouble& y, const tdouble& z) const
{
  return XXX_rlz(pOrder,x,dVec[mapGlobal[0]],dVec[mapGlobal[1]],&(dVec[mapGlobal[2]]));
}

const std::vector< tdouble >& flxElement_KL_1D::get_IntervalVec_err2(const int idx) const
{
  if (idx==0) {
    return IntervalVec_e2_i1;
  } else if (idx==2) {
    return IntervalVec_e2_o;
  } else {
    throw FlxException_Crude("flxElement_KL_1D::get_IntervalVec_err2");
  }
}

flxElement_KL_2D::flxElement_KL_2D(flxFace* face, FlxKLelementProp_2D& KLelProp)
: flxElement_KL_base(KLelProp.get_geo_fun(),false), pOrderLx(KLelProp.get_pOrderLx()), pOrderLy(KLelProp.get_pOrderLy()), tensorSpace(KLelProp.get_tensorSpace()), DegCorr(KLelProp.get_degCorr()), DegStd(KLelProp.get_degStd()),
pox(0),poy(0),N_local_DOF(0), djNj_xV(NULL),djNj_yV(NULL),djNj_bV(NULL),
face(face), mesh_single(NULL),mesh_single_cc(NULL),mesh_outer(NULL),mesh_outer_cc(NULL),mesh_inner_s(NULL),mesh_inner_s_cc(NULL),mesh_inner_d(NULL),mesh_inner_d_cc(NULL),
mesh_err_is(NULL),mesh_err_is_cc(NULL),mesh_err_id(NULL),mesh_err_id_cc(NULL),
area_min_level(KLelProp.get_area_min_level()),area_max_level(KLelProp.get_area_max_level()),
EOLE_SMP_MTH(KLelProp.get_EOLE_SMP_MTH()),EOLE_N_LX(KLelProp.get_EOLE_N_LX()),EOLE_N_LY(KLelProp.get_EOLE_N_LY()),EOLE_N(KLelProp.get_EOLE_N()),
CovThreshold(KLelProp.get_covThreshold())
{
  face->set_DegStd(DegStd);
  face->set_DegCorr(DegCorr);
  // just a temporary assignment (needed for mesh-refinement)
    pox = pOrderLx;
    poy = pOrderLy;
  KLelProp.set_face(face);
  // refine the mesh
    mesh_single = KLelProp.refine_single(maxtree_single,mesh_single_cc);
    mesh_outer = KLelProp.refine_outer(maxtree_outer,mesh_outer_cc);
    // inner, same (and different) element
      mesh_inner_s = KLelProp.refine_inner_s(maxtree_inner_s,mesh_inner_s_cc);
      mesh_inner_d = KLelProp.refine_inner_d(maxtree_inner_d,mesh_inner_d_cc);
    mesh_err_is = KLelProp.refine_err_is(mesh_err_is_cc);
    mesh_err_id = KLelProp.refine_err_id(mesh_err_id_cc);
  // check if enough Gauss-points are loaded
    GI->check_GA_polynomialDegree(pOrderLx*2);
    GI->check_GA_polynomialDegree(pOrderLy*2);
    GI->check_GA_polynomialDegree(pOrderLx+DegStd+DegCorr);
    GI->check_GA_polynomialDegree(pOrderLy+DegStd+DegCorr);
    GI->check_GA_polynomialDegree(GI->pDegree2GPs(DegCorr+DegStd*2));
  // make sure that enough shape functions are available
    XXX_check_order(pOrderLx);
    XXX_check_order(pOrderLy);
  // check ...
    if (CovThreshold>=0.5) {
      std::ostringstream ssV;
      ssV << "cov_threshold too large (" << GlobalVar.Double2String(CovThreshold) << ")";
      GlobalVar.alert.alert("flxElement_KL_2D::flxElement_KL_2D",ssV.str());
    }
}

flxElement_KL_2D::~flxElement_KL_2D()
{
  if (djNj_xV) delete djNj_xV;
  if (djNj_yV) delete djNj_yV;
  if (djNj_bV) delete djNj_bV;
  if (mesh_single) delete [] mesh_single;
  if (mesh_outer) delete [] mesh_outer;
  if (mesh_inner_s) delete [] mesh_inner_s;
  if (mesh_inner_d) delete [] mesh_inner_d;
  if (mesh_err_is) delete [] mesh_err_is;
  if (mesh_err_id) delete [] mesh_err_id;
  if (mesh_single_cc) delete [] mesh_single_cc;
  if (mesh_outer_cc) delete [] mesh_outer_cc;
  if (mesh_inner_s_cc) delete [] mesh_inner_s_cc;
  if (mesh_inner_d_cc) delete [] mesh_inner_d_cc;
  if (mesh_err_is_cc) delete [] mesh_err_is_cc;
  if (mesh_err_id_cc) delete [] mesh_err_id_cc;
}

void flxElement_KL_2D::update_globalConst_i(const tdouble& lxV, const tdouble& lyV) const
{
  // update GX,GY,GZ
    face->update_globalConst(lxV,lyV);
  // update DELTAs
    *(GX2+3) = fabs(*(GX2+0) - *(GX2-3));
    *(GX2+4) = fabs(*(GX2+1) - *(GX2-2));
    *(GX2+5) = fabs(*(GX2+2) - *(GX2-1));
    *(GX2+6) = sqrt(pow2(*(GX2+3)) + pow2(*(GX2+4)) + pow2(*(GX2+5)));
}

#if FLX_KAHAN_FCRF
void flxElement_KL_2D::calc_local_corrMtx_KLE_inner(flxpVec& t, const bool sameElement) const
#else
void flxElement_KL_2D::calc_local_corrMtx_KLE_inner(flxVec& t, const bool sameElement) const
#endif
{
  t.set_zero();
  if (is_empty) return;
  flxVec r(t.get_N());
  flxVec s(t.get_N());
  flxVec rx(pox+1);
  flxVec ry(poy+1);
  maxtree_inner_now = (sameElement)?maxtree_inner_s:maxtree_inner_d;
  tdouble* ccpos = (sameElement)?mesh_inner_s_cc:mesh_inner_d_cc;
  const tuint* vpos = (sameElement)?mesh_inner_s:mesh_inner_d;
  const tuint GNx = GI->pDegree2GPs(get_polydeg_innerIntegral_X());
  const tuint GNy = GI->pDegree2GPs(get_polydeg_innerIntegral_Y());
  calc_local_corrMtx_KLE_inner_rec(0,vpos,ccpos,GNx,GNy,ZERO,ZERO,t,r,s,rx,ry);
}

#if FLX_KAHAN_FCRF
void flxElement_KL_2D::calc_local_corrMtx_KLE_inner_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxpVec& t, flxVec& r, flxVec& s, flxVec& rx, flxVec& ry) const
#else
void flxElement_KL_2D::calc_local_corrMtx_KLE_inner_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxVec& t, flxVec& r, flxVec& s, flxVec& rx, flxVec& ry) const
#endif
{
  switch (*vpos) {
    case 0:		// parent
    {
      update_GN(level,maxtree_inner_now,GNx,GNy); // reduce number of Gauss-points
      const tdouble dhh = dha[level+1];
      ++vpos; 
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym-dhh,t,r,s,rx,ry);
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym-dhh,t,r,s,rx,ry);
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym+dhh,t,r,s,rx,ry);
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym+dhh,t,r,s,rx,ry);
      return;
    }
    case 1:		// no geometry
      ++vpos;
      return;
    case 2:		// mixed
    {
      const tdouble dh = dha[level];
      tdouble* rxp = rx.get_tmp_vptr();
      tdouble* ryp = ry.get_tmp_vptr();
      tdouble* sp = s.get_tmp_vptr();
      const tdouble xt = *(ccpos++), yt = *(ccpos++);
      update_globalConst_i(xt,yt);
      const tdouble f = ptrFunSigma->calc()*ptrFunRho->calc() * 4.0 * face->get_detJ(xt,yt) * dh*dh * (*(ccpos++));
      XXX_vec(rx,xt);
      XXX_vec(ry,yt);
      XXX_2D_base(sp,rxp,ryp);
      s*=f;
      t+=s;
      ++vpos;
      return;
    }
    case 3:
    default:		// full
    {
      const tdouble dh = dha[level];
      tdouble* rxp = rx.get_tmp_vptr();
      tdouble* ryp = ry.get_tmp_vptr();
      tdouble* sp = s.get_tmp_vptr();
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GNx);
	const tdouble* GWx = GI->get_GW(GNx);
	const tdouble* GPy = GI->get_GP(GNy);
	const tdouble* GWy = GI->get_GW(GNy);
      // integration
	r=ZERO;
	tdouble lx,ly,sigma_eval;
	for (tuint i=0;i<GNx;++i) {
	  lx = xm+dh*GPx[i];
	  XXX_vec(rx,lx);
	  for (tuint j=0;j<GNy;++j) {
	    ly = ym+dh*GPy[j];
	    update_globalConst_i(lx,ly);
	    sigma_eval = ptrFunSigma->calc()*ptrFunRho->calc() * GWx[i]*GWy[j]*face->get_detJ(lx,ly);
	    XXX_vec(ry,ly);
	    XXX_2D_base(sp,rxp,ryp);
	    s*=sigma_eval;
	    r+=s;
	  }
	}
	r*=dh*dh;
	#if FLX_KAHAN_FCRF
	  pVec_add(t,r);
	#else
	  t+=r;
	#endif
      ++vpos;
      return;
    }
  }
}

void flxElement_KL_2D::get_error_2i_el(const bool sameEl, tdouble& integ_Cov, tdouble& integ_Err, const tdouble& sDx, const flxVec& tr) const
{
  throw FlxException_NotImplemented("flxElement_KL_2D::get_error_2i_el");
}

void flxElement_KL_2D::get_error_1i_el(const bool sameEl, flxVec& tr, flxVec& tri) const
{
  tr.set_zero();
  if (is_empty) return;
  // integration
    tdouble* ccpos = (sameEl)?mesh_err_is_cc:mesh_err_id_cc;
    const tuint* vpos = (sameEl)?mesh_err_is:mesh_err_id;
    maxtree_inner_now = (sameEl)?maxtree_inner_s:maxtree_inner_d;
    const tuint GNx = GI->pDegree2GPs(pox+DegStd+DegCorr+(face->get_is_detJ_const()?0:1));
    const tuint GNy = GI->pDegree2GPs(poy+DegStd+DegCorr+(face->get_is_detJ_const()?0:1));
    get_error_1i_el_rec(0,vpos,ccpos,GNx,GNy,ZERO,ZERO,tr,tri);
}

void flxElement_KL_2D::get_error_1i_el_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxVec& tr, flxVec& tri) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      update_GN(level,maxtree_inner_now,GNx,GNy);
      const tdouble dhh = dha[level+1];
      ++vpos;
      if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym-dhh,tr,tri);
      if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym-dhh,tr,tri);
      if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym+dhh,tr,tri);
      if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym+dhh,tr,tri);
      return;
    }
    case 1:		// no geometry
      ++vpos;
      return;
    case 2:		// mixed
    {
      const size_t DIM = ptrEigenvectors->size();
      const tdouble dh = dha[level];
      const tdouble xt = *(ccpos++), yt = *(ccpos++);
      update_globalConst_i(xt,yt);
      tdouble t = ptrFunRho->calc()*ptrFunSigma->calc()*4.0*face->get_detJ(xt,yt)*(*(ccpos++))*dh*dh;
      for (tuint k=0;k<DIM;++k) {
	tri[k] = t*calc_djNj(&(ptrEigenvectors->operator[](k))[0],xt,yt,ZERO);
      }
      tr+=tri;
      ++vpos;
      return;
    }
    case 3:
    default:		// full
    {
      const size_t DIM = ptrEigenvectors->size();
      // get Gauss points
	  const tdouble* GPx = GI->get_GP(GNx);
	  const tdouble* GWx = GI->get_GW(GNx);
	  const tdouble* GPy = GI->get_GP(GNy);
	  const tdouble* GWy = GI->get_GW(GNy);
      // integration
	const tdouble dh = dha[level];
	tdouble lx,ly,t;
	tri.set_zero();
	for (tuint i=0;i<GNx;++i) {
	  lx = xm+dh*GPx[i];
	  for (tuint j=0;j<GNy;++j) {
	    ly = ym+dh*GPy[j];
	    update_globalConst_i(lx,ly);
	    t = ptrFunRho->calc()*ptrFunSigma->calc()*GWx[i]*GWy[j]*face->get_detJ(lx,ly);
	    for (tuint k=0;k<DIM;++k) {
	      tri[k] += t*calc_djNj(&(ptrEigenvectors->operator[](k))[0],lx,ly,ZERO);
	    }
	  }
	}
	tri*=dh*dh;
	tr+=tri;
      ++vpos;
      return;
    }
  }
}

void flxElement_KL_2D::get_error_2i_el_EOLE(const bool sameEl, tdouble& integ_Cov, tdouble& integ_Err, const tdouble& sDx, const flxVec& tr, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, flxVec& Hx) const
{
  throw FlxException_NotImplemented("flxElement_KL_2D::get_error_2i_el_EOLE");
}

void flxElement_KL_2D::XXX_2D_base(tdouble* res, const tdouble* rxp, const tdouble* ryp) const
{
  // nodal DOFs
    res[0] = rxp[0]*ryp[0];
    res[1] = rxp[1]*ryp[0];
    res[2] = rxp[1]*ryp[1];
    res[3] = rxp[0]*ryp[1];
  // edge DOFs
    tuint c = 4;
    XXX_2D_bemc(&res[c],rxp,ryp[0],0); c+=edgeDOFpOrder[0]-1;
    XXX_2D_bemc(&res[c],ryp,rxp[1],1); c+=edgeDOFpOrder[1]-1;
    XXX_2D_bemc(&res[c],rxp,ryp[1],2); c+=edgeDOFpOrder[2]-1;
    XXX_2D_bemc(&res[c],ryp,rxp[0],3); c+=edgeDOFpOrder[3]-1;
  // bubble-DOFs
    if (tensorSpace) {
      for (tuint i=2;i<=pOrderLx;++i) {
	for (tuint j=2;j<=pOrderLy;++j) {
	  res[c++] = rxp[i]*ryp[j];
	}
      }
    } else {
      const tuint MAX = (pOrderLx>=pOrderLy)?pOrderLx:pOrderLy;
      for (tuint i=2;i<=MAX-2 && i<=pOrderLx;++i) {
	for (tuint j=2;j<=pOrderLy && i+j<=MAX;++j) {
	  res[c++] = rxp[i]*ryp[j];
	}
      }
    }
}

inline void flxElement_KL_2D::XXX_2D_bemc(tdouble* res, const tdouble* r1p, const tdouble& r2p, tuint i) const
{
  if (edgOrient[i]) {
    for (tuint k=2;k<=edgeDOFpOrder[i];++k) {
      res[k-2] = r1p[k]*r2p;
    }
  } else {
    for (tuint k=2;k<=edgeDOFpOrder[i];k+=2) {
      res[k-2] = r1p[k]*r2p;
    }
    for (tuint k=3;k<=edgeDOFpOrder[i];k+=2) {
      res[k-2] = -ONE*r1p[k]*r2p;
    }
  }
}

const tdouble flxElement_KL_2D::XXX_2D_rlz(const tdouble* rxp, const tdouble* ryp, const tdouble* d) const
{
  // vertices
    tdouble t = rxp[0]*ryp[0]*d[mapGlobal[0]]+rxp[1]*ryp[0]*d[mapGlobal[1]]+rxp[1]*ryp[1]*d[mapGlobal[2]]+rxp[0]*ryp[1]*d[mapGlobal[3]] ;
  // edges
    t+= XXX_2D_emc(rxp,&d[mapGlobal[4]],0)*ryp[0];
    t+= XXX_2D_emc(ryp,&d[mapGlobal[5]],1)*rxp[1];
    t+= XXX_2D_emc(rxp,&d[mapGlobal[6]],2)*ryp[1];
    t+= XXX_2D_emc(ryp,&d[mapGlobal[7]],3)*rxp[0];
  // bubble-modes
    const tdouble* dp2 = &d[mapGlobal[8]];
    tuint c=0;
    if (tensorSpace) {
      for (tuint i=2;i<=pOrderLx;++i) {
	for (tuint j=2;j<=pOrderLy;++j) {
	  t += rxp[i]*ryp[j]*dp2[c++];
	}
      }
    } else {
      const tuint MAX = (pOrderLx>=pOrderLy)?pOrderLx:pOrderLy;
      for (tuint i=2;i<=MAX-2 && i<=pOrderLx;++i) {
	for (tuint j=2;j<=pOrderLy && i+j<=MAX;++j) {
	  t += rxp[i]*ryp[j]*dp2[c++];
	}
      }
    }
  return t;
}

const tdouble flxElement_KL_2D::XXX_2D_emc(const tdouble* rp, const tdouble* de, tuint i) const
{
  tdouble t = ZERO;
  if (edgOrient[i]) {
    for (tuint k=2;k<=edgeDOFpOrder[i];++k) {
      t += rp[k]*de[k-2];
    }
  } else {
    for (tuint k=2;k<=edgeDOFpOrder[i];k+=2) {
      t += rp[k]*de[k-2];
    }
    for (tuint k=3;k<=edgeDOFpOrder[i];k+=2) {
      t -= rp[k]*de[k-2];
    }
  }
  return t;
}

inline void flxElement_KL_2D::update_GN(const tuint prev_level, const tuint max_level, tuint& GNx, tuint& GNy) const
{
//   if (prev_level%2==1) {
//   if (prev_level%2==1 && prev_level>1) {		// next level is odd
//   if (prev_level>=3) {
//   if (prev_level%2==0 && prev_level>1) {
  if (prev_level>=4 || prev_level==2) {
    GNx=(GNx+1)/2;
    GNy=(GNy+1)/2;
    if (prev_level+1<max_level) {
      if (GNx==1) GNx=2;
      if (GNy==1) GNy=2;
    }
  }
}

inline void flxElement_KL_2D::update_GN_mass(const tuint prev_level, const tuint max_level, tuint& GNx, tuint& GNy) const
{
//   if (prev_level%2==1) {
//   if (prev_level%2==1 && prev_level>1) {		// next level is odd
//   if (prev_level>=3) {
//   if (prev_level%2==0 && prev_level>1) {
  if (prev_level>=6) {
    GNx=(GNx+1)/2;
    GNy=(GNy+1)/2;
    if (prev_level+1<max_level) {
      if (GNx==1) GNx=2;
      if (GNy==1) GNy=2;
    }
  }
}

void flxElement_KL_2D::get_mesh_topology(const tuint level, const_tuintPtr& vpos, std::vector< tuint >& topV) const
{
  if (level+1 > topV.size()) {
    topV.push_back(0);
  }
  switch (*vpos) {
    case 0:		// parent
    {
      ++vpos;
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      return;
    }
    case 1:
      ++vpos;
      return;
    default:		// mixed or full
    {
      ++vpos;
      ++topV[level];
      return;
    }
  }
}

const tdouble flxElement_KL_2D::check_cov_val() const
{
  tdouble max = ZERO;
  for (tdouble i=-ONE;i<1.5;i+=2.0) {
    for (tdouble j=-ONE;j<1.5;j+=2.0) {
      update_globalConst_i(i,j);
      const tdouble t = fabs(ptrFunRho->calc());
      if (t>max) max = t;
    }
  }
  return max;
}

void flxElement_KL_2D::log_report(const tuint rfindex, const std::string& elID, const flxElement_KL_base::rftype rft) const
{
  std::vector<tuint> topV; const tuint* vpos;
  
  GlobalVar.slog(4) << "Assigned '" << elID << "' to random field " << rfindex << "." << std::endl << "  ";
  
  if (rft == rfKLfemGauss) {
    GlobalVar.slog(4) << "pOrder=(" << pOrderLx << "," << pOrderLy << "); ";
    GlobalVar.slog(4) << "tensorSp=(" << (tensorSpace?"yes":"no") << "); ";
  }
  
  if (rft == rfKLfemGauss) {
    topV.clear();
    vpos = mesh_outer;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_outer=" << topV << "; ";
    topV.clear();
    vpos = mesh_inner_s;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_inner_s=" << topV << ":(";
    {
      tuint GN[2] = {GI->pDegree2GPs(get_polydeg_innerIntegral_X()),GI->pDegree2GPs(get_polydeg_innerIntegral_Y())};
      for (tuint i=0;i<topV.size();++i) {
	if (i>0) GlobalVar.slog(4) << ",";
	if (GN[0]==GN[1]) {
	  GlobalVar.slog(4) << GN[0];
	} else {
	  GlobalVar.slog(4) << "[" << GN[0] << "," << GN[1] << "]";
	}
	update_GN(i,maxtree_inner_s,GN[0],GN[1]);
      }
    }
    GlobalVar.slog(4) << "); ";
    topV.clear();
    vpos = mesh_inner_d;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_inner_d=" << topV << ":(";
    {
      tuint GN[2] = {GI->pDegree2GPs(get_polydeg_innerIntegral_X()),GI->pDegree2GPs(get_polydeg_innerIntegral_Y())};
      for (tuint i=0;i<topV.size();++i) {
	if (i>0) GlobalVar.slog(4) << ",";
	if (GN[0]==GN[1]) {
	  GlobalVar.slog(4) << GN[0];
	} else {
	  GlobalVar.slog(4) << "[" << GN[0] << "," << GN[1] << "]";
	}
	update_GN(i,maxtree_inner_d,GN[0],GN[1]);
      }
    }
    GlobalVar.slog(4) << "); ";
  }
  if ( rft == rfEOLEgauss ) {
    GlobalVar.slog(4) << "eole_points=(";
    switch (EOLE_SMP_MTH) {
      case (1):
	GlobalVar.slog(4) << "uniform grid," << EOLE_N_LX << "," << EOLE_N_LY;
	break;
      case (2):
	GlobalVar.slog(4) << "random smp," << EOLE_N;
	break;
      default:
	break;
    }
    GlobalVar.slog(4) << "); ";
  }
  GlobalVar.slog(4) << "degCorr=" << DegCorr << "; ";
  if ( rft != rfKLAnaExpCorrGauss1D ) {
    GlobalVar.slog(4) << "degStd=" << DegStd << "; ";
    GlobalVar.slog(4) << "areaLevel=(" << area_min_level << "," << area_max_level << "); ";
  }
  if ( rft != rfKLAnaExpCorrGauss1D ) {
    topV.clear();
    vpos = mesh_single;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_single=" << topV << "; ";
    GlobalVar.slog(4) << "domain_el=" << GlobalVar.Double2String(calc_domain(true)) << "; ";
  }
  if ( rft == rfKLfemGauss ) {
    topV.clear();
    vpos = mesh_err_is;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_err_is=" << topV << "; ";
    topV.clear();
    vpos = mesh_err_id;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_err_id=" << topV << "; ";
  }
  
  GlobalVar.slog(4) << std::endl;
}

const tdouble flxElement_KL_2D::calc_domain(const bool considerGeo) const
{
  if (considerGeo && geo_fun) {
    if (is_empty) return ZERO;
    return calc_domain_rec(0,ZERO,ZERO);
  } else {
    return calc_area();
  }
}

const tdouble flxElement_KL_2D::calc_domain_rec(const tuint level, const tdouble xm, const tdouble ym) const
{
  const tdouble dh = dha[level];
  const tdouble dhk = dh*0.99;
  bool gb[5];
  update_globalConst(xm-dhk,ym-dhk);
    gb[0] = (geo_fun->calc()>=ZERO);
  update_globalConst(xm+dhk,ym-dhk);
    gb[1] = (geo_fun->calc()>=ZERO);
  update_globalConst(xm+dhk,ym+dhk);
    gb[2] = (geo_fun->calc()>=ZERO);
  update_globalConst(xm-dhk,ym+dhk);
    gb[3] = (geo_fun->calc()>=ZERO);
  update_globalConst(xm,ym);
  gb[4] = (geo_fun->calc()>=ZERO);
    bool same=true;
  for (tuint i=1;i<5;++i) {
    if (gb[0]!=gb[i]) {
      same = false;
      break;
    }
  }
  if ((area_min_level>level || !same) && area_max_level>level) {
    const tdouble dhh = dha[level+1];
    tdouble res = ZERO;
    res+=calc_domain_rec(level+1,xm-dhh,ym-dhh);
    res+=calc_domain_rec(level+1,xm+dhh,ym-dhh);
    res+=calc_domain_rec(level+1,xm+dhh,ym+dhh);
    res+=calc_domain_rec(level+1,xm-dhh,ym+dhh);
    return res;
  } else {
    const tdouble a = face->get_detJ(xm,ym)*4.0*dh*dh;
    const tuint ID = (gb[0]?1:0)+(gb[1]?2:0)+(gb[2]?4:0)+(gb[3]?8:0)+(gb[4]?16:0);
    switch (ID) {
      case 0:
	return ZERO;
      case 1:
      case 2:
	return a/8;
      case 3:
	return 0.3125*a;
      case 4:
	return a/8;
      case 5:
	return a/4;
      case 6:
	return 0.3125*a;
      case 7:
	return a/2;
      case 8:
	return a/8;
      case 9:
	return 0.3125*a;
      case 10:
	return a/4;
      case 11:
	return a/2;
      case 12:
	return 0.3125*a;
      case 13:
      case 14:
	return a/2;
      case 15:
	return 0.75*a;
      case 16:
	return a/4;
      case 17:
      case 18:
	return a/2;
      case 19:
	return 0.6875*a;
      case 20:
	return a/2;
      case 21:
	return 0.75*a;
      case 22:
	return 0.6875*a;
      case 23:
	return 0.875*a;
      case 24:
	return a/2;
      case 25:
	return 0.6875*a;
      case 26:
	return 0.75*a;
      case 27:
	return 0.875*a;
      case 28:
	return 0.6875*a;
      case 29:
      case 30:
	return 0.875*a;
      case 31:
	return a;
      default:
	#if FLX_DEBUG
	  throw FlxException_Crude("flxElement_KL_2D::calc_domain_rec");
	#else
	  return ZERO;
	#endif
    }
  }
}

void flxElement_KL_2D::countDOFs(niMap& nodalM, eiMap& edgeM, fiMap& faceM, std::vector< const flxVertex* >& nV, std::vector< const flxEdge* >& eV, std::vector< const flxFace* >& fV)
{
  if (is_empty) return;
  // deal with vertices
    std::map<const flxVertex*,tnlong>::iterator pos;
    for (tuint i=0;i<4;++i) {
      flxVertex& v = face->get_vertex(i);
      pos = nodalM.find(&v);
      if ( pos == nodalM.end() ) {
	std::pair<const flxVertex*,tnlong>Element(&v, 0);
	nodalM.insert(Element);
	nV.push_back(&v);
      }
    }
  // deal with edges
    std::map<const flxEdge*,eiMap_sec>::iterator posE;
    for (tuint i=0;i<4;++i) {
      edgOrient[i] = face->get_edge_Orient(i);
      flxEdge& e = face->get_edge(i);
      posE = edgeM.find(&e);
      if ( posE == edgeM.end() ) {	// edge does not yet exist
	eiMap_sec ems; ems.dofindex=0; ems.count = ((i==0||i==2)?(pOrderLx):(pOrderLy))-1;
	std::pair<const flxEdge*,eiMap_sec>Element(&e,ems);
	edgeM.insert(Element);
	eV.push_back(&e);
      } else {				// edge already exists
	tuint c = ((i==0||i==2)?(pOrderLx):(pOrderLy))-1;
	if (posE->second.count < c) posE->second.count = c;	// choose the larger polynomial degree
      }
    }
  // deal with faces
    std::map<const flxFace*,fiMap_sec>::iterator posF;
    posF = faceM.find(face);
    if ( posF == faceM.end() ) {	// vertex is NOT in the list
      fiMap_sec ems; ems.dofindex=0; 
      if (tensorSpace) {
	ems.count = (pOrderLx-1)*(pOrderLy-1);
      } else {
	const tuint max = (pOrderLx>=pOrderLy)?pOrderLx:pOrderLy;
	const tuint min = (pOrderLx<=pOrderLy)?pOrderLx:pOrderLy;
	if (min<=1) {
	  ems.count = 0;
	} else {
	  ems.count = (max*max+6-5*max)/2;
	  if (max-min>2) {
	    const tuint m = max-min-2;
	    ems.count -= (m*m+m)/2;
	  }
	}
      }
      std::pair<const flxFace*,fiMap_sec>Element(face,ems);
      faceM.insert(Element);
      fV.push_back(face);
    } else {				// vertex is already in the list
      throw FlxException("flxElement_KL_2D::countDOFs","There is something wrong with the geometrical definition of the random field.");
    }
}

void flxElement_KL_2D::assembleDOFs(const niMap& nodalM, const eiMap& edgeM, fiMap& faceM)
{
  if (is_empty) return;
  // deal with vertices
    std::map<const flxVertex*,tnlong>::const_iterator pos;
    for (tuint i=0;i<4;++i) {
      pos = nodalM.find(&(face->get_vertex(i)));
      #if FLX_DEBUG
	if ( pos == nodalM.end() ) { throw FlxException_Crude("flxElement_KL_2D::assembleDOFs_1"); }
      #endif
      mapGlobal[i] = pos->second;
    }
  // deal with edges
    std::map<const flxEdge*,eiMap_sec>::const_iterator posE;
    for (tuint i=0;i<4;++i) {
      posE = edgeM.find(&(face->get_edge(i)));
      #if FLX_DEBUG
	if ( posE == edgeM.end() ) { throw FlxException_Crude("flxElement_KL_2D::assembleDOFs_2"); }
      #endif
      mapGlobal[i+4] = posE->second.dofindex;
      edgeDOFpOrder[i] = posE->second.count+1;
    }
  // deal with faces
      std::map<const flxFace*,fiMap_sec>::const_iterator posF;
      posF = faceM.find(face);
      #if FLX_DEBUG
	if ( posF == faceM.end() ) { throw FlxException_Crude("flxElement_KL_2D::assembleDOFs_3"); }
      #endif
      mapGlobal[8] = (posF->second).dofindex;
  // determine maximal polynomial orders
    pox = pOrderLx;
      if (edgeDOFpOrder[0]>pox) pox = edgeDOFpOrder[0];
      if (edgeDOFpOrder[2]>pox) pox = edgeDOFpOrder[0];
    poy = pOrderLy;
      if (edgeDOFpOrder[1]>poy) poy = edgeDOFpOrder[0];
      if (edgeDOFpOrder[3]>poy) poy = edgeDOFpOrder[0];
  // determine number of local DOFs
    N_local_DOF = 0;
    for (tuint i=0;i<4;++i) {
      N_local_DOF+=edgeDOFpOrder[i];
    }
    N_local_DOF+=(posF->second).count;
  // create helping values
    djNj_x = ZERO;
    djNj_y = ZERO;
    djNj_xV = new flxVec(pox+1);
    djNj_yV = new flxVec(poy+1);
    djNj_bV = new flxVec(N_local_DOF);
    XXX_vec(*djNj_xV,djNj_x);
    XXX_vec(*djNj_yV,djNj_y);
    XXX_2D_base(&(*djNj_bV)[0],&(*djNj_xV)[0],&(*djNj_yV)[0]);
}

void flxElement_KL_2D::calc_local_MassMatrix_KLE(FlxMtxSym& Mmtx)
{
  if (is_empty) return;
  // integration (assembly)
    #if FLX_KAHAN_FCRF
    flxpVec M((pow2(N_local_DOF)+N_local_DOF)/2);		// stores the local mass matrix
    #else
    flxVec M((pow2(N_local_DOF)+N_local_DOF)/2);		// stores the local mass matrix
    #endif
    flxVec Mi(M.get_N());		// for the inner loop
    flxVec rx(pox+1);
    flxVec ry(poy+1);
    tdouble* ccpos = mesh_single_cc;
    const tuint* vpos = mesh_single;
    const tuint GNx = GI->pDegree2GPs(pox*2+(face->get_is_detJ_const()?0:1));
    const tuint GNy = GI->pDegree2GPs(poy*2+(face->get_is_detJ_const()?0:1));
    calc_local_MassMatrix_KLE_rec(0,vpos,ccpos,GNx,GNy,ZERO,ZERO,M,Mi,rx,ry);	// assembles the local mass matrix
  // map the local matrix to the global matrix
    #if FLX_KAHAN_FCRF
      Mi = M;
      const tdouble* dp = Mi.get_tmp_vptr();
    #else
      const tdouble* dp = M.get_tmp_vptr();
    #endif
    tuint c = 0;
    // vertice-rows
      for (tuint i=0;i<4;++i) {
	for (tuint j=0;j<=i;++j) {
	  Mmtx.add_value(mapGlobal[i],mapGlobal[j],dp[c++]);
	}
      }
    tuint r = 4;
    // edge-rows
      for (tuint i=0;i<4;++i) {		// over edges
	const tuint S = edgeDOFpOrder[i]-1;
	r+=S;
	for (tuint j=0;j<S;++j) {		// over edge DOF of edge i
	  for (tuint k=0;k<4;++k) {			// over nodal DOFs
	    Mmtx.add_value(mapGlobal[4+i]+j,mapGlobal[k],dp[c++]);
	  }
	  for (tuint k=0;k<i;++k) {			// over (full) edges
	    const tuint S2 = edgeDOFpOrder[k]-1;
	    for (tuint l=0;l<S2;++l) {
	      Mmtx.add_value(mapGlobal[4+i]+j,mapGlobal[4+k]+l,dp[c++]);
	    }
	  }
	  for (tuint k=0;k<=j;++k) {			// over this edge
	    Mmtx.add_value(mapGlobal[4+i]+j,mapGlobal[4+i]+k,dp[c++]);
	  }
	}
      }
    // bubble-rows
      tuint Ni = N_local_DOF-r;	// number of internal DOFs
      for (tuint i=0;i<Ni;++i) {
	for (tuint j=0;j<4;++j) {			// over nodal DOFs
	  Mmtx.add_value(mapGlobal[8]+i,mapGlobal[j],dp[c++]);
	}
	for (tuint j=0;j<4;++j) {			// over edge DOFs
	  const tuint S = edgeDOFpOrder[j]-1;
	  for (tuint k=0;k<S;++k) {
	    Mmtx.add_value(mapGlobal[8]+i,mapGlobal[4+j]+k,dp[c++]);
	  }
	}
	for (tuint j=0;j<=i;++j) {			// over bubble DOFs
	  Mmtx.add_value(mapGlobal[8]+i,mapGlobal[8]+j,dp[c++]);
	}
      }
}

#if FLX_KAHAN_FCRF
void flxElement_KL_2D::calc_local_MassMatrix_KLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxpVec& M, flxVec& Mi, flxVec& rx, flxVec& ry) const
#else
void flxElement_KL_2D::calc_local_MassMatrix_KLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxVec& M, flxVec& Mi, flxVec& rx, flxVec& ry) const
#endif
{
  switch (*vpos) {
    case 0:		// parent
    {
      update_GN_mass(level,maxtree_single,GNx,GNy);
      const tdouble dhh = dha[level+1];
      ++vpos;
      #if FLX_FC_STABLE
	calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym-dhh,M,Mi,rx,ry);
	calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym-dhh,M,Mi,rx,ry);
	calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym+dhh,M,Mi,rx,ry);
	calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym+dhh,M,Mi,rx,ry);
      #else 
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym-dhh,M,Mi,rx,ry);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym-dhh,M,Mi,rx,ry);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym+dhh,M,Mi,rx,ry);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym+dhh,M,Mi,rx,ry);
      #endif
      return;
    }
    #if FLX_FC_STABLE
    #else
    case 1:		// no geometry
      ++vpos;
      return;
    #endif
    case 2:
    {
      #ifndef FLX_CV_1
	tdouble shapeFun[N_local_DOF];
      #else
	tdouble *shapeFun = new tdouble[N_local_DOF];
      #endif
      tdouble* rxp = rx.get_tmp_vptr();
      tdouble* ryp = ry.get_tmp_vptr();
      tdouble* Mip = Mi.get_tmp_vptr();
      const tdouble dh = dha[level];
      const tdouble xt=*(ccpos++), yt=*(ccpos++);
      XXX_vec(rx,xt);
      XXX_vec(ry,yt);
      XXX_2D_base(shapeFun,rxp,ryp);
      #if FLX_FC_STABLE
	const tdouble Ap = (*(ccpos++));
	const tdouble f = 4.0*face->get_detJ(xt,yt)*dh*dh*Ap;
	const tdouble fstab = 4.0*face->get_detJ(xt,yt)*dh*dh*(ONE-Ap)/FLX_FC_STABLE_DIV;
      #else
	const tdouble f = 4.0*face->get_detJ(xt,yt)*dh*dh*(*(ccpos++));
      #endif
      tuint c=0;
      for (tuint k=0;k<N_local_DOF;++k) {
	for (tuint l=0;l<=k;++l) {
	  #if FLX_FC_STABLE
	    Mip[c++]=(f+fstab)*shapeFun[k]*shapeFun[l];
	  #else
	    Mip[c++]=f*shapeFun[k]*shapeFun[l];
	  #endif
	}
      }
      #if FLX_KAHAN_FCRF
      pVec_add(M,Mi);
      #else
      M+=Mi;
      #endif
      #ifdef FLX_CV_1
	delete [] shapeFun;
      #endif
      ++vpos;
      return;
    }
    #if FLX_FC_STABLE
    case 1:
    #endif
    case 3:
    default:		// mixed or full
    {
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GNx);
	const tdouble* GWx = GI->get_GW(GNx);
	const tdouble* GPy = GI->get_GP(GNy);
	const tdouble* GWy = GI->get_GW(GNy);
      // integration
	Mi=ZERO;
	#ifndef FLX_CV_1
	  tdouble shapeFun[N_local_DOF];
	#else
	  tdouble *shapeFun = new tdouble[N_local_DOF];
	#endif
	tdouble* rxp = rx.get_tmp_vptr();
	tdouble* ryp = ry.get_tmp_vptr();
	tdouble* Mip = Mi.get_tmp_vptr();
	const tdouble dh = dha[level];
	tdouble lx,ly,f;
	for (tuint i=0;i<GNx;++i) {
	  lx = xm+dh*GPx[i];
	  XXX_vec(rx,lx);
	  for (tuint j=0;j<GNy;++j) {
	    ly = ym+dh*GPy[j];
	    XXX_vec(ry,ly);
	    XXX_2D_base(shapeFun,rxp,ryp);
	    f = GWx[i]*GWy[j]*face->get_detJ(lx,ly);
	    tuint c=0;
	    for (tuint k=0;k<N_local_DOF;++k) {
	      for (tuint l=0;l<=k;++l) {
		Mip[c++]+=f*shapeFun[k]*shapeFun[l];
	      }
	    }
	  }
	}
	#if FLX_FC_STABLE
	  if ( *vpos==1 ) {	// geometry at this point
	    Mi*=dh*dh/FLX_FC_STABLE_DIV;
	  } else {
	    Mi*=dh*dh;
	  }
	#else
	  Mi*=dh*dh;
	#endif
	#if FLX_KAHAN_FCRF
	pVec_add(M,Mi);
	#else
	M+=Mi;
	#endif
	#ifdef FLX_CV_1
	  delete [] shapeFun;
	#endif
      ++vpos;
      return;
    }
  }
}

void flxElement_KL_2D::calc_local_collocMtx(const tnlong nid, FlxMtx& Amtx, const tdouble& sd)
{
  throw FlxException_NotImplemented("flxElement_KL_1D::calc_local_collocMtx");
}

void flxElement_KL_2D::calc_local_corrMtx_KLE(FlxMtxSym& Cmtx, std::vector< flxElement_KL_base* >& ElVec) const
{
  if (is_empty) return;
  tuint Ni2;
  flxVec s(N_local_DOF);						// stores precomputed shape functions
  flxElement_KL_2D* ce;
  for (tuint i=0;i<ElVec.size();++i) {				// perform the integration for each element
    ce = dynamic_cast<flxElement_KL_2D*>(ElVec[i]);
    if (ce==NULL) {
      throw FlxException("flxElement_KL_2D::calc_local_corrMtx_KLE", "There seems to be a problem with the geometrical definition of the random field.");
    } else if (ce!=this) {	// check if we need to integrate it ... threshold
      tdouble max = ZERO;
      for (tdouble i=-ONE;i<1.5;i+=2.0) {
	for (tdouble j=-ONE;j<1.5;j+=2.0) {
	  update_globalConst_o(i,j);
	  const tdouble t = ce->check_cov_val();
	  if (t>max) max = t;
	}
      }
      if (max<=CovThreshold) {
	continue;
      }
    }
    // integrate
      Ni2 = ce->N_local_DOF;					// equal to number of shape functions of referenced element
      flxVec r(N_local_DOF*Ni2);
      #if FLX_KAHAN_FCRF
	flxpVec d(N_local_DOF*Ni2); tdouble* dp = r.get_tmp_vptr();			// Ni1=rows; Ni2=columns
	flxpVec t(Ni2);
      #else
	flxVec d(N_local_DOF*Ni2); tdouble* dp = d.get_tmp_vptr();			// Ni1=rows; Ni2=columns
	flxVec t(Ni2);
      #endif
      flxVec rx(pox+1);
      flxVec ry(poy+1);
      GI->check_GA_polynomialDegree(ce->get_polydeg_innerIntegral_X()+1);
      GI->check_GA_polynomialDegree(ce->get_polydeg_innerIntegral_Y()+1);
      const tuint GNx = GI->pDegree2GPs(ce->get_polydeg_innerIntegral_X()+1);
      const tuint GNy = GI->pDegree2GPs(ce->get_polydeg_innerIntegral_Y()+1);
      const tuint* vpos = mesh_outer;
      tdouble* ccpos = mesh_outer_cc;
      calc_local_corrMtx_KLE_rec(0,vpos,ccpos,GNx,GNy,ZERO,ZERO,ce,d,r,s,t,rx,ry);
      #if FLX_KAHAN_FCRF
	r=d;
      #endif
      // map the local matrix to the global matrix
      if (ce==this) {
	// vertice-rows
	  for (tuint i=0;i<4;++i) {
	    for (tuint j=0;j<i;++j) {
	      Cmtx.add_value(mapGlobal[i],mapGlobal[j],(dp[i*N_local_DOF+j]+dp[j*N_local_DOF+i])/2.0);
	    }
	    Cmtx.add_value(mapGlobal[i],mapGlobal[i],dp[i*N_local_DOF+i]);
	  }
	// edge-rows
	  tuint r = 4;	// current row
	  tuint c;	// current column
	  for (tuint i=0;i<4;++i) {		// over edges
	    const tuint S = edgeDOFpOrder[i]-1;
	    for (tuint j=0;j<S;++j) {		// over edge DOF of edge i
	      for (tuint k=0;k<4;++k) {			// over nodal DOFs
		Cmtx.add_value(mapGlobal[4+i]+j,mapGlobal[k],(dp[r*N_local_DOF+k]+dp[k*N_local_DOF+r])/2.0);
	      }
	      c=4;
	      for (tuint k=0;k<i;++k) {			// over (full) edges
		const tuint S2 = edgeDOFpOrder[k]-1;
		for (tuint l=0;l<S2;++l,++c) {
		  Cmtx.add_value(mapGlobal[4+i]+j,mapGlobal[4+k]+l,(dp[r*N_local_DOF+c]+dp[c*N_local_DOF+r])/2.0);
		}
	      }
	      for (tuint k=0;k<=j;++k,++c) {			// over this edge
		Cmtx.add_value(mapGlobal[4+i]+j,mapGlobal[4+i]+k,(dp[r*N_local_DOF+c]+dp[c*N_local_DOF+r])/2.0);
	      }
	      ++r;
	    }
	  }
	// bubble-rows
	  tuint Ni = N_local_DOF-r;	// number of internal DOFs
	  for (tuint i=0;i<Ni;++i) {
	    for (tuint j=0;j<4;++j) {			// over nodal DOFs
	      Cmtx.add_value(mapGlobal[8]+i,mapGlobal[j],(dp[r*N_local_DOF+j]+dp[j*N_local_DOF+r])/2.0);
	    }
	    c=4;
	    for (tuint j=0;j<4;++j) {			// over edge DOFs
	      const tuint S = edgeDOFpOrder[j]-1;
	      for (tuint k=0;k<S;++k,++c) {
		Cmtx.add_value(mapGlobal[8]+i,mapGlobal[4+j]+k,(dp[r*N_local_DOF+c]+dp[c*N_local_DOF+r])/2.0);
	      }
	    }
	    for (tuint j=0;j<=i;++j,++c) {			// over bubble DOFs
	      Cmtx.add_value(mapGlobal[8]+i,mapGlobal[8]+j,(dp[r*N_local_DOF+c]+dp[c*N_local_DOF+r])/2.0);
	    }
	    ++r;
	  }
      } else {
	tuint r = 4;	// current row
	tuint c;	// current column
	// vertice-rows
	  for (tuint i=0;i<4;++i) {
	    for (tuint j=0;j<4;++j) {		// nodes
	      Cmtx.add_value(mapGlobal[i],ce->mapGlobal[j],dp[Ni2*i+j]*((mapGlobal[i]==ce->mapGlobal[j])?2.0:ONE));
	    }
	    c=4;
	    for (tuint j=0;j<4;++j) {		// edges
	      const tuint S2 = ce->edgeDOFpOrder[j]-1;
	      for (tuint k=0;k<S2;++k) {
		Cmtx.add_value(mapGlobal[i],ce->mapGlobal[4+j]+k,dp[Ni2*i+c]);
		++c;
	      }
	    }
	    for (tuint j=0;c<Ni2;++j) {	// bubble-DOFs
	      Cmtx.add_value(mapGlobal[i],ce->mapGlobal[8]+j,dp[Ni2*i+c]);
	      ++c;
	    }
	  }
	// edge-rows
	  for (tuint i=0;i<4;++i) {		// over edges
	    const tuint S = edgeDOFpOrder[i]-1;
	    for (tuint j=0;j<S;++j) {		// over edge DOFs of edge i
	      for (tuint k=0;k<4;++k) {			// over nodal DOFs
		Cmtx.add_value(mapGlobal[4+i]+j,ce->mapGlobal[k],dp[Ni2*r+k]);
	      }
	      c=4;
	      for (tuint k=0;k<4;++k) {			// over edges
		const tuint S2 = ce->edgeDOFpOrder[k]-1;
		if (mapGlobal[4+i]==ce->mapGlobal[4+k]) {
		  for (tuint l=0;l<S2;++l,++c) {
		    Cmtx.add_value(mapGlobal[4+i]+j,ce->mapGlobal[4+k]+l,dp[Ni2*r+c]*((j==l)?2.0:ONE));
		  }
		} else {
		  for (tuint l=0;l<S2;++l,++c) {
		    Cmtx.add_value(mapGlobal[4+i]+j,ce->mapGlobal[4+k]+l,dp[Ni2*r+c]);
		  }
		}
	      }
	      for (tuint k=0;c<Ni2;++c,++k) {	// bubble-DOFs
		Cmtx.add_value(mapGlobal[4+i]+j,ce->mapGlobal[8]+k,dp[Ni2*r+c]);
	      }
	      ++r;
	    }
	  }
	// bubble-rows
	  tuint Ni = N_local_DOF-r;	// number of internal DOFs
	  for (tuint i=0;i<Ni;++i) {
	    for (tuint j=0;j<4;++j) {			// over nodal DOFs
	      Cmtx.add_value(mapGlobal[8]+i,ce->mapGlobal[j],dp[Ni2*r+j]);
	    }
	    c=4;
	    for (tuint j=0;j<4;++j) {			// over edges
	      const tuint S2 = ce->edgeDOFpOrder[j]-1;
	      for (tuint k=0;k<S2;++k,++c) {
		Cmtx.add_value(mapGlobal[8]+i,ce->mapGlobal[4+j]+k,dp[Ni2*r+c]);
	      }
	    }
	    for (tuint j=0;c<Ni2;++c,++j) {				// over bubble DOFs
	      Cmtx.add_value(mapGlobal[8]+i,ce->mapGlobal[8]+j,dp[Ni2*r+c]);
	    }
	    ++r;
	  }
      }
  }
}

#if FLX_KAHAN_FCRF
void flxElement_KL_2D::calc_local_corrMtx_KLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxElement_KL_2D* ce, flxpVec& d, flxVec& r, flxVec& s, flxpVec& t, flxVec& rx, flxVec& ry) const
#else
void flxElement_KL_2D::calc_local_corrMtx_KLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxElement_KL_2D* ce, flxVec& d, flxVec& r, flxVec& s, flxVec& t, flxVec& rx, flxVec& ry) const
#endif
{
  switch (*vpos) {
    case 0:		// parent
    {
      update_GN(level,maxtree_outer,GNx,GNy); // reduce number of Gauss-points
      const tdouble dhh = dha[level+1];
      ++vpos;
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym-dhh,ce,d,r,s,t,rx,ry);
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym-dhh,ce,d,r,s,t,rx,ry);
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym+dhh,ce,d,r,s,t,rx,ry);
      if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym+dhh,ce,d,r,s,t,rx,ry);
      return;
    }
    case 1:		// no geometry
      ++vpos;
      return;
    case 2:		// mixed 
    {
      const tuint Ni2 = ce->N_local_DOF;
      tdouble* rxp = rx.get_tmp_vptr();
      tdouble* ryp = ry.get_tmp_vptr();
      tdouble* rp = r.get_tmp_vptr();
      tdouble* sp = s.get_tmp_vptr();
      #if FLX_KAHAN_FCRF
	pdouble* tp = t.get_tmp_vptr();
      #else
	tdouble* tp = t.get_tmp_vptr();
      #endif
      const tdouble dh = dha[level];
      tdouble sigma_eval;
      const tdouble xt = *(ccpos++), yt = *(ccpos++);
      XXX_vec(rx,xt);
      XXX_vec(ry,yt);
      update_globalConst_o(xt,yt);
      sigma_eval = ptrFunSigma->calc() * 4.0 * face->get_detJ(xt,yt) * (*(ccpos++)) * dh*dh;
      XXX_2D_base(sp,rxp,ryp);
      s*=sigma_eval;
      ce->calc_local_corrMtx_KLE_inner(t,ce==this);
      tuint c=0;
      for (tuint k=0;k<N_local_DOF;++k) {
	for (tuint l=0;l<Ni2;++l) {
	  #if FLX_KAHAN_FCRF
	    rp[c++]=sp[k]*tp[l].cast2double();
	  #else
	    rp[c++]=sp[k]*tp[l];
	  #endif
	}
      }
      #if FLX_KAHAN_FCRF
	pVec_add(d,r);
      #else
	d+=r;
      #endif
      ++vpos;
      return;
    }
    case 3:
    default:		// full
    {
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GNx);
	const tdouble* GWx = GI->get_GW(GNx);
	const tdouble* GPy = GI->get_GP(GNy);
	const tdouble* GWy = GI->get_GW(GNy);
      // integration
	const tuint Ni2 = ce->N_local_DOF;
	r=ZERO;
	tdouble* rxp = rx.get_tmp_vptr();
	tdouble* ryp = ry.get_tmp_vptr();
	tdouble* rp = r.get_tmp_vptr();
	tdouble* sp = s.get_tmp_vptr();
	#if FLX_KAHAN_FCRF
	  pdouble* tp = t.get_tmp_vptr();
	#else
	  tdouble* tp = t.get_tmp_vptr();
	#endif
	const tdouble dh = dha[level];
	tdouble lx,ly,sigma_eval;
	for (tuint i=0;i<GNx;++i) {
	  lx = xm+dh*GPx[i];
	  XXX_vec(rx,lx);
	  for (tuint j=0;j<GNy;++j) {
	    ly = ym+dh*GPy[j];
	    update_globalConst_o(lx,ly);
	    sigma_eval = ptrFunSigma->calc() * GWx[i]*GWy[j] * face->get_detJ(lx,ly);
	    XXX_vec(ry,ly);
	    XXX_2D_base(sp,rxp,ryp);
	    s*=sigma_eval;
	    ce->calc_local_corrMtx_KLE_inner(t,ce==this);
	    tuint c=0;
	    for (tuint k=0;k<N_local_DOF;++k) {
	      for (tuint l=0;l<Ni2;++l) {
		#if FLX_KAHAN_FCRF
		  rp[c++]+=sp[k]*tp[l].cast2double();
		#else
		  rp[c++]+=sp[k]*tp[l];
		#endif
	      }
	    }
	  }
	}
	r*=dh*dh;
	#if FLX_KAHAN_FCRF
	  pVec_add(d,r);
	#else
	  d+=r;
	#endif
      ++vpos;
      return;
    }
  }
}

const tdouble flxElement_KL_2D::calc_djNj2(const tdouble* dVec) const
{
  if (is_empty) return ZERO;
  // integration
    flxVec rx(pox+1);
    flxVec ry(poy+1);
    tdouble* ccpos = mesh_single_cc;
    const tuint* vpos = mesh_single;
    const tuint GNx = GI->pDegree2GPs(pox*2+(face->get_is_detJ_const()?0:1));
    const tuint GNy = GI->pDegree2GPs(poy*2+(face->get_is_detJ_const()?0:1));
    #if FLX_KAHAN_FCRF
      return calc_djNj2_rec(0,vpos,ccpos,GNx,GNy,ZERO,ZERO,dVec,rx,ry).cast2double();
    #else
      return calc_djNj2_rec(0,vpos,ccpos,GNx,GNy,ZERO,ZERO,dVec,rx,ry);
    #endif
}

#if FLX_KAHAN_FCRF
const pdouble flxElement_KL_2D::calc_djNj2_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, const tdouble* dVec, flxVec& rx, flxVec& ry) const
#else
const tdouble flxElement_KL_2D::calc_djNj2_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, const tdouble* dVec, flxVec& rx, flxVec& ry) const
#endif
{
  switch (*vpos) {
    case 0:		// parent
    {
      update_GN(level,maxtree_single,GNx,GNy); // reduce number of Gauss-points
      const tdouble dhh = dha[level+1];
      #if FLX_KAHAN_FCRF
      pdouble res = ZERO;
      #else
      tdouble res = ZERO;
      #endif
      ++vpos;
      if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym-dhh,dVec,rx,ry);
      if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym-dhh,dVec,rx,ry);
      if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym+dhh,dVec,rx,ry);
      if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym+dhh,dVec,rx,ry);
      return res;
    }
    case 1:		// no geometry
      ++vpos;
      return ZERO;
    case 2:
    {
      tdouble* rxp = rx.get_tmp_vptr();
      tdouble* ryp = ry.get_tmp_vptr();
      const tdouble dh = dha[level];
      const tdouble xt = *(ccpos++), yt = *(ccpos++);
      XXX_vec(rx,xt);
      XXX_vec(ry,yt);
      tdouble res = pow2(XXX_2D_rlz(rxp,ryp,dVec))*4.0*face->get_detJ(xt,yt)*(*(ccpos++))*dh*dh;
      ++vpos;
      return res;
    }
    case 3:
    default:		// mixed or full
    {
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GNx);
	const tdouble* GWx = GI->get_GW(GNx);
	const tdouble* GPy = GI->get_GP(GNy);
	const tdouble* GWy = GI->get_GW(GNy);
      // integration
	tdouble* rxp = rx.get_tmp_vptr();
	tdouble* ryp = ry.get_tmp_vptr();
	const tdouble dh = dha[level];
	tdouble res=ZERO, lx,ly, r;
	for (tuint i=0;i<GNx;++i) {
	  lx = xm+dh*GPx[i];
	  XXX_vec(rx,lx);
	  r = ZERO;
	  for (tuint j=0;j<GNy;++j) {
	    ly = ym+dh*GPy[j];
	    XXX_vec(ry,ly);
	    r += pow2(XXX_2D_rlz(rxp,ryp,dVec))*GWy[j]*face->get_detJ(lx,ly);
	  }
	  r*=GWx[i];
	  res+=r;
	}
      ++vpos;
      return res*dh*dh;
    }
  }
}

const tdouble flxElement_KL_2D::calc_djNj(const tdouble* dVec, const tdouble& x, const tdouble& y, const tdouble& z) const
{
  if (x!=djNj_x||y!=djNj_y) {
    if (x!=djNj_x) {
      djNj_x = x;
      XXX_vec(*djNj_xV,x);
    }
    if (y!=djNj_y) {
      djNj_y = y;
      XXX_vec(*djNj_yV,y);
    }
    XXX_2D_base(&(*djNj_bV)[0],&(*djNj_xV)[0],&(*djNj_yV)[0]);
  }
  const tdouble* bp = &(*djNj_bV)[0];
  const tdouble* dp = &dVec[0];
  tdouble res=ZERO;
  // vertices
    for (tuint i=0;i<4;++i) {
      res += bp[i] * dp[mapGlobal[i]];
    }
  // edges
    tuint c = 4;
    for (tuint i=0;i<4;++i) {
      const tuint S = edgeDOFpOrder[i]-1;
      for (tuint j=0;j<S;++j) {
	res += bp[c++] * dp[mapGlobal[4+i]+j];
      }
    }
  // bubbles
    for (tuint i=0;c<N_local_DOF;++i,++c) {
      res += bp[c]*dp[mapGlobal[8]+i];
    }
  return res;
}

const tdouble flxElement_KL_2D::err_var_domain() const
{
  throw FlxException_NotImplemented("flxElement_KL_2D::err_var_domain");
}

const tdouble flxElement_KL_2D::err_cov_domain() const
{
  throw FlxException_NotImplemented("flxElement_KL_2D::err_cov_domain");
}

void flxElement_KL_2D::plot_el(std::ostream& sout, FlxMtxConstFun* ppdim, const int errMeasure, const int prec, const int fixW, const bool checkTOL) const
{
  if (is_empty) return;
  const size_t DIM = ptrEigenvectors->size();
  const iVec ppdim_help = ConstMtxBox->get_Vec_cast2tuint(ppdim->eval(),true);;
  if (ppdim_help.size()<2) {
    std::ostringstream ssV;
    ssV << "The dimension of the vector has to be at least '2'.";
    throw FlxException("flxElement_KL_2D::plot_el", ssV.str() );
  }
  const tuint PPDIM_X = ppdim_help[0];
  const tuint PPDIM_Y = ppdim_help[1];
  const tdouble dx = 2.0/PPDIM_X;
  const tdouble dy = 2.0/PPDIM_Y;
  tdouble x = -ONE + dx/2;
  for (tuint i=0;i<PPDIM_X;++i) {
    tdouble y = -ONE + dy/2.0;
    for (tuint j=0;j<PPDIM_Y;++j) {
      update_globalConst(x,y);
      if ( (geo_fun && geo_fun->calc()>=ZERO) || !geo_fun) {
	sout << GlobalVar.Double2String(*GX,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GY,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GZ,false,prec,fixW) << ' ';
	sout << GlobalVar.Double2String(get_error(x,y,ZERO,errMeasure),checkTOL,prec,fixW);
	for (tuint k=0;k<DIM;++k) {
	  sout << ' ' << GlobalVar.Double2String(calc_djNj(&(ptrEigenvectors->operator[](k))[0],x,y,ZERO),true,prec,fixW);
	}
	sout << std::endl;
      }
      y+=dy;
    }
    x+=dx;
    sout << std::endl;
  }
  sout << std::endl;
}

void flxElement_KL_2D::plotcov_el(std::ostream& sout, const flxPoint& pp, FlxMtxConstFun* ppdim, const flxVec& tr, const int prec, const int fixW) const
{
  throw FlxException_NotImplemented("flxElement_KL_2D::plotcov_el");
}

void flxElement_KL_2D::assembleEOLEpointVec(std::vector< flxPoint >& pointVec, const tuint Npt, tdouble* Nia) const
{
  if (is_empty) return;
  // define some vectors ... only relevant for Npt>0
    flxVec s(N_local_DOF);
    flxVec rx(pox+1);
    flxVec ry(poy+1);
    tdouble* rxp = rx.get_tmp_vptr();
    tdouble* ryp = ry.get_tmp_vptr();
    tdouble* sp = s.get_tmp_vptr();
  switch (EOLE_SMP_MTH) {
    case 1:
      {
	const tdouble dx = 2.0/EOLE_N_LX;
	const tdouble dy = 2.0/EOLE_N_LY;
	tdouble x = -ONE + dx/2.0;
	for (tuint i=0;i<EOLE_N_LX;++i) {
	  tdouble y = -ONE + dy/2.0;
	  for (tuint j=0;j<EOLE_N_LY;++j) {
	    update_globalConst(x,y);
	    if ( (geo_fun && geo_fun->calc()>=ZERO) || !geo_fun) {
	      flxPoint p(*(GX+0),*(GX+1),*(GX+2));
	      const tnlong id = pointVec.size();
	      pointVec.push_back(p);
	      if (Npt>0) {
		XXX_vec(rx,x);
		XXX_vec(ry,y);
		XXX_2D_base(sp,rxp,ryp);
		// mapping 
		  tuint c = 0;
		  // vertices
		    for (tuint k=0;k<4;++k) {
		      Nia[mapGlobal[k]*Npt+id] = sp[c++];
		    }
		  tuint r = 4;
		  // edges
		    for (tuint k=0;k<4;++k) {		// over edges
		      const tuint S = edgeDOFpOrder[k]-1;
		      r+=S;
		      for (tuint l=0;l<S;++l) {		// over edge DOF of edge k
			Nia[(mapGlobal[4+k]+l)*Npt+id] = sp[c++];
		      }
		    }
		  // bubbles
		    tuint Ni = N_local_DOF-r;	// number of internal DOFs
		    for (tuint k=0;k<Ni;++k) {
		      Nia[(mapGlobal[8]+k)*Npt+id] = sp[c++];
		    }
	      }
	    }
	    y+=dy;
	  }
	  x+=dx;
	}
      }
      break;
    case 2:
      {
	throw FlxException_NotImplemented("flxElement_KL_2D::assembleEOLEpointVec");
      }
      break;
    default:
      {
	std::ostringstream ssV;
	ssV << "A EOLE-sampling-method with index '" << EOLE_SMP_MTH << "is not defined.";
	throw FlxException("flxElement_KL_2D::assembleEOLEpointVec", ssV.str() );
      }
  }
}

void flxElement_KL_2D::get_PlotPoints(std::vector< flxPoint >& pointVec, std::vector< tuint >& geoVec, FlxMtxConstFun* ppdim) const
{
  pointVec.clear();
  if (is_empty) return;
  iVec t = ConstMtxBox->get_Vec_cast2tuint(ppdim->eval(),true);;
  if (t.size()<2) {
    std::ostringstream ssV;
    ssV << "The dimension of the vector has to be at least '2'.";
    throw FlxException("flxElement_KL_2D::get_PlotPoints", ssV.str() );
  }
  const tuint PPDIM_X = t[0];
  const tuint PPDIM_Y = t[1];
  const tdouble dx = 2.0/PPDIM_X;
  const tdouble dy = 2.0/PPDIM_Y;
  tdouble x = -ONE + dx/2;
  for (tuint i=0;i<PPDIM_X;++i) {
    tdouble y = -ONE + dy/2.0;
    for (tuint j=0;j<PPDIM_Y;++j) {
      update_globalConst(x,y);
      if ( (geo_fun && geo_fun->calc()>=ZERO) || !geo_fun) {
	pointVec.push_back(flxPoint(*(GX+0),*(GX+1),*(GX+2)));
      }
      y+=dy;
    }
    x+=dx;
    geoVec.push_back(pointVec.size());
  }
}

const tdouble flxElement_KL_2D::err_var_domain_EOLE(flxVec& Hx, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, const bool abs) const
{
  if (is_empty) return ZERO;
  tdouble* ccpos = mesh_single_cc;
  const tuint* vpos = mesh_single;
  const tuint GN = GI->pDegree2GPs(DegCorr+DegStd*2+(face->get_is_detJ_const()?0:1));		// of course this won't be an exact integration
  return err_var_domain_EOLE_rec(0,vpos,ccpos,GN,GN,ZERO,ZERO,Hx,pointVec,sdVec,abs);  
}

const tdouble flxElement_KL_2D::err_var_domain_EOLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, tuint GNx, tuint GNy, const tdouble xm, const tdouble ym, flxVec& Hx, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, const bool abs) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      update_GN(level,maxtree_single,GNx,GNy);
      const tdouble dhh = dha[level+1];
      tdouble res = ZERO;
      ++vpos;
      if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym-dhh,Hx,pointVec,sdVec,abs);
      if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym-dhh,Hx,pointVec,sdVec,abs);
      if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNx,GNy,xm+dhh,ym+dhh,Hx,pointVec,sdVec,abs);
      if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNx,GNy,xm-dhh,ym+dhh,Hx,pointVec,sdVec,abs);
      return res;
    }
    case 1:		// no geometry
      ++vpos;
      return ZERO;
    case 2:
    {
      const tuint DIM = ptrEigenvalues->get_N();  
      const tdouble dh = dha[level];
      tdouble sD_curr_x_2;
      const tdouble xt = *(ccpos++), yt = *(ccpos++);
      update_globalConst_o(xt,yt);
      assemble_Hx_EOLE(Hx,sD_curr_x_2,pointVec,sdVec);
      sD_curr_x_2 = pow2(sD_curr_x_2);
      tdouble t = sD_curr_x_2;
      for (tuint k=0;k<DIM;++k) {	// i+1 is odd
	t -= pow2( ( ptrEigenvectors->operator[](k) * Hx ) * ptrEigenvalues->operator[](k) );
      }
      if (abs) t = fabs(t);
      t = t/sD_curr_x_2*4.0*face->get_detJ(xt,yt)*dh*dh*(*(ccpos++));
      ++vpos;
      return t;
    }
    case 3:
    default:		// mixed or full
    {
      const tuint DIM = ptrEigenvalues->get_N();  
      // get Gauss-points
	const tdouble* GPx = GI->get_GP(GNx);
	const tdouble* GWx = GI->get_GW(GNx);
	const tdouble* GPy = GI->get_GP(GNy);
	const tdouble* GWy = GI->get_GW(GNy);
      const tdouble dh = dha[level];
      tdouble res=ZERO, lx,ly, r, t, sD_curr_x_2;
      for (tuint i=0;i<GNx;++i) {
	lx = xm+dh*GPx[i];
	r = ZERO;
	for (tuint j=0;j<GNy;++j) {
	  ly = ym+dh*GPy[j];
	  update_globalConst_o(lx,ly);
	  assemble_Hx_EOLE(Hx,sD_curr_x_2,pointVec,sdVec);
	  sD_curr_x_2 = pow2(sD_curr_x_2);
	  t = sD_curr_x_2;
	  for (tuint k=0;k<DIM;++k) {	// i+1 is odd
	    t -= pow2( ( ptrEigenvectors->operator[](k) * Hx ) * ptrEigenvalues->operator[](k) );
	  }
	  if (abs) t = fabs(t);
	  r += t/sD_curr_x_2*GWy[j]*face->get_detJ(lx,ly);
	}
	r*=GWx[i];
	res+=r;
      }
      ++vpos;
      return res*dh*dh;
    }
  }
}

const tdouble flxElement_KL_2D::err_cov_domain_EOLE(const std::vector< flxPoint >& pointVec, const flxVec& sdVec) const
{
  throw FlxException_NotImplemented("flxElement_KL_2D::err_cov_domain_EOLE");
}

const bool flxElement_KL_2D::map2local(const flxPoint& p) const
{
  return face->map2local(p);
}

FlxKLelementProp_base::FlxKLelementProp_base()
: geo_fun(NULL), degCorr(NULL),degStd(NULL)
{
  
}

flxElement_KL_3D::flxElement_KL_3D(flxBox* box, FlxKLelementProp_3D& KLelProp)
: flxElement_KL_base(KLelProp.get_geo_fun(),false), DegCorr(KLelProp.get_degCorr()), DegStd(KLelProp.get_degStd()),
N_local_DOF(0),djNj_bV(NULL),box(box), mesh_single(NULL),mesh_single_cc(NULL),mesh_outer(NULL),mesh_outer_cc(NULL),mesh_inner_s(NULL),mesh_inner_s_cc(NULL),mesh_err_is(NULL),mesh_err_is_cc(NULL),
EOLE_SMP_MTH(KLelProp.get_EOLE_SMP_MTH())
{
  box->set_DegStd(DegStd);
  box->set_DegCorr(DegCorr);
  KLelProp.set_box(box);
  // set some more values
    KLelProp.get_pOrder(pOrder);
    pom = pOrder[0];
      for (tuint i=1;i<3;++i) if (pom < pOrder[i]) pom = pOrder[i];
    KLelProp.get_EOLE_N(EOLE_SMP_MTH,EOLE_N);
    djNj_x[0]=ZERO; djNj_x[1]=ZERO; djNj_x[2]=ZERO; 
    djNj_xV[0] = NULL; djNj_xV[1] = NULL; djNj_xV[2] = NULL;
  // refine the mesh
    mesh_single = KLelProp.refine_single(maxtree_single,mesh_single_cc);
    // inner, same (and different) element
      mesh_outer = KLelProp.refine_outer(maxtree_outer,mesh_outer_cc);
      mesh_inner_s = KLelProp.refine_inner_s(maxtree_inner,mesh_inner_s_cc);
    mesh_err_is = KLelProp.refine_err_is(mesh_err_is_cc);
  // check if enough Gauss-points are loaded
    GI->check_GA_polynomialDegree(pom*2);
    GI->check_GA_polynomialDegree(pom+DegStd+DegCorr);
    GI->check_GA_polynomialDegree(GI->pDegree2GPs(DegCorr+DegStd*2));
  // make sure that enough shape functions are available
    XXX_check_order(pom);
}

flxElement_KL_3D::~flxElement_KL_3D()
{
  for (tuint i=0;i<3;++i) if (djNj_xV[i]) delete djNj_xV[i];
  if (djNj_bV) delete djNj_bV;
  if (mesh_single) delete [] mesh_single;
    if (mesh_single_cc) delete [] mesh_single_cc;
  if (mesh_outer) delete [] mesh_outer;
    if (mesh_outer_cc) delete [] mesh_outer_cc;
  if (mesh_inner_s) delete [] mesh_inner_s;
    if (mesh_inner_s_cc) delete [] mesh_inner_s_cc;
  if (mesh_err_is) delete [] mesh_err_is;
    if (mesh_err_is_cc) delete [] mesh_err_is_cc;
}

void flxElement_KL_3D::update_globalConst_i(flxPoint& lxp) const
{
  // update GX,GY,GZ
    box->update_globalConst(lxp);
  // update DELTAs
    *(GX2+3) = fabs(*(GX2+0) - *(GX2-3));
    *(GX2+4) = fabs(*(GX2+1) - *(GX2-2));
    *(GX2+5) = fabs(*(GX2+2) - *(GX2-1));
    *(GX2+6) = sqrt(pow2(*(GX2+3)) + pow2(*(GX2+4)) + pow2(*(GX2+5)));
}

void flxElement_KL_3D::calc_local_corrMtx_KLE_inner(flxVec& t, flxVec** rv) const
{
  t.set_zero();
  flxVec r(t.get_N());
  flxVec s(t.get_N());
  tdouble* ccpos = mesh_inner_s_cc;
  const tuint* vpos = mesh_inner_s;
  const tuint GN[3] = {GI->pDegree2GPs(pOrder[0]+DegCorr+DegStd),GI->pDegree2GPs(pOrder[1]+DegCorr+DegStd),GI->pDegree2GPs(pOrder[2]+DegCorr+DegStd)};
  flxPoint p(ZERO,ZERO,ZERO);
  calc_local_corrMtx_KLE_inner_rec(0,vpos,ccpos,GN,p,t,r,s,rv);
}

void flxElement_KL_3D::calc_local_corrMtx_KLE_inner_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, const tuint* GN, flxPoint& p, flxVec& t, flxVec& r, flxVec& s, flxVec** rv) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      tuint GNl[3] = {GN[0],GN[1],GN[2]};
      update_GN(level,GNl);
      const tdouble dhh = dha[level+1];
      ++vpos;
      flxPoint pt = p+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      pt = p+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      pt = p+flxPoint(dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      pt = p+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      pt = p+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      pt = p+flxPoint(dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      pt = p+flxPoint(dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      pt = p+flxPoint(-ONE*dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_inner_rec(level+1,vpos,ccpos,GNl,pt,t,r,s,rv);
      return;
    }
    case 1:		// no geometry
      ++vpos;
      return;
    case 2:
    {
      const tdouble* rvp[3] = {&((*rv[0])[0]),&((*rv[1])[0]),&((*rv[2])[0])};
      tdouble* sp = &s[0];
      const tdouble& d1 = *(ccpos++);
      const tdouble& d2 = *(ccpos++);
      const tdouble& d3 = *(ccpos++);
      flxPoint lxp(d1,d2,d3);
      XXX_vec(*rv[0],lxp.id_fast(0));
      XXX_vec(*rv[1],lxp.id_fast(1));
      XXX_vec(*rv[2],lxp.id_fast(2));
      XXX_3D_base(sp,rvp);
      update_globalConst_i(lxp);
      tdouble sigma_eval = ptrFunSigma->calc()*ptrFunRho->calc() * 8.0 * pow(dha[level],3)*(*(ccpos++));
      s*=sigma_eval;
      t+=s;
      ++vpos;
      return;
    } 
    case 3:
    default:		// mixed(2) or full(3)
    {
      const tdouble dh = dha[level];
      const tdouble* rvp[3] = {(*rv[0]).get_tmp_vptr_const(),(*rv[1]).get_tmp_vptr_const(),(*rv[2]).get_tmp_vptr_const()};
      tdouble* sp = s.get_tmp_vptr();
      if (level==maxtree_inner && GN[0]+GN[1]+GN[2]==3 ) {
	update_globalConst_i(p);
	const tdouble f = ptrFunSigma->calc()*ptrFunRho->calc() * 8.0 * dh*dh*dh;
	XXX_vec(*rv[0],p.id_fast(0));
	XXX_vec(*rv[1],p.id_fast(1));
	XXX_vec(*rv[2],p.id_fast(2));
	XXX_3D_base(sp,rvp);
	s*=f;
	t+=s;
      } else {
	// get Gauss points
	  const tdouble* GPx = GI->get_GP(GN[0]);
	  const tdouble* GWx = GI->get_GW(GN[0]);
	  const tdouble* GPy = GI->get_GP(GN[1]);
	  const tdouble* GWy = GI->get_GW(GN[1]);
	  const tdouble* GPz = GI->get_GP(GN[2]);
	  const tdouble* GWz = GI->get_GW(GN[2]);
	// integration
	  r=ZERO;
	  tdouble sigma_eval,douh;
	  flxPoint lxp;
	  for (tuint i=0;i<GN[0];++i) {
	    lxp.id_fast(0) = p.id_fast(0)+dh*GPx[i];
	    XXX_vec(*rv[0],lxp.id_fast(0));
	    for (tuint j=0;j<GN[1];++j) {
	      lxp.id_fast(1) = p.id_fast(1)+dh*GPy[j];
	      XXX_vec(*rv[1],lxp.id_fast(1));
	      douh = GWx[i]*GWy[j];
	      for (tuint k=0;k<GN[2];++k) {
		lxp.id_fast(2) = p.id_fast(2)+dh*GPz[k];
		update_globalConst_i(lxp);
		sigma_eval = ptrFunSigma->calc()*ptrFunRho->calc() * douh*GWz[k];
		XXX_vec(*rv[2],lxp.id_fast(2));
		XXX_3D_base(sp,rvp);
		s*=sigma_eval;
		r+=s;
	      }
	    }
	  }
	  r*=dh*dh*dh;
	  t+=r;
      }
      ++vpos;
      return;
    }
  }
}

void flxElement_KL_3D::get_error_2i_el(const bool sameEl, tdouble& integ_Cov, tdouble& integ_Err, const tdouble& sDx, const flxVec& tr) const
{
  throw FlxException_NotImplemented("flxElement_KL_3D::get_error_2i_el");
}

void flxElement_KL_3D::get_error_1i_el(const bool sameEl, flxVec& tr, flxVec& tri) const
{
  tr.set_zero();;
  if (is_empty) return;
  // integration
    tdouble* ccpos = mesh_err_is_cc;
    const tuint* vpos = mesh_err_is;
    const tuint GN[3] = {GI->pDegree2GPs(pOrder[0]+DegStd+DegCorr),GI->pDegree2GPs(pOrder[1]+DegStd+DegCorr),GI->pDegree2GPs(pOrder[2]+DegStd+DegCorr)};
    flxPoint p(ZERO,ZERO,ZERO);
    get_error_1i_el_rec(0,vpos,ccpos,GN,p,tr,tri);
    tr*=box->get_detJ();
}

void flxElement_KL_3D::get_error_1i_el_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, const tuint* GN, flxPoint& p, flxVec& tr, flxVec& tri) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      tuint GNl[3] = {GN[0],GN[1],GN[2]};
      update_GN(level,GNl);
      const tdouble dhh = dha[level+1];
      ++vpos;
      flxPoint pt = p+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      pt = p+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      pt = p+flxPoint(dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      pt = p+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      pt = p+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      pt = p+flxPoint(dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      pt = p+flxPoint(dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      pt = p+flxPoint(-ONE*dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else get_error_1i_el_rec(level+1,vpos,ccpos,GNl,pt,tr,tri);
      return;
    }
    case 1:		// no geometry
      ++vpos;
      return;
    case 2:
    {
      const size_t DIM = ptrEigenvectors->size();
      const tdouble& d1 = *(ccpos++);
      const tdouble& d2 = *(ccpos++);
      const tdouble& d3 = *(ccpos++);
      flxPoint lxp(d1,d2,d3);
      update_globalConst_i(lxp);
      const tdouble t = ptrFunRho->calc()*ptrFunSigma->calc()*8.0*(*(ccpos++))*pow(dha[level],3);
      for (tuint l=0;l<DIM;++l) {
	tr[l] += t*calc_djNj(&(ptrEigenvectors->operator[](l))[0],lxp.id_fast(0),lxp.id_fast(1),lxp.id_fast(2));
      }
      ++vpos;
      return;
    }
    case 3:
    default:		// mixed or full
    {
      const size_t DIM = ptrEigenvectors->size();
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GN[0]);
	const tdouble* GWx = GI->get_GW(GN[0]);
	const tdouble* GPy = GI->get_GP(GN[1]);
	const tdouble* GWy = GI->get_GW(GN[1]);
	const tdouble* GPz = GI->get_GP(GN[2]);
	const tdouble* GWz = GI->get_GW(GN[2]);
      // integration
	const tdouble dh = dha[level];
	tdouble t;
	tri=ZERO;
	flxPoint lxp;
	for (tuint i=0;i<GN[0];++i) {
	  lxp.id_fast(0) = p.id_fast(0)+dh*GPx[i];
	  for (tuint j=0;j<GN[1];++j) {
	    lxp.id_fast(1) = p.id_fast(1)+dh*GPy[j];
	    for (tuint k=0;k<GN[2];++k) {
	      lxp.id_fast(2) = p.id_fast(2)+dh*GPz[k];
	      update_globalConst_i(lxp);
	      t = ptrFunRho->calc()*ptrFunSigma->calc()*GWx[i]*GWy[j]*GWz[k];
	      for (tuint l=0;l<DIM;++l) {
		tri[l] += t*calc_djNj(&(ptrEigenvectors->operator[](l))[0],lxp.id_fast(0),lxp.id_fast(1),lxp.id_fast(2));
	      }
	    }
	  }
	}
	tri*=dh*dh*dh;
	tr+=tri;
      ++vpos;
      return;
    }
  }
}

void flxElement_KL_3D::get_error_2i_el_EOLE(const bool sameEl, tdouble& integ_Cov, tdouble& integ_Err, const tdouble& sDx, const flxVec& tr, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, flxVec& Hx) const
{
  throw FlxException_NotImplemented("flxElement_KL_3D::get_error_2i_el_EOLE");
}

void flxElement_KL_3D::XXX_3D_base(tdouble* res, const tdouble** rvp) const
{
  const tdouble* p1 = rvp[0];
  const tdouble* p2 = rvp[1];
  const tdouble* p3 = rvp[2];
  tuint c=0;
  for (tuint i=0;i<=pOrder[0];++i) {	// x4
    for (tuint j=0;j<=pOrder[1];++j) {	// x16
      const tdouble t = p1[i]*p2[j];	
      for (tuint k=0;k<=pOrder[2];++k) { // x64
	res[c++] = t*p3[k];
      }
    }
  }
}

const tdouble flxElement_KL_3D::XXX_3D_rlz(const tdouble** rvp, const tdouble* d) const
{
  tdouble res=ZERO;
  tuint c=0;
  for (tuint i=0;i<=pOrder[0];++i) {
    for (tuint j=0;j<=pOrder[1];++j) {
      const tdouble t = rvp[0][i]*rvp[1][j];
      for (tuint k=0;k<=pOrder[2];++k) {
	res += t*rvp[2][k] * d[c++];
      }
    }
  }
  return res;
}

void flxElement_KL_3D::update_GN(const tuint prev_level, tuint* GN) const
{
  if (prev_level>=4 || prev_level==2) {
    GN[0]=(GN[0]+1)/2;
    GN[1]=(GN[1]+1)/2;
    GN[2]=(GN[2]+1)/2;
    if (GN[0]<=1) GN[0]=2;
    if (GN[1]<=1) GN[1]=2;
    if (GN[2]<=1) GN[2]=2;
  }
}

void flxElement_KL_3D::update_GN_mass(const tuint prev_level, tuint* GN) const
{
  if (prev_level>=6) {
    GN[0]=(GN[0]+1)/2;
    GN[1]=(GN[1]+1)/2;
    GN[2]=(GN[2]+1)/2;
    if (GN[0]<=1) GN[0]=2;
    if (GN[1]<=1) GN[1]=2;
    if (GN[2]<=1) GN[2]=2;
  }
}

void flxElement_KL_3D::get_mesh_topology(const tuint level, const_tuintPtr& vpos, std::vector< tuint >& topV) const
{
  if (level+1 > topV.size()) {
    topV.push_back(0);
  }
  switch (*vpos) {
    case 0:		// parent
    {
      ++vpos;
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      get_mesh_topology(level+1,vpos,topV);
      return;
    }
    case 1:
      ++vpos;
      return;
    default:		// mixed or full
    {
      ++vpos;
      ++topV[level];
      return;
    }
  }
}

void flxElement_KL_3D::log_report(const tuint rfindex, const std::string& elID, const flxElement_KL_base::rftype rft) const
{
  std::vector<tuint> topV; const tuint* vpos;
  
  GlobalVar.slog(4) << "Assigned '" << elID << "' to random field " << rfindex << "." << std::endl << "  ";
  
  if (rft == rfKLfemGauss) {
    GlobalVar.slog(4) << "pOrder=(" << pOrder[0] << "," << pOrder[1] << "," << pOrder[2] << "); ";
  }
  
  if (rft == rfKLfemGauss) {
    topV.clear();
    vpos = mesh_outer;
    get_mesh_topology(0,vpos,topV);
    // set up counter ... for runtime
    {
      tuint GN[3] = {GI->pDegree2GPs(pOrder[0]*2+1+DegCorr+DegStd),GI->pDegree2GPs(pOrder[1]*2+1+DegCorr+DegStd),GI->pDegree2GPs(pOrder[2]*2+1+DegCorr+DegStd)};
      tnlong c=0;
      for (tuint i=0;i<topV.size();++i) {
	c+=GN[0]*GN[1]*GN[2]*topV[i];
	update_GN(i,GN);
      }
      MAXCOUNT=c;
    }
    GlobalVar.slog(4) << "mesh_outer=" << topV << ":(";
    {
      tuint GN[3] = {GI->pDegree2GPs(pOrder[0]*2+1+DegCorr+DegStd),GI->pDegree2GPs(pOrder[1]*2+1+DegCorr+DegStd),GI->pDegree2GPs(pOrder[2]*2+1+DegCorr+DegStd)};
      for (tuint i=0;i+1<topV.size();++i) {
	if (i>0) GlobalVar.slog(4) << ",";
	if ((GN[0]==GN[1]) && (GN[0]==GN[2])) {
	  GlobalVar.slog(4) << GN[0];
	} else {
	  GlobalVar.slog(4) << "[" << GN[0] << "," << GN[1] << "," << GN[2] << "]";
	}
	update_GN(i,GN);
      }
    }
    GlobalVar.slog(4) << ",1";
    GlobalVar.slog(4) << "); ";
    topV.clear();
    vpos = mesh_inner_s;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_inner_s=" << topV << ":(";
    {
      tuint GN[3] = {GI->pDegree2GPs(pOrder[0]+DegCorr+DegStd),GI->pDegree2GPs(pOrder[1]+DegCorr+DegStd),GI->pDegree2GPs(pOrder[2]+DegCorr+DegStd)};
      for (tuint i=0;i+1<topV.size();++i) {
	if (i>0) GlobalVar.slog(4) << ",";
	if ((GN[0]==GN[1]) && (GN[0]==GN[2])) {
	  GlobalVar.slog(4) << GN[0];
	} else {
	  GlobalVar.slog(4) << "[" << GN[0] << "," << GN[1] << "," << GN[2] << "]";
	}
	update_GN(i,GN);
      }
    }
    GlobalVar.slog(4) << ",1";
    GlobalVar.slog(4) << "); ";
  }
  if ( rft == rfEOLEgauss ) {
    GlobalVar.slog(4) << "eole_points=(";
    switch (EOLE_SMP_MTH) {
      case (1):
	GlobalVar.slog(4) << "uniform grid," << EOLE_N[0] << "," << EOLE_N[1] << "," << EOLE_N[2];
	break;
      case (2):
	GlobalVar.slog(4) << "random smp," << EOLE_N[0];
	break;
      default:
	break;
    }
    GlobalVar.slog(4) << "); ";
  }
  GlobalVar.slog(4) << "degCorr=" << DegCorr << "; ";
  if ( rft != rfKLAnaExpCorrGauss1D ) {
    GlobalVar.slog(4) << "degStd=" << DegStd << "; ";
  }
  if ( rft != rfKLAnaExpCorrGauss1D ) {
    topV.clear();
    vpos = mesh_single;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_single=" << topV << "; ";
    GlobalVar.slog(4) << "domain_el=" << GlobalVar.Double2String(calc_domain(true)) << "; ";
  }
  if ( rft == rfKLfemGauss ) {
    topV.clear();
    vpos = mesh_err_is;
    get_mesh_topology(0,vpos,topV);
    GlobalVar.slog(4) << "mesh_err_is=" << topV << "; ";
  }
  
  GlobalVar.slog(4) << std::endl;
}

const tdouble flxElement_KL_3D::calc_domain(const bool considerGeo) const
{
  if (considerGeo && geo_fun) {
    if (is_empty) return ZERO;
    tdouble* ccpos = mesh_single_cc;
    const tuint* vpos = mesh_single;
    flxPoint p(ZERO,ZERO,ZERO);
    return calc_domain_rec(0,vpos,ccpos,p).cast2double()*box->get_detJ();
  } else {
    return calc_volume();
  }
}

const pdouble flxElement_KL_3D::calc_domain_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, flxPoint& p) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      const tdouble dhh = dha[level+1];
      pdouble res = ZERO;
      ++vpos;
      flxPoint pt = p+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      pt = p+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      pt = p+flxPoint(dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      pt = p+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      pt = p+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      pt = p+flxPoint(dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      pt = p+flxPoint(dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      pt = p+flxPoint(-ONE*dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_domain_rec(level+1,vpos,ccpos,pt);
      return res;
    }
    case 1:		// no geometry
      ++vpos;
      return ZERO;
    case 2:
    {
      const tdouble dh3 = pow(dha[level],3);
      ++ccpos;++ccpos;++ccpos;
      ++vpos;
      return 8.0*dh3*(*(ccpos++));
    }
    case 3:
    {
      ++vpos;
      const tdouble dh3 = pow(dha[level],3);
      return 8.0*dh3;
    }
    default:
      return ZERO;
  }
}

void flxElement_KL_3D::countDOFs(niMap& nodalM, eiMap& edgeM, fiMap& faceM, std::vector< const flxVertex* >& nV, std::vector< const flxEdge* >& eV, std::vector< const flxFace* >& fV)
{
  if (is_empty) return;
  // deal with faces
    std::map<const flxFace*,fiMap_sec>::iterator posF;
    posF = faceM.find(box->get_FacLst()[0]);
    if ( posF == faceM.end() ) {	// vertex is NOT in the list
      fiMap_sec ems; ems.dofindex=0; 
      N_local_DOF = (pOrder[0]+1)*(pOrder[1]+1)*(pOrder[2]+1);
      ems.count = N_local_DOF;
      std::pair<const flxFace*,fiMap_sec>Element(box->get_FacLst()[0],ems);
      faceM.insert(Element);
      fV.push_back(box->get_FacLst()[0]);
    } else {				// vertex is already in the list
      throw FlxException("flxElement_KL_3D::countDOFs","There is something wrong with the geometrical definition of the random field.");
    }
}

void flxElement_KL_3D::assembleDOFs(const niMap& nodalM, const eiMap& edgeM, fiMap& faceM)
{
  if (is_empty) return;
  // create helping values
    djNj_xV[0] = new flxVec(pOrder[0]+1);
    djNj_xV[1] = new flxVec(pOrder[1]+1);
    djNj_xV[2] = new flxVec(pOrder[2]+1);
    djNj_bV = new flxVec(N_local_DOF);
    XXX_vec(*djNj_xV[0],djNj_x[0]);
    XXX_vec(*djNj_xV[1],djNj_x[1]);
    XXX_vec(*djNj_xV[2],djNj_x[2]);
    const tdouble* rvp[3] = {(*djNj_xV[0]).get_tmp_vptr_const(),(*djNj_xV[1]).get_tmp_vptr_const(),(*djNj_xV[2]).get_tmp_vptr_const()};
    XXX_3D_base(&(*djNj_bV)[0],rvp);
}

void flxElement_KL_3D::calc_local_MassMatrix_KLE(FlxMtxSym& Mmtx)
{
  if (is_empty) return;
  // integration (assembly)
    flxVec M((pow2(N_local_DOF)+N_local_DOF)/2);		// stores the local mass matrix
    flxVec Mi(M.get_N());		// for the inner loop
    flxVec *rv[3];
    for (tuint i=0;i<3;++i) rv[i] = new flxVec(pOrder[i]+1);
    tdouble* ccpos = mesh_single_cc;
    const tuint* vpos = mesh_single;
    const tuint GN[3] = {GI->pDegree2GPs(pOrder[0]*2),GI->pDegree2GPs(pOrder[1]*2),GI->pDegree2GPs(pOrder[2]*2)};
    flxPoint p(ZERO,ZERO,ZERO);
    calc_local_MassMatrix_KLE_rec(0,vpos,ccpos,GN,p,M,Mi,rv);	// assembles the local mass matrix
    for (tuint i=0;i<3;++i) delete rv[i];
    M*=box->get_detJ();
  // map the local matrix to the global matrix
    tdouble* mtxp = Mmtx.get_VecPointer();
    const tdouble* Mp = M.get_tmp_vptr_const();
    const size_t S = M.get_N();
    for (tuint i=0;i<S;++i) {
      mtxp[i] = Mp[i];
    }
}

void flxElement_KL_3D::calc_local_MassMatrix_KLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, const tuint* GN, flxPoint& p, flxVec& M, flxVec& Mi, flxVec** rv) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      tuint GNl[3] = {GN[0],GN[1],GN[2]};
      update_GN_mass(level,GNl);
      const tdouble dhh = dha[level+1];
      ++vpos;
      flxPoint pt = p+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      pt = p+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      pt = p+flxPoint(dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      pt = p+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      pt = p+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      pt = p+flxPoint(dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      pt = p+flxPoint(dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      pt = p+flxPoint(-ONE*dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_MassMatrix_KLE_rec(level+1,vpos,ccpos,GNl,pt,M,Mi,rv);
      return;
    }
    case 1:		// no geometry
      ++vpos;
      return;
    case 2:
    {
      #ifndef FLX_CV_1
	tdouble shapeFun[N_local_DOF];
      #else
	tdouble *shapeFun = new tdouble[N_local_DOF];
      #endif
      const tdouble* rvp[3] = {&((*rv[0])[0]),&((*rv[1])[0]),&((*rv[2])[0])};
      tdouble* Mp = &M[0];
      XXX_vec(*rv[0],*(ccpos++));
      XXX_vec(*rv[1],*(ccpos++));
      XXX_vec(*rv[2],*(ccpos++));
      XXX_3D_base(shapeFun,rvp);
      tdouble f = 8.0 * (*(ccpos++)) * pow(dha[level],3);
      tuint c=0;
      for (tuint k=0;k<N_local_DOF;++k) {
	for (tuint l=0;l<=k;++l) {
	  Mp[c++]+=f*shapeFun[k]*shapeFun[l];
	}
      }
      #ifdef FLX_CV_1
	delete [] shapeFun;
      #endif
      ++vpos;
      return;
    }
    case 3:
    default:		// mixed or full
    {
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GN[0]);
	const tdouble* GWx = GI->get_GW(GN[0]);
	const tdouble* GPy = GI->get_GP(GN[1]);
	const tdouble* GWy = GI->get_GW(GN[1]);
	const tdouble* GPz = GI->get_GP(GN[2]);
	const tdouble* GWz = GI->get_GW(GN[2]);
      // integration
	Mi=ZERO;
	#ifndef FLX_CV_1
	  tdouble shapeFun[N_local_DOF];
	#else
	  tdouble *shapeFun = new tdouble[N_local_DOF];
	#endif
	const tdouble* rvp[3] = {&((*rv[0])[0]),&((*rv[1])[0]),&((*rv[2])[0])};
	tdouble* Mip = &Mi[0];
	tdouble f;
	const tdouble dh = dha[level];
	flxPoint lxp;
	for (tuint i=0;i<GN[0];++i) {
	  lxp.id_fast(0) = p.id_fast(0)+dh*GPx[i];
	  XXX_vec(*rv[0],lxp.id_fast(0));
	  for (tuint j=0;j<GN[1];++j) {
	    lxp.id_fast(1) = p.id_fast(1)+dh*GPy[j];
	    XXX_vec(*rv[1],lxp.id_fast(1));
	    for (tuint m=0;m<GN[2];++m) {
	      lxp.id_fast(2) = p.id_fast(2)+dh*GPz[m];
	      XXX_vec(*rv[2],lxp.id_fast(2));
	      XXX_3D_base(shapeFun,rvp);
	      f = GWx[i]*GWy[j]*GWz[m];
	      tuint c=0;
	      for (tuint k=0;k<N_local_DOF;++k) {
		for (tuint l=0;l<=k;++l) {
		  Mip[c++]+=f*shapeFun[k]*shapeFun[l];
		}
	      }
	    }
	  }
	}
	#ifdef FLX_CV_1
	  delete [] shapeFun;
	#endif
	Mi*=dh*dh*dh;
	M+=Mi;
      ++vpos;
      return;
    }
  }
}

void flxElement_KL_3D::calc_local_corrMtx_KLE(FlxMtxSym& Cmtx, std::vector< flxElement_KL_base* >& ElVec) const
{
  if (is_empty) return;
  if (ElVec.size()!=1) {
    std::ostringstream ssV;
    ssV << "Only one element allowed for 3D-random fields.";
    throw FlxException("flxElement_KL_3D::calc_local_corrMtx_KLE_1", ssV.str() );
  }
  flxVec s(N_local_DOF);						// stores precomputed shape functions
  flxVec t(N_local_DOF);
  flxElement_KL_3D* ce = dynamic_cast<flxElement_KL_3D*>(ElVec[0]);
  if (ce==NULL) {
    throw FlxException("flxElement_KL_3D::calc_local_corrMtx_KLE_2", "There seems to be a problem with the geometrical definition of the random field.");
  }
  // integrate
    NOWCOUNT=0; LASTCOUNT=0;
    flxVec d(N_local_DOF*N_local_DOF); tdouble* dp = d.get_tmp_vptr();			// Ni1=rows; Ni2=columns
    flxVec r(N_local_DOF*N_local_DOF);
    flxVec *rv[3];
      for (tuint i=0;i<3;++i) rv[i] = new flxVec(pOrder[i]+1);
    flxVec *rv2[3];
      for (tuint i=0;i<3;++i) rv2[i] = new flxVec(pOrder[i]+1);
    GI->check_GA_polynomialDegree(pom*2+1+DegCorr+DegStd);
    const tuint GN[3] = {GI->pDegree2GPs(pOrder[0]+1+DegCorr+DegStd),GI->pDegree2GPs(pOrder[1]+1+DegCorr+DegStd),GI->pDegree2GPs(pOrder[2]+1+DegCorr+DegStd)};
    flxPoint p(ZERO,ZERO,ZERO);
    tdouble* ccpos = mesh_outer_cc;
    const tuint* vpos = mesh_outer;
    // register progress-bar
      std::ostream &op = *(GlobalVar.get_cout());
      FlxProgress prg(op,true);
      op.flush();
      prg.start(MAXCOUNT);
    calc_local_corrMtx_KLE_rec(0,vpos,ccpos,GN,p,d,r,s,t,rv,rv2,prg);
    // deactivate the progress-bar
      prg.stop();
    for (tuint i=0;i<3;++i) delete rv[i];
    for (tuint i=0;i<3;++i) delete rv2[i];
    d*=pow2(box->get_detJ());
  // map the local matrix to the global matrix
    tdouble* mtxp = Cmtx.get_VecPointer();
    tuint c=0;
    for (tuint i=0;i<N_local_DOF;++i) {
      for (tuint j=0;j<i;++j) {
	mtxp[c++] = (dp[i*N_local_DOF+j]+dp[j*N_local_DOF+i])/2.0;
      }
      mtxp[c++] = dp[i*N_local_DOF+i];
    }
}

void flxElement_KL_3D::calc_local_corrMtx_KLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, const tuint* GN, flxPoint& p, flxVec& d, flxVec& r, flxVec& s, flxVec& t, flxVec** rv, flxVec** rv2, FlxProgress& prg) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      tuint GNl[3] = {GN[0],GN[1],GN[2]};
      update_GN(level,GNl);
      const tdouble dhh = dha[level+1];
      ++vpos;
      flxPoint pt = p+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      pt = p+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      pt = p+flxPoint(dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      pt = p+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      pt = p+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      pt = p+flxPoint(dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      pt = p+flxPoint(dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      pt = p+flxPoint(-ONE*dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else calc_local_corrMtx_KLE_rec(level+1,vpos,ccpos,GNl,pt,d,r,s,t,rv,rv2,prg);
      return;
    }
    case 1:		// no geometry
      ++vpos;
      return;
    case 2:
    {
      // integration
      const tdouble* rvp[3] = {&((*rv[0])[0]),&((*rv[1])[0]),&((*rv[2])[0])};
      tdouble* dp = d.get_tmp_vptr();
      tdouble* sp = s.get_tmp_vptr();
      tdouble* tp = t.get_tmp_vptr();
      const tdouble& d1 = *(ccpos++);
      const tdouble& d2 = *(ccpos++);
      const tdouble& d3 = *(ccpos++);
      flxPoint lxp(d1,d2,d3);
      XXX_vec(*rv[0],lxp.id_fast(0));
      XXX_vec(*rv[1],lxp.id_fast(1));
      XXX_vec(*rv[2],lxp.id_fast(2));
      XXX_3D_base(sp,rvp);
      update_globalConst_o(lxp);
      tdouble f = ptrFunSigma->calc() * 8.0 * pow(dha[level],3) * (*(ccpos++));
      s*=f;
      calc_local_corrMtx_KLE_inner(t,rv2);
      tuint c=0;
      for (tuint k=0;k<N_local_DOF;++k) {
	for (tuint l=0;l<N_local_DOF;++l) {
	  dp[c++]+=sp[k]*tp[l];
	}
      }
      ++vpos;
      break;
    }
    case 3:
    {
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GN[0]);
	const tdouble* GWx = GI->get_GW(GN[0]);
	const tdouble* GPy = GI->get_GP(GN[1]);
	const tdouble* GWy = GI->get_GW(GN[1]);
	const tdouble* GPz = GI->get_GP(GN[2]);
	const tdouble* GWz = GI->get_GW(GN[2]);
      // integration
	r=ZERO;
	const tdouble* rvp[3] = {&((*rv[0])[0]),&((*rv[1])[0]),&((*rv[2])[0])};
	tdouble* rp = r.get_tmp_vptr();
	tdouble* sp = s.get_tmp_vptr();
	tdouble* tp = t.get_tmp_vptr();
	const tdouble dh = dha[level];
	tdouble sigma_eval;
	flxPoint lxp;
	for (tuint i=0;i<GN[0];++i) {
	  lxp.id_fast(0) = p.id_fast(0)+dh*GPx[i];
	  XXX_vec(*rv[0],lxp.id_fast(0));
	  for (tuint j=0;j<GN[1];++j) {
	    lxp.id_fast(1) = p.id_fast(1)+dh*GPy[i];
	    XXX_vec(*rv[1],lxp.id_fast(1));
	    for (tuint m=0;m<GN[2];++m) {
	      lxp.id_fast(2) = p.id_fast(2)+dh*GPz[m];
	      update_globalConst_o(lxp);
	      sigma_eval = ptrFunSigma->calc() * GWx[i]*GWy[j]*GWz[m];
	      XXX_vec(*rv[2],lxp.id_fast(2));
	      XXX_3D_base(sp,rvp);
	      s*=sigma_eval;
	      calc_local_corrMtx_KLE_inner(t,rv2);
	      tuint c=0;
	      for (tuint k=0;k<N_local_DOF;++k) {
		for (tuint l=0;l<N_local_DOF;++l) {
		  rp[c++]+=sp[k]*tp[l];
		}
	      }
	    }
	  }
	}
	r*=dh*dh*dh;
	d+=r;
      ++vpos;
      break;
    }
    default:
      break;
  }
  // runtime-output
    NOWCOUNT+=GN[0]*GN[1]*GN[2];
    if ((NOWCOUNT*100)/MAXCOUNT-LASTCOUNT>=2) {
      prg.tick(NOWCOUNT);
    }
}

void flxElement_KL_3D::calc_local_collocMtx(const tnlong nid, FlxMtx& Amtx, const tdouble& sd)
{
  throw FlxException_NotImplemented("flxElement_KL_3D::calc_local_collocMtx");
}

const tdouble flxElement_KL_3D::calc_djNj2(const tdouble* dVec) const
{
  if (is_empty) return ZERO;
  flxVec *rv[3];
  for (tuint i=0;i<3;++i) rv[i] = new flxVec(pOrder[i]+1);
  tdouble* ccpos = mesh_single_cc;
  const tuint* vpos = mesh_single;
  const tuint GN[3] = {GI->pDegree2GPs(pOrder[0]*2),GI->pDegree2GPs(pOrder[1]*2),GI->pDegree2GPs(pOrder[2]*2)};
  flxPoint p(ZERO,ZERO,ZERO);
  const tdouble res = calc_djNj2_rec(0,vpos,ccpos,GN,p,dVec,rv)*box->get_detJ();
  for (tuint i=0;i<3;++i) delete rv[i];
  return res;
}

const tdouble flxElement_KL_3D::calc_djNj2_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, const tuint* GN, flxPoint& p, const tdouble* dVec, flxVec** rv) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      tuint GNl[3] = {GN[0],GN[1],GN[2]};
      update_GN(level,GNl);
      const tdouble dhh = dha[level+1];
      tdouble res = ZERO;
      ++vpos;
      flxPoint pt = p+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);
      pt = p+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);
      pt = p+flxPoint(dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);
      pt = p+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);
      pt = p+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);;
      pt = p+flxPoint(dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);
      pt = p+flxPoint(dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);
      pt = p+flxPoint(-ONE*dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else res+=calc_djNj2_rec(level+1,vpos,ccpos,GNl,pt,dVec,rv);
      return res;
    }
    case 1:		// no geometry
      ++vpos;
      return ZERO;
    case 2:
    {
      const tdouble* rvp[3] = {&((*rv[0])[0]),&((*rv[1])[0]),&((*rv[2])[0])};
      XXX_vec(*rv[0],*(ccpos++));
      XXX_vec(*rv[1],*(ccpos++));
      XXX_vec(*rv[2],*(ccpos++));
      ++vpos;
      return pow2(XXX_3D_rlz(rvp,dVec))*8.0*(*(ccpos++))*pow(dha[level],3);
    }
    case 3:
    default:		// mixed or full
    {
      // get Gauss points
	const tdouble* GPx = GI->get_GP(GN[0]);
	const tdouble* GWx = GI->get_GW(GN[0]);
	const tdouble* GPy = GI->get_GP(GN[1]);
	const tdouble* GWy = GI->get_GW(GN[1]);
	const tdouble* GPz = GI->get_GP(GN[2]);
	const tdouble* GWz = GI->get_GW(GN[2]);
      // integration
	const tdouble* rvp[3] = {(*rv[0]).get_tmp_vptr_const(),(*rv[1]).get_tmp_vptr_const(),(*rv[2]).get_tmp_vptr_const()};
	const tdouble dh = dha[level];
	tdouble res=ZERO, r,s;
	flxPoint lxp;
	for (tuint i=0;i<GN[0];++i) {
	  lxp.id_fast(0) = p.id_fast(0)+dh*GPx[i];
	  XXX_vec(*rv[0],lxp.id_fast(0));
	  r = ZERO;
	  for (tuint j=0;j<GN[1];++j) {
	    lxp.id_fast(1) = p.id_fast(1)+dh*GPy[j];
	    XXX_vec(*rv[1],lxp.id_fast(1));
	    s=ZERO;
	    for (tuint k=0;k<GN[2];++k) {
	      lxp.id_fast(2) = p.id_fast(2)+dh*GPz[k];
	      XXX_vec(*rv[2],lxp.id_fast(2));
	      s += pow2(XXX_3D_rlz(rvp,dVec))*GWz[k];
	    }
	    s*=GWy[j];
	    r+=s;
	  }
	  r*=GWx[i];
	  res+=r;
	}
      ++vpos;
      return res*dh*dh*dh;
    }
  }
}

const tdouble flxElement_KL_3D::calc_djNj(const tdouble* dVec, const tdouble& x, const tdouble& y, const tdouble& z) const
{
  const tdouble* rvp[3] = {&((*djNj_xV[0])[0]),&((*djNj_xV[1])[0]),&((*djNj_xV[2])[0])};
  if (x!=djNj_x[0]||y!=djNj_x[1]||z!=djNj_x[2]) {
    if (x!=djNj_x[0]) {
      djNj_x[0] = x;
      XXX_vec(*djNj_xV[0],x);
    }
    if (y!=djNj_x[1]) {
      djNj_x[1] = y;
      XXX_vec(*djNj_xV[1],y);
    }
    if (z!=djNj_x[2]) {
      djNj_x[2] = z;
      XXX_vec(*djNj_xV[2],z);
    }
    XXX_3D_base(&(*djNj_bV)[0],rvp);
  }
  const tdouble* bp = &(*djNj_bV)[0];
  tdouble res=ZERO;
  for (tuint i=0;i<N_local_DOF;++i) {
    res+=dVec[i]*bp[i];
  }
  return res;
}

const tdouble flxElement_KL_3D::err_var_domain() const
{
  throw FlxException_NotImplemented("flxElement_KL_3D::err_var_domain");
}

const tdouble flxElement_KL_3D::err_cov_domain() const
{
  throw FlxException_NotImplemented("flxElement_KL_3D::err_cov_domain");
}

void flxElement_KL_3D::plot_el(std::ostream& sout, FlxMtxConstFun* ppdim, const int errMeasure, const int prec, const int fixW, const bool checkTOL) const
{
  if (is_empty) return;
  const size_t DIM = ptrEigenvectors->size();
  const iVec ppdim_help = ConstMtxBox->get_Vec_cast2tuint(ppdim->eval(),true);;
  if (ppdim_help.size()!=3) {
    std::ostringstream ssV;
    ssV << "The dimension of the vector has to be '3'.";
    throw FlxException("flxElement_KL_3D::plot_el", ssV.str() );
  }
  const tuint PPDIM_X = ppdim_help[0];
  const tuint PPDIM_Y = ppdim_help[1];
  const tuint PPDIM_Z = ppdim_help[2];
  const tdouble dx = 2.0/PPDIM_X;
  const tdouble dy = 2.0/PPDIM_Y;
  const tdouble dz = 2.0/PPDIM_Z;
  tdouble x = -ONE + dx/2;
  for (tuint i=0;i<PPDIM_X;++i) {
    tdouble y = -ONE + dy/2.0;
    for (tuint j=0;j<PPDIM_Y;++j) {
      tdouble z = -ONE + dz/2.0;
      for (tuint l=0;l<PPDIM_Z;++l) {
	flxPoint p(x,y,z);
	update_globalConst(p);
	if ( (geo_fun && geo_fun->calc()>=ZERO) || !geo_fun) {
	  sout << GlobalVar.Double2String(*GX,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GY,false,prec,fixW) << ' ' << GlobalVar.Double2String(*GZ,false,prec,fixW) << ' ';
	  sout << GlobalVar.Double2String(get_error(x,y,z,errMeasure),checkTOL);
	  for (tuint k=0;k<DIM;++k) {
	    sout << ' ' << GlobalVar.Double2String(calc_djNj(&(ptrEigenvectors->operator[](k))[0],x,y,z),true,prec,fixW);
	  }
	  sout << std::endl;
	}
	z+=dz;
      }
      y+=dy;
    }
    x+=dx;
    sout << std::endl;
  }
  sout << std::endl;
}

void flxElement_KL_3D::plotcov_el(std::ostream& sout, const flxPoint& pp, FlxMtxConstFun* ppdim, const flxVec& tr, const int prec, const int fixW) const
{
  throw FlxException_NotImplemented("flxElement_KL_3D::plotcov_el");
}

void flxElement_KL_3D::assembleEOLEpointVec(std::vector< flxPoint >& pointVec, const tuint Npt, tdouble* Nia) const
{
  if (is_empty) return;
  switch (EOLE_SMP_MTH) {
    case 1:
      {
	// define some vecotrs ... only relevant if Npt>0
	  #ifndef FLX_CV_1
	    tdouble sp[N_local_DOF];
	  #else
	    tdouble *sp = new tdouble[N_local_DOF];
	  #endif
	  flxVec *rv[3];
	  for (tuint i=0;i<3;++i) rv[i] = new flxVec(pOrder[i]+1);
	  const tdouble* rvp[3] ={&((*rv[0])[0]),&((*rv[1])[0]),&((*rv[2])[0])};
	const tdouble dx = 2.0/EOLE_N[0];
	const tdouble dy = 2.0/EOLE_N[1];
	const tdouble dz = 2.0/EOLE_N[2];
	flxPoint p;
	p.id_fast(0) = -ONE + dx/2.0;
	for (tuint i=0;i<EOLE_N[0];++i) {
	  p.id_fast(1) = -ONE + dy/2.0;
	  for (tuint j=0;j<EOLE_N[1];++j) {
	    p.id_fast(2) = -ONE + dz/2.0;
	    for (tuint k=0;k<EOLE_N[2];++k) {
	      update_globalConst(p);
	      if ( (geo_fun && geo_fun->calc()>=ZERO) || !geo_fun) {
		flxPoint pg(*(GX+0),*(GX+1),*(GX+2));
		const tnlong id = pointVec.size();
		pointVec.push_back(pg);
		if (Npt>0) {
		  XXX_vec(*rv[0],p.id_fast(0));
		  XXX_vec(*rv[1],p.id_fast(1));
		  XXX_vec(*rv[2],p.id_fast(2));
		  XXX_3D_base(sp,rvp);
		  // mapping 
		    for (tuint k=0;k<N_local_DOF;++k) {
		      Nia[k*Npt+id] = sp[k];
		    }
		}
	      }
	      p.id_fast(2)+=dz;
	    }
	    p.id_fast(1)+=dy;
	  }
	  p.id_fast(0)+=dx;
	}
	for (tuint i=0;i<3;++i) delete rv[i];
	#ifdef FLX_CV_1
	  delete [] sp;
	#endif
      }
      break;
    case 2:
      {
	throw FlxException_NotImplemented("flxElement_KL_2D::assembleEOLEpointVec");
      }
      break;
    default:
      {
	std::ostringstream ssV;
	ssV << "A EOLE-sampling-method with index '" << EOLE_SMP_MTH << "is not defined.";
	throw FlxException("flxElement_KL_2D::assembleEOLEpointVec", ssV.str() );
      }
  }
}

void flxElement_KL_3D::get_PlotPoints(std::vector< flxPoint >& pointVec, std::vector< tuint >& geoVec, FlxMtxConstFun* ppdim) const
{
  pointVec.clear();
  if (is_empty) return;
  iVec t = ConstMtxBox->get_Vec_cast2tuint(ppdim->eval(),true);;
  if (t.size()!=3) {
    std::ostringstream ssV;
    ssV << "The dimension of the vector has to be '3'.";
    throw FlxException("flxElement_KL_3D::get_PlotPoints", ssV.str() );
  }
  const tuint PPDIM_X = t[0];
  const tuint PPDIM_Y = t[1];
  const tuint PPDIM_Z = t[1];
  const tdouble dx = 2.0/PPDIM_X;
  const tdouble dy = 2.0/PPDIM_Y;
  const tdouble dz = 2.0/PPDIM_Z;
  flxPoint p;
  p.id_fast(0) = -ONE + dx/2.0;
  for (tuint i=0;i<PPDIM_X;++i) {
    p.id_fast(1) = -ONE + dy/2.0;
    for (tuint j=0;j<PPDIM_Y;++j) {
      p.id_fast(2) = -ONE + dz/2.0;
      for (tuint k=0;k<PPDIM_Z;++k) {
	update_globalConst(p);
	if ( (geo_fun && geo_fun->calc()>=ZERO) || !geo_fun) {
	  pointVec.push_back(flxPoint(*(GX+0),*(GX+1),*(GX+2)));
	}
	p.id_fast(2)+=dz;
      }
      p.id_fast(1)+=dy;
    }
    p.id_fast(0)+=dx;
    geoVec.push_back(pointVec.size());
  }
}

const tdouble flxElement_KL_3D::err_var_domain_EOLE(flxVec& Hx, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, const bool abs) const
{
  if (is_empty) return ZERO;
  tdouble* ccpos = mesh_single_cc;
  const tuint* vpos = mesh_single;
  const tuint GN = GI->pDegree2GPs(DegCorr+DegStd*2);			// of course this won't be an exact integration
  const tuint GNp[3] = {GN,GN,GN};
  flxPoint p(ZERO,ZERO,ZERO);
  return err_var_domain_EOLE_rec(0,vpos,ccpos,GNp,p,Hx,pointVec,sdVec,abs)*box->get_detJ();  
}

const tdouble flxElement_KL_3D::err_var_domain_EOLE_rec(const tuint level, const_tuintPtr& vpos, tdoublePtr& ccpos, const tuint* GN, flxPoint& p, flxVec& Hx, const std::vector< flxPoint >& pointVec, const flxVec& sdVec, const bool abs) const
{
  switch (*vpos) {
    case 0:		// parent
    {
      tuint GNl[3] = {GN[0],GN[1],GN[2]};
      update_GN(level,GNl);
      const tdouble dhh = dha[level+1];
      tdouble res = ZERO;
      ++vpos;
      flxPoint pt = p+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      pt = p+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      pt = p+flxPoint(dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      pt = p+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      pt = p+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      pt = p+flxPoint(dhh,-ONE*dhh,dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      pt = p+flxPoint(dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      pt = p+flxPoint(-ONE*dhh,dhh,dhh);
	if (*vpos==1) ++vpos; else res+=err_var_domain_EOLE_rec(level+1,vpos,ccpos,GNl,pt,Hx,pointVec,sdVec,abs);
      return res;
    }
    case 1:		// no geometry
      ++vpos;
      return ZERO;
    case 2:
    {
      const tuint DIM = ptrEigenvalues->get_N();  
      const tdouble& d1 = *(ccpos++);
      const tdouble& d2 = *(ccpos++);
      const tdouble& d3 = *(ccpos++);
      flxPoint lxp(d1,d2,d3);
      tdouble sD_curr_x_2;
      update_globalConst_o(lxp);
      assemble_Hx_EOLE(Hx,sD_curr_x_2,pointVec,sdVec);
      sD_curr_x_2 = pow2(sD_curr_x_2);
      tdouble t = sD_curr_x_2;
      for (tuint l=0;l<DIM;++l) {
	t -= pow2( ( ptrEigenvectors->operator[](l) * Hx ) * ptrEigenvalues->operator[](l) );
      }
      if (abs) t = fabs(t);
      ++vpos;
      return t/sD_curr_x_2*8.0*(*(ccpos++))*pow(dha[level],3);
    }
    case 3:
    default:		// mixed or full
    {
      const tuint DIM = ptrEigenvalues->get_N();  
      // get Gauss-points
	const tdouble* GPx = GI->get_GP(GN[0]);
	const tdouble* GWx = GI->get_GW(GN[0]);
	const tdouble* GPy = GI->get_GP(GN[1]);
	const tdouble* GWy = GI->get_GW(GN[1]);
	const tdouble* GPz = GI->get_GP(GN[2]);
	const tdouble* GWz = GI->get_GW(GN[2]);
      const tdouble dh = dha[level];
      flxPoint lxp;
      tdouble res=ZERO, r,s, t, sD_curr_x_2;
      for (tuint i=0;i<GN[0];++i) {
	lxp.id_fast(0) = p.id_fast(0)+dh*GPx[i];
	r = ZERO;
	for (tuint j=0;j<GN[1];++j) {
	  lxp.id_fast(1) = p.id_fast(1)+dh*GPy[j];
	  s = ZERO;
	  for (tuint k=0;k<GN[2];++k) {
	    lxp.id_fast(2) = p.id_fast(2)+dh*GPz[k];
	    update_globalConst_o(lxp);
	    assemble_Hx_EOLE(Hx,sD_curr_x_2,pointVec,sdVec);
	    sD_curr_x_2 = pow2(sD_curr_x_2);
	    t = sD_curr_x_2;
	    for (tuint l=0;l<DIM;++l) {
	      t -= pow2( ( ptrEigenvectors->operator[](l) * Hx ) * ptrEigenvalues->operator[](l) );
	    }
	    if (abs) t = fabs(t);
	    s += t/sD_curr_x_2*GWz[k];
	  }
	  s*=GWy[j];
	  r+=s;
	}
	r*=GWx[i];
	res+=r;
      }
      ++vpos;
      return res*dh*dh*dh;
    }
  }
}

const tdouble flxElement_KL_3D::err_cov_domain_EOLE(const std::vector< flxPoint >& pointVec, const flxVec& sdVec) const
{
  throw FlxException_NotImplemented("flxElement_KL_3D::err_cov_domain_EOLE");
}

const bool flxElement_KL_3D::map2local(const flxPoint& p) const
{
  throw FlxException_NotImplemented("flxElement_KL_3D::map2local");
}

FlxKLelementProp_base::~FlxKLelementProp_base()
{
  if (degCorr) delete degCorr;
  if (degStd) delete degStd;
  if (geo_fun) delete geo_fun;
}

void FlxKLelementProp_base::read_fun(FlxFunctionPtr& fp, const std::string str) const
{
  reader->getWord(str.c_str(),false);
  reader->getChar('=',false);
  if (fp) {
    std::ostringstream ssV;
    ssV << "'" << str << "' has aleready been defined.";
    throw FlxException("FlxKLelementProp_base::read_fun_"+str, ssV.str() );
  }
  fp = new FlxFunction(funReader,false);
}

const tuint FlxKLelementProp_base::get_degCorr()
{
  if (degCorr) {
    return degCorr->cast2tuintW0();
  } else {
    return 6;
  }
}

const tuint FlxKLelementProp_base::get_degStd()
{
  if (degStd) {
    return degStd->cast2tuintW0();
  } else {
    return 0;
  }
}

FlxKLelementProp_1D::FlxKLelementProp_1D(bool errSerious)
:maxsize_1(NULL),maxsize_2(NULL),minsize(NULL),maxsize_out(NULL),
maxsize_err2_1(NULL),maxsize_err2_2(NULL),maxsize_err2_o(NULL),
pOrder(NULL), geo_intnumb(NULL), geo_imin(NULL)
{
  try {
    bool b=true;
    do {
      if (reader->whatIsNextString(6,true) == "porder") {
	reader->getWord("porder",false);
	reader->getChar('=',false);
	if (pOrder!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'pOrder' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_1", ssV.str() );
	}
	pOrder = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(7,true) == "degcorr") {
	reader->getWord("degcorr",false);
	reader->getChar('=',false);
	if (degCorr!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'degcorr' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_2", ssV.str() );
	}
	degCorr = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(6,true) == "degstd") {
	reader->getWord("degstd",false);
	reader->getChar('=',false);
	if (degStd!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'degstd' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_3", ssV.str() );
	}
	degStd = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(8,true) == "maxsize1") {
	reader->getWord("maxsize1",false);
	reader->getChar('=',false);
	if (maxsize_1!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'maxsize1' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_4", ssV.str() );
	}
	maxsize_1 = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(8,true) == "maxsize2") {
	reader->getWord("maxsize2",false);
	reader->getChar('=',false);
	if (maxsize_2!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'maxsize2' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_5", ssV.str() );
	}
	maxsize_2 = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(8,true) == "maxsizeo") {
	reader->getWord("maxsizeo",false);
	reader->getChar('=',false);
	if (maxsize_out!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'maxsizeo' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_6", ssV.str() );
	}
	maxsize_out = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(7,true) == "minsize") {
	reader->getWord("minsize",false);
	reader->getChar('=',false);
	if (minsize!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'minsize' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_7", ssV.str() );
	}
	minsize = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(14,true) == "maxsize_err2_1") {
	reader->getWord("maxsize_err2_1",false);
	reader->getChar('=',false);
	if (maxsize_err2_1!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'maxsize_err2_1' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_8", ssV.str() );
	}
	maxsize_err2_1 = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(14,true) == "maxsize_err2_2") {
	reader->getWord("maxsize_err2_2",false);
	reader->getChar('=',false);
	if (maxsize_err2_2!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'maxsize_err2_2' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_9", ssV.str() );
	}
	maxsize_err2_2 = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(14,true) == "maxsize_err2_o") {
	reader->getWord("maxsize_err2_o",false);
	reader->getChar('=',false);
	if (maxsize_err2_o!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'maxsize_err2_o' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_10", ssV.str() );
	}
	maxsize_err2_o = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(3,true) == "geo") {
	reader->getWord("geo",false);
	reader->getChar('=',false);
	if (geo_fun!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'geo' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_11", ssV.str() );
	}
	geo_fun = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(11,true) == "geo_intnumb") {
	reader->getWord("geo_intnumb",false);
	reader->getChar('=',false);
	if (geo_intnumb!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'geo_intnumb' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_12", ssV.str() );
	}
	geo_intnumb = new FlxFunction(funReader,false);
      } else if (reader->whatIsNextString(10,true) == "geo_intmin") {
	reader->getWord("geo_intmin",false);
	reader->getChar('=',false);
	if (geo_imin!=NULL) {
	  std::ostringstream ssV;
	  ssV << "'geo_intmin' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_1D::FlxKLelementProp_1D_13", ssV.str() );
	}
	geo_imin = new FlxFunction(funReader,false);
      } else {
	b=false;
      }
    } while (b);
  } catch (FlxException &e) {
    FLXMSG("lxKLelementProp_1D::FlxKLelementProp_1D_14",1);
    if (pOrder) { delete pOrder; pOrder=NULL; }
    if (maxsize_1) { delete maxsize_1; maxsize_1=NULL; }
    if (maxsize_2) { delete maxsize_2; maxsize_2=NULL; }
    if (minsize) { delete minsize; minsize=NULL; }
    if (maxsize_out) { delete maxsize_out; maxsize_out=NULL; }
    if (maxsize_err2_1) { delete maxsize_err2_1; maxsize_err2_1=NULL; }
    if (maxsize_err2_2) { delete maxsize_err2_2; maxsize_err2_2=NULL; }
    if (maxsize_err2_o) { delete maxsize_err2_o; maxsize_err2_o=NULL; }
    if (geo_intnumb) { delete geo_intnumb; geo_intnumb=NULL; }
    if (geo_imin) { delete geo_imin; geo_imin=NULL; }
    if (degCorr) { delete degCorr; degCorr=NULL; }
    if (degStd) { delete degStd; degStd=NULL; }
    if (geo_fun) { delete geo_fun; geo_fun=NULL; }
    throw;
  }
}

FlxKLelementProp_1D::~FlxKLelementProp_1D()
{
  if (pOrder) delete pOrder;
  if (maxsize_1) delete maxsize_1;
  if (maxsize_2) delete maxsize_2;
  if (maxsize_out) delete maxsize_out;
  if (minsize) delete minsize;
  if (maxsize_err2_1) delete maxsize_err2_1;
  if (maxsize_err2_2) delete maxsize_err2_2;
  if (maxsize_err2_o) delete maxsize_err2_o;
  if (geo_intnumb) delete geo_intnumb;
  if (geo_imin) delete geo_imin;
}

const tuint FlxKLelementProp_1D::get_pOrder()
{
  if (pOrder!=NULL) {
    return pOrder->cast2tuint();
  } else {
    return 1;
  }
}

const bool FlxKLelementProp_1D::do_geo_refine_1D(const flxEdge& klbel)
{
  geo_vector.clear();
  geo_vector_bool.clear();
  if (geo_fun == NULL)  {
    geo_vector.push_back(-ONE);
    geo_vector.push_back(ONE);
    geo_vector_bool.push_back(true);
    return true;
  }
  tuint GIN = 100;
  if (geo_intnumb!=NULL) {
    GIN = geo_intnumb->cast2tuint();
  }
  const tdouble dx = 2.0/GIN;
  klbel.update_globalConst(-ONE);
  bool gprev = (geo_fun->calc()>=ZERO);
  if (gprev) {
    geo_vector.push_back(-ONE);
    geo_vector_bool.push_back(true);
  }
  bool gnow = false;
  tdouble lx_0, lx_u,lx_o,lx_m;
  tdouble GIM = 1e-6;
  if (geo_imin!=NULL) {
    GIM = geo_imin->cast2positive();
  }
  const tdouble min = GIM * 2.0;
  for (tdouble lx = -ONE+dx; lx <= ONE+dx/2.0; lx+=dx) {
    if (lx>ONE) lx = ONE;
    klbel.update_globalConst(lx);
    gnow = (geo_fun->calc()>=ZERO);
    if (gnow!=gprev) {	// change in geometry
      // search for changing value
	if ( geo_fun->calc() == ZERO ) lx_0 = lx;
	else {
	  klbel.update_globalConst(lx-dx);
	  if ( geo_fun->calc() == ZERO ) lx_0 = lx-dx;
	  else {
	    lx_u = lx-dx;
	    lx_o = lx;
	    while (lx_o-lx_u > min) {
	      lx_m = lx_u+(lx_o-lx_u)/2.0;
	      klbel.update_globalConst(lx_m);
	      lx_0 = geo_fun->calc();
	      if (lx_0 == ZERO) break;
	      else if (lx_0 > ZERO) {
		if (gprev) {
		  lx_u = lx_m;
		} else {
		  lx_o = lx_m;
		}
	      } else {
		if (gprev) {
		  lx_o = lx_m;
		} else {
		  lx_u = lx_m;
		}
	      }
	    }
	    if (lx_0!=ZERO) {
	      lx_0 = lx_u+(lx_o-lx_u)/2.0;
	    }
	  }
	}
	geo_vector.push_back(lx_0);
	geo_vector_bool.push_back(gnow);
	gprev = gnow;
    }
  }
  if (geo_vector.empty()) {
    return false;
  }
  if (!gnow) {
    geo_vector_bool.pop_back();
  } else {
    geo_vector.push_back(ONE);
  }
  return true;
}

void FlxKLelementProp_1D::get_refine_1D(const int idx, std::vector< tdouble >& resVec, std::vector<bool> &resVecGeo)
{
  resVec = geo_vector;
  resVecGeo = geo_vector_bool;
  if (geo_vector.empty()) {
    return;
  }
  
  // determine maximum interval size
    tdouble maxs;
    if (idx==0) {
      if (maxsize_1==NULL) maxs = ONE;
      else maxs = maxsize_1->cast2positive();
    } else if (idx==1) {
      if (maxsize_2==NULL) maxs = ONE;
      else maxs = maxsize_2->cast2positive();
    } else if (idx==2) {
      if (maxsize_out==NULL) maxs = ONE;
      else maxs = maxsize_out->cast2positive();
    } else {
      throw FlxException_Crude("FlxKLelementProp::get_refine_1");
    }
    if (maxs>ONE) {
      std::ostringstream ssV;
      ssV << "The maximum interval size is lager than 100%.";
      throw FlxException("FlxKLelementProp::get_refine_2", ssV.str() );
    }
    maxs*=2.0;
  
  // check if an interval is larger than maxs
    tuint i = 0, j,k;
    tdouble dx;
    do {
      if (!resVecGeo[i]) continue;
      dx = resVec[i+1]-resVec[i];
      if (dx>maxs) {
	j = tuint(dx/maxs+0.999);
	dx /= j;
	for (k=1;k<j;++k) {
	  resVec.insert(resVec.begin()+i+1,resVec[i]+dx);
	  resVecGeo.insert(resVecGeo.begin()+i,true);
	  ++i;
	}
      }
      i+=2;
    } while (i<resVec.size()-1);
}

void FlxKLelementProp_1D::refine_vec(const int idx, std::vector< tdouble >& resVec, std::vector< bool >& resVecGeo, const std::vector< tdouble >& iVec, const std::vector< bool >& iVecb)
{
  resVec.clear(); 
  resVecGeo.clear();
  if (geo_vector.empty()) return;
  tdouble maxs;
  if (idx==0) {
    if (maxsize_err2_1==NULL) maxs = 0.05;
    else maxs = maxsize_err2_1->cast2positive();
  } else if (idx==1) {
    if (maxsize_err2_2==NULL) maxs = 0.1;
    else maxs = maxsize_err2_2->cast2positive();
  } else if (idx==2) {
    if (maxsize_err2_o==NULL) maxs = 0.05;
    else maxs = maxsize_err2_o->cast2positive();
  } else {
    throw FlxException_Crude("FlxKLelementProp::refine_vec_1");
  }
  maxs *= 2.0;
  // perform the refinement
  resVec.push_back(iVec[0]);
  tdouble t;
  for (tuint i=1;i<iVec.size();++i) {
    if (iVecb[i-1]) {
      t = (iVec[i]-iVec[i-1])/maxs;
      if ( t > 1 ) {
	tuint j = tuint(t+0.999);	// j = number of intervals
	t = (iVec[i]-iVec[i-1])/j;
	for (tuint k=1;k<j;++k) {
	  resVec.push_back(iVec[i-1]+t*k);
	  resVecGeo.push_back(true);
	}
      }
    }
    resVec.push_back(iVec[i]);
    resVecGeo.push_back(iVecb[i-1]);
  }
}

void FlxKLelementProp_1D::get_geo_info(std::vector< tdouble >& resVec, std::vector< bool >& resVecGeo) const
{
  resVec = geo_vector;
  resVecGeo = geo_vector_bool;
}

FlxKLelementProp_2D::FlxKLelementProp_2D(const bool errSerious)
:face(NULL),pOrderLx(NULL),pOrderLy(NULL),tensorSpace(false),
area_min_level(NULL),area_max_level(NULL),EOLE_SMP_MTH(NULL),EOLE_N_LX(NULL),EOLE_N_LY(NULL),EOLE_N(NULL),
integ1l_min_level(NULL),integ1l_max_level(NULL),outer_min_level(NULL),outer_max_level(NULL),
inner_s_min_level(NULL),inner_s_max_level(NULL),inner_d_min_level(NULL),inner_d_max_level(NULL),
err_is_min_level(NULL),err_is_max_level(NULL),err_id_min_level(NULL),err_id_max_level(NULL),
cellAreaPoints(NULL),covThreshold(NULL)
{
  try {
    bool b=true;
    do {
      if (reader->whatIsNextString(8,true) == "porderlx") {
	read_fun(pOrderLx,"porderlx");
      } else if (reader->whatIsNextString(8,true) == "porderly") {
	read_fun(pOrderLy,"porderly");
      } else if (reader->whatIsNextString(7,true) == "degcorr") {
	read_fun(degCorr,"degcorr");
      } else if (reader->whatIsNextString(6,true) == "degstd") { 
	read_fun(degStd,"degstd");
      } else if (reader->whatIsNextString(3,true) == "geo") {
	read_fun(geo_fun,"geo");
      } else if (reader->whatIsNextString(11,true) == "tensorspace") {
	reader->getWord("tensorspace",false);
	reader->getChar('=',false);
	FlxFunction* tb = new FlxFunction(funReader,errSerious);
	tensorSpace = (tb->cast2int()!=0);
	delete tb;
      } else if (reader->whatIsNextString(14,true) == "area_min_level") {
	read_fun(area_min_level,"area_min_level");
      } else if (reader->whatIsNextString(14,true) == "area_max_level") {
	read_fun(area_max_level,"area_max_level");
      } else if (reader->whatIsNextString(12,true) == "eole_smp_mth") {
	read_fun(EOLE_SMP_MTH,"eole_smp_mth");
      } else if (reader->whatIsNextString(9,true) == "eole_n_lx") {
	read_fun(EOLE_N_LX,"eole_n_lx");
      } else if (reader->whatIsNextString(9,true) == "eole_n_ly") {
	read_fun(EOLE_N_LY,"eole_n_ly");
      } else if (reader->whatIsNextString(6,true) == "eole_n") {
	read_fun(EOLE_N,"eole_n");
      } else if (reader->whatIsNextString(17,true) == "integ1l_min_level") {
	read_fun(integ1l_min_level,"integ1l_min_level");
      } else if (reader->whatIsNextString(17,true) == "integ1l_max_level") {
	read_fun(integ1l_max_level,"integ1l_max_level");
      } else if (reader->whatIsNextString(15,true) == "outer_min_level") {
	read_fun(outer_min_level,"outer_min_level");
      } else if (reader->whatIsNextString(15,true) == "outer_max_level") {
	read_fun(outer_max_level,"outer_max_level");
      } else if (reader->whatIsNextString(20,true) == "inner_same_min_level") {
	read_fun(inner_s_min_level,"inner_same_min_level");
      } else if (reader->whatIsNextString(20,true) == "inner_same_max_level") {
	read_fun(inner_s_max_level,"inner_same_max_level");
      } else if (reader->whatIsNextString(20,true) == "inner_diff_min_level") {
	read_fun(inner_d_min_level,"inner_diff_min_level");
      } else if (reader->whatIsNextString(20,true) == "inner_diff_max_level") {
	read_fun(inner_d_max_level,"inner_diff_max_level");
      } else if (reader->whatIsNextString(16,true) == "err_is_min_level") {
	read_fun(err_is_min_level,"err_is_min_level");
      } else if (reader->whatIsNextString(16,true) == "err_is_max_level") {
	read_fun(err_is_max_level,"err_is_max_level");
      } else if (reader->whatIsNextString(16,true) == "err_id_min_level") {
	read_fun(err_id_min_level,"err_id_min_level");
      } else if (reader->whatIsNextString(16,true) == "err_id_max_level") {
	read_fun(err_id_max_level,"err_id_max_level");
      } else if (reader->whatIsNextString(10,true) == "cc_area_pn") {
	read_fun(cellAreaPoints,"cc_area_pn");
      } else if (reader->whatIsNextString(13,true) == "cov_threshold") {
	read_fun(covThreshold,"cov_threshold");
      } else {
	b=false;
      }
    } while (b);
  } catch (FlxException &e) {
    FLXMSG("FlxKLelementProp_2D::FlxKLelementProp_2D_1",1);
    delete_dyn();
    if (degCorr) { delete degCorr; degCorr=NULL; }
    if (degStd) { delete degStd; degStd=NULL; }
    if (geo_fun) { delete geo_fun; geo_fun=NULL; }
    throw;
  }
}

FlxKLelementProp_2D::~FlxKLelementProp_2D()
{
  delete_dyn();
}

void FlxKLelementProp_2D::delete_dyn()
{
  if (pOrderLx) delete pOrderLx;
  if (pOrderLy) delete pOrderLy;
  if (area_min_level) delete area_min_level;
  if (area_max_level) delete area_max_level;
  if (EOLE_SMP_MTH) delete EOLE_SMP_MTH;
  if (EOLE_N_LX) delete EOLE_N_LX;
  if (EOLE_N_LY) delete EOLE_N_LY;
  if (EOLE_N) delete EOLE_N;  
  if (integ1l_min_level) delete integ1l_min_level;
  if (integ1l_max_level) delete integ1l_max_level;
  if (outer_min_level) delete outer_min_level;
  if (outer_max_level) delete outer_max_level;
  if (inner_s_min_level) delete inner_s_min_level;
  if (inner_s_max_level) delete inner_s_max_level;
  if (inner_d_min_level) delete inner_d_min_level;
  if (inner_d_max_level) delete inner_d_max_level;
  if (err_is_min_level) delete err_is_min_level;
  if (err_is_max_level) delete err_is_max_level;
  if (err_id_min_level) delete err_id_min_level;
  if (err_id_max_level) delete err_id_max_level;
  if (cellAreaPoints) delete cellAreaPoints;
  if (covThreshold) delete covThreshold;
}

void FlxKLelementProp_2D::check_cell(const tdouble dhk, const tdouble xm, const tdouble ym, bool& same, bool* gb)
{
  face->update_globalConst(xm-dhk,ym-dhk);
    gb[0] = (geo_fun->calc()>=ZERO);
  face->update_globalConst(xm+dhk,ym-dhk);
    gb[1] = (geo_fun->calc()>=ZERO);
  face->update_globalConst(xm+dhk,ym+dhk);
    gb[2] = (geo_fun->calc()>=ZERO);
  face->update_globalConst(xm-dhk,ym+dhk);
    gb[3] = (geo_fun->calc()>=ZERO);
  face->update_globalConst(xm,ym);
    gb[4] = (geo_fun->calc()>=ZERO);
  for (tuint i=1;i<5;++i) {
    if (gb[0]!=gb[i]) {
      same = false;
      break;
    }
  }
}

const tdouble FlxKLelementProp_2D::get_cellarea(const tdouble dh, const tdouble xm, const tdouble ym, tdouble& cmx, tdouble& cmy)
{
  tuint H=0;
  face->update_globalConst(xm,ym);
  const tuint N = (cellAreaPoints)?cellAreaPoints->cast2tuint():100;
  const tdouble dx = dh*2.0/N;
  tdouble x,y=dx/2.0,sx=ZERO,sy=ZERO;
  for (tuint i=0;i<N;++i) {
    x = dx/2.0;
    for (tuint j=0;j<N;++j) {
      face->update_globalConst(xm+(x-dh),ym+(y-dh));
      if (geo_fun->calc()>=ZERO) {
	++H;
	sx+=x;
	sy+=y;
      }
      x+=dx;
    }
    y+=dx;
  }
  if (H>0) {
    cmx = xm+(sx/H-dh);
    cmy = ym+(sy/H-dh);
  }
  return tdouble(H)/tdouble(N*N);
}

void FlxKLelementProp_2D::refine_mesh_help(std::vector< tuint >& vec, const tuint level, const tuint min_level, const tuint max_level, const tdouble xm, const tdouble ym, std::vector< tdouble >& cutcells)
{
  const tdouble dh = 1./(pow(2.,int(level)));
  bool gb[5];
  bool same=true;
  if (geo_fun) {
    const tdouble dhk = dh*0.999;
    check_cell(dhk,xm,ym,same,gb);
  } else {
    for (tuint i=0;i<5;++i) gb[i] = true;
  }
  if ((min_level>level || !same) && max_level>level) {
    const tdouble dhh = dh/2.0;
    vec.push_back(0);		// parent cell
    refine_mesh_help(vec,level+1,min_level,max_level,xm-dhh,ym-dhh,cutcells);
    refine_mesh_help(vec,level+1,min_level,max_level,xm+dhh,ym-dhh,cutcells);
    refine_mesh_help(vec,level+1,min_level,max_level,xm+dhh,ym+dhh,cutcells);
    refine_mesh_help(vec,level+1,min_level,max_level,xm-dhh,ym+dhh,cutcells);
  } else {
    if (same) {
      if (gb[0]) {
	vec.push_back(3);	// full geometry
      } else {
	vec.push_back(1);	// no geometry
      }
    } else {
      tdouble cmx=xm,cmy=ym;
      const tdouble A = get_cellarea(dh,xm,ym,cmx,cmy);
      if (A<=GlobalVar.TOL()) vec.push_back(1);	// no geometry
      else if (ONE-A<=GlobalVar.TOL()) vec.push_back(3);	// full geometry
      else {
	vec.push_back(2);		// mixed cell
	// add center's
	  cutcells.push_back(cmx);
	  cutcells.push_back(cmy);
	cutcells.push_back(A);
      }
    }
  }
}

const tuint* FlxKLelementProp_2D::refine_mesh(const tuint min_level, const tuint max_level, tdoublePtr& cutcells)
{
  std::vector<tuint> vec;
  std::vector<tdouble> ccV;
  refine_mesh_help(vec,0,min_level,max_level,ZERO,ZERO,ccV);
  const size_t S = vec.size();
  tuint* geov = new tuint[S];
  const tuint* vecp = &vec[0];
  for (tuint i=0;i<S;++i) {
    geov[i] = vecp[i];
  }
  const tuint Ncc = ccV.size();
  if (Ncc>0) {
    cutcells = new tdouble[Ncc];
    tdouble* ccP = &ccV[0];
    for (tuint i=0;i<Ncc;++i) {
      cutcells[i] = ccP[i];
    }
  } else {
    cutcells = NULL;
  }
  return geov;
}

const tuint FlxKLelementProp_2D::get_pOrderLx()
{
  if (pOrderLx) {
    return pOrderLx->cast2tuint();
  } else {
    return 1;
  }
}

const tuint FlxKLelementProp_2D::get_pOrderLy()
{
  if (pOrderLy) {
    return pOrderLy->cast2tuint();
  } else {
    return 1;
  }
}

const tuint FlxKLelementProp_2D::get_area_min_level()
{
  if (area_min_level) {
    return area_min_level->cast2tuintW0();
  } else {
    return 1;
  }
}

const tuint FlxKLelementProp_2D::get_area_max_level()
{
  if (area_max_level) {
    return area_max_level->cast2tuintW0();
  } else {
    return 14;
  }
}

const int FlxKLelementProp_2D::get_EOLE_SMP_MTH()
{
  if (EOLE_SMP_MTH) {
    return EOLE_SMP_MTH->cast2int();
  } else {
    return 1;
  }
}

const tuint FlxKLelementProp_2D::get_EOLE_N_LX()
{
  if (EOLE_N_LX) {
    return EOLE_N_LX->cast2tuint();
  } else {
    return 10;
  }
}

const tuint FlxKLelementProp_2D::get_EOLE_N_LY()
{
  if (EOLE_N_LY) {
    return EOLE_N_LY->cast2tuint();
  } else {
    return 10;
  }
}

const tuint FlxKLelementProp_2D::get_EOLE_N()
{
  if (EOLE_N) {
    return EOLE_N->cast2tuint();
  } else {
    return 100;
  }
}

const tdouble FlxKLelementProp_2D::get_covThreshold()
{
  if (covThreshold) {
    return covThreshold->cast2positive_or0();
  } else {
    return 1e-4;
  }
}

const tuint* FlxKLelementProp_2D::refine_single(tuint& maxtree_single, tdoublePtr& cutcells)
{
  const tuint min = (integ1l_min_level?integ1l_min_level->cast2tuintW0():3);
  maxtree_single = (integ1l_max_level?integ1l_max_level->cast2tuintW0():9);
  return refine_mesh(min,maxtree_single,cutcells);
}

const tuint* FlxKLelementProp_2D::refine_outer(tuint& maxtree_outer, tdoublePtr& cutcells)
{
  const tuint min = (outer_min_level?outer_min_level->cast2tuintW0():3);
  maxtree_outer = (outer_max_level?outer_max_level->cast2tuintW0():8);
  return refine_mesh(min,maxtree_outer,cutcells);
}

const tuint* FlxKLelementProp_2D::refine_inner_s(tuint& maxtree_inner, tdoublePtr& cutcells)
{
  const tuint min = (inner_s_min_level?inner_s_min_level->cast2tuintW0():3);
  maxtree_inner = (inner_s_max_level?inner_s_max_level->cast2tuintW0():8);
  return refine_mesh(min,maxtree_inner,cutcells);
}

const tuint* FlxKLelementProp_2D::refine_inner_d(tuint& maxtree_inner, tdoublePtr& cutcells)
{
  const tuint min = (inner_d_min_level?inner_d_min_level->cast2tuintW0():3);
  maxtree_inner = (inner_d_max_level?inner_d_max_level->cast2tuintW0():8);
  return refine_mesh(min,maxtree_inner,cutcells);
}

const tuint* FlxKLelementProp_2D::refine_err_is(tdoublePtr& cutcells)
{
  const tuint min = (err_is_min_level?err_is_min_level->cast2tuintW0():3);
  const tuint max = (err_is_max_level?err_is_max_level->cast2tuintW0():8);
  return refine_mesh(min,max,cutcells);
}

const tuint* FlxKLelementProp_2D::refine_err_id(tdoublePtr& cutcells)
{
  const tuint min = (err_id_min_level?err_id_min_level->cast2tuintW0():3);
  const tuint max = (err_id_max_level?err_id_max_level->cast2tuintW0():8);
  return refine_mesh(min,max,cutcells);
}

void FlxKLelementProp_2D::set_face(const flxFace* faceV)
{
  face = faceV;
}

FlxKLelementProp_3D::FlxKLelementProp_3D(const bool errSerious)
:boxV(NULL),pOrder(NULL),EOLE_SMP_MTH(NULL),EOLE_N(NULL),
integ1l_min_level(NULL),integ1l_max_level(NULL),outer_min_level(NULL),outer_max_level(NULL),
inner_s_min_level(NULL),inner_s_max_level(NULL),inner_d_min_level(NULL),inner_d_max_level(NULL),
err_is_min_level(NULL),err_is_max_level(NULL),err_id_min_level(NULL),err_id_max_level(NULL),cellVolumePoints(NULL)
{
  try {
    bool b=true;
    do {
      if (reader->whatIsNextString(6,true) == "porder") {
	reader->getWord("porder",false);
	reader->getChar('=',false);
	if (pOrder) {
	  std::ostringstream ssV;
	  ssV << "'porder' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_3D::FlxKLelementProp_3D_1", ssV.str() );
	}
	pOrder = new FlxMtxConstFun(true);
      } else if (reader->whatIsNextString(7,true) == "degcorr") {
	read_fun(degCorr,"degcorr");
      } else if (reader->whatIsNextString(6,true) == "degstd") { 
	read_fun(degStd,"degstd");
      } else if (reader->whatIsNextString(3,true) == "geo") {
	read_fun(geo_fun,"geo");
      } else if (reader->whatIsNextString(12,true) == "eole_smp_mth") {
	read_fun(EOLE_SMP_MTH,"eole_smp_mth");
      } else if (reader->whatIsNextString(6,true) == "eole_n") {
	reader->getWord("eole_n",false);
	reader->getChar('=',false);
	if (EOLE_N) {
	  std::ostringstream ssV;
	  ssV << "'eole_n' has aleready been defined.";
	  throw FlxException("FlxKLelementProp_3D::FlxKLelementProp_3D_2", ssV.str() );
	}
	EOLE_N = new FlxMtxConstFun(true);
      } else if (reader->whatIsNextString(17,true) == "integ1l_min_level") {
	read_fun(integ1l_min_level,"integ1l_min_level");
      } else if (reader->whatIsNextString(17,true) == "integ1l_max_level") {
	read_fun(integ1l_max_level,"integ1l_max_level");
      } else if (reader->whatIsNextString(15,true) == "outer_min_level") {
	read_fun(outer_min_level,"outer_min_level");
      } else if (reader->whatIsNextString(15,true) == "outer_max_level") {
	read_fun(outer_max_level,"outer_max_level");
      } else if (reader->whatIsNextString(20,true) == "inner_same_min_level") {
	read_fun(inner_s_min_level,"inner_same_min_level");
      } else if (reader->whatIsNextString(20,true) == "inner_same_max_level") {
	read_fun(inner_s_max_level,"inner_same_max_level");
      } else if (reader->whatIsNextString(20,true) == "inner_diff_min_level") {
	read_fun(inner_d_min_level,"inner_diff_min_level");
      } else if (reader->whatIsNextString(20,true) == "inner_diff_max_level") {
	read_fun(inner_d_max_level,"inner_diff_max_level");
      } else if (reader->whatIsNextString(16,true) == "err_is_min_level") {
	read_fun(err_is_min_level,"err_is_min_level");
      } else if (reader->whatIsNextString(16,true) == "err_is_max_level") {
	read_fun(err_is_max_level,"err_is_max_level");
      } else if (reader->whatIsNextString(16,true) == "err_id_min_level") {
	read_fun(err_id_min_level,"err_id_min_level");
      } else if (reader->whatIsNextString(16,true) == "err_id_max_level") {
	read_fun(err_id_max_level,"err_id_max_level");
      } else if (reader->whatIsNextString(12,true) == "cc_volume_pn") {
	read_fun(cellVolumePoints,"cc_volume_pn");
      } else {
	b=false;
      }
    } while (b);
  } catch (FlxException &e) {
    FLXMSG("FlxKLelementProp_3D::FlxKLelementProp_3D_1",1);
    delete_dyn();
    if (degCorr) { delete degCorr; degCorr=NULL; }
    if (degStd) { delete degStd; degStd=NULL; }
    if (geo_fun) { delete geo_fun; geo_fun=NULL; }
    throw;
  }
}

FlxKLelementProp_3D::~FlxKLelementProp_3D()
{
  delete_dyn();
}

void FlxKLelementProp_3D::delete_dyn()
{
  if (pOrder) delete pOrder;
  if (EOLE_SMP_MTH) delete EOLE_SMP_MTH;
  if (EOLE_N) delete EOLE_N;  
  if (integ1l_min_level) delete integ1l_min_level;
  if (integ1l_max_level) delete integ1l_max_level;
  if (outer_min_level) delete outer_min_level;
  if (outer_max_level) delete outer_max_level;
  if (inner_s_min_level) delete inner_s_min_level;
  if (inner_s_max_level) delete inner_s_max_level;
  if (inner_d_min_level) delete inner_d_min_level;
  if (inner_d_max_level) delete inner_d_max_level;
  if (err_is_min_level) delete err_is_min_level;
  if (err_is_max_level) delete err_is_max_level;
  if (err_id_min_level) delete err_id_min_level;
  if (err_id_max_level) delete err_id_max_level;
  if (cellVolumePoints) delete cellVolumePoints;
}

const tuint* FlxKLelementProp_3D::refine_mesh(const tuint min_level, const tuint max_level, tdoublePtr& cutcells)
{
  std::vector<tuint> vec;
  std::vector<tdouble> ccV;
  refine_mesh_help(vec,0,min_level,max_level,flxPoint(),ccV);
  const size_t S = vec.size();
  tuint* geov = new tuint[S];
  const tuint* vecp = &vec[0];
  for (tuint i=0;i<S;++i) {
    geov[i] = vecp[i];
  }
  const tuint Ncc = ccV.size();
  if (Ncc>0) {
    cutcells = new tdouble[Ncc];
    tdouble* ccP = &ccV[0];
    for (tuint i=0;i<Ncc;++i) {
      cutcells[i] = ccP[i];
    }
  } else {
    cutcells = NULL;
  }
  return geov;
}

void FlxKLelementProp_3D::check_cell(const tdouble dhk, const flxPoint& p, bool& same, bool* gb)
{
  flxPoint pt;
  pt = p+flxPoint(-ONE*dhk,-ONE*dhk,-ONE*dhk);
    boxV->update_globalConst(pt);
    gb[0] = (geo_fun->calc()>=ZERO);
  pt = p+flxPoint(dhk,-ONE*dhk,-ONE*dhk);
    boxV->update_globalConst(pt);
    gb[1] = (geo_fun->calc()>=ZERO);
  pt = p+flxPoint(dhk,dhk,-ONE*dhk);
    boxV->update_globalConst(pt);
    gb[2] = (geo_fun->calc()>=ZERO);
  pt = p+flxPoint(-ONE*dhk,dhk,-ONE*dhk);
    boxV->update_globalConst(pt);
    gb[3] = (geo_fun->calc()>=ZERO);
  pt = p+flxPoint(-ONE*dhk,-ONE*dhk,dhk);
    boxV->update_globalConst(pt);
    gb[4] = (geo_fun->calc()>=ZERO);
  pt = p+flxPoint(dhk,-ONE*dhk,dhk);
    boxV->update_globalConst(pt);
    gb[5] = (geo_fun->calc()>=ZERO);
  pt = p+flxPoint(dhk,dhk,dhk);
    boxV->update_globalConst(pt);
    gb[6] = (geo_fun->calc()>=ZERO);
  pt = p+flxPoint(-ONE*dhk,dhk,dhk);
    boxV->update_globalConst(pt);
    gb[7] = (geo_fun->calc()>=ZERO);
  pt = p;
    boxV->update_globalConst(pt);
    gb[8] = (geo_fun->calc()>=ZERO);
  for (tuint i=1;i<9;++i) {
    if (gb[0]!=gb[i]) {
      same = false;
      break;
    }
  }
}

const tdouble FlxKLelementProp_3D::get_cellvolume(const tdouble dh, flxPoint& cm)
{
  flxPoint& p = cm;
  tuint H=0;
  boxV->update_globalConst(p);
  const tuint N = (cellVolumePoints)?cellVolumePoints->cast2tuint():30;
  const tdouble dx = dh*2.0/N;
  tdouble x=dx/2.0,y,z,sx=ZERO,sy=ZERO,sz=ZERO;
  for (tuint i=0;i<N;++i) {
    y = dx/2.0;
    for (tuint j=0;j<N;++j) {
      z = dx/2.0;
      for (tuint k=0;k<N;++k) {
	flxPoint pt = p + flxPoint(x-dh,y-dh,z-dh);
	boxV->update_globalConst(pt);
	if (geo_fun->calc()>=ZERO) {
	  ++H;
	  sx+=x;
	  sy+=y;
	  sz+=z;
	}
	z+=dx;
      }
      y+=dx;
    }
    x+=dx;
  }
  if (H>0) {
    cm.id_fast(0) = p.id_fast(0)+(sx/H-dh);
    cm.id_fast(1) = p.id_fast(1)+(sy/H-dh);
    cm.id_fast(2) = p.id_fast(2)+(sz/H-dh);
  }
  return tdouble(H)/tdouble(N*N*N);
}

void FlxKLelementProp_3D::refine_mesh_help(std::vector< tuint >& vec, const tuint level, const tuint min_level, const tuint max_level, const flxPoint& p, std::vector< tdouble >& cutcells)
{
  const tdouble dh = 1./(pow(2.,int(level)));
  bool gb[9];
  bool same=true;
  if (geo_fun) {
    const tdouble dhk = 0.999*dh;
    check_cell(dhk,p,same,gb);
  } else {
    for (tuint i=0;i<9;++i) gb[i] = true;
  }
  if ((min_level>level || !same) && max_level>level) {
    flxPoint pt;
    const tdouble dhh = dh/2.0;
    vec.push_back(0);		// parent cell
    pt = flxPoint(p)+flxPoint(-ONE*dhh,-ONE*dhh,-ONE*dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
    pt = flxPoint(p)+flxPoint(dhh,-ONE*dhh,-ONE*dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
    pt = flxPoint(p)+flxPoint(dhh,dhh,-ONE*dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
    pt = flxPoint(p)+flxPoint(-ONE*dhh,dhh,-ONE*dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
    pt = flxPoint(p)+flxPoint(-ONE*dhh,-ONE*dhh,dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
    pt = flxPoint(p)+flxPoint(dhh,-ONE*dhh,dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
    pt = flxPoint(p)+flxPoint(dhh,dhh,dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
    pt = flxPoint(p)+flxPoint(-ONE*dhh,dhh,dhh);
      refine_mesh_help(vec,level+1,min_level,max_level,pt,cutcells);
  } else {
    if (same) {
      if (gb[0]) {
	vec.push_back(3);	// full geometry
      } else {
	vec.push_back(1);	// no geometry
      }
    } else {
      flxPoint cm = p;
      const tdouble V = get_cellvolume(dh,cm);
      if (V<=GlobalVar.TOL()) vec.push_back(1);	// no geometry
      else if (ONE-V<=GlobalVar.TOL()) vec.push_back(3);	// full geometry
      else {
	vec.push_back(2);		// mixed cell
	// add center's
	  cutcells.push_back(cm.get_x());
	  cutcells.push_back(cm.get_y());
	  cutcells.push_back(cm.get_z());
	cutcells.push_back(V);
      }
    }
  }
}

void FlxKLelementProp_3D::get_pOrder(tuint* ref)
{
  if (pOrder) {
    const iVec vec = ConstMtxBox->get_Vec_cast2tuint(pOrder->eval(),true);
    if (vec.size()!=3) {
      std::ostringstream ssV;
      ssV << "The dimension of the vector has to be '3'.";
      throw FlxException("FlxKLelementProp_3D::get_pOrder", ssV.str() );
    }
    ref[0] = vec[0];
    ref[1] = vec[1];
    ref[2] = vec[2];
  } else {
    ref[0] = 1;
    ref[1] = 1;
    ref[2] = 1;
  }
}

const int FlxKLelementProp_3D::get_EOLE_SMP_MTH()
{
  if (EOLE_SMP_MTH) {
    return EOLE_SMP_MTH->cast2int();
  } else {
    return 1;
  }
}

void FlxKLelementProp_3D::get_EOLE_N(const int SMP_MTH, tuint* ref)
{
  if (EOLE_N) {
    const iVec vec = ConstMtxBox->get_Vec_cast2tuint(EOLE_N->eval(),true);
    const tuint S = (SMP_MTH==1)?3:1;
    if (vec.size()!=S) {
      std::ostringstream ssV;
      ssV << "The dimension of the vector has to be '" << S << "'.";
      throw FlxException("FlxKLelementProp_3D::get_EOLE_N", ssV.str() );
    }
    for (tuint i=0;i<S;++i) {
      ref[i] = vec[i];
    }
  } else {
    if (SMP_MTH==1) {
      ref[0] = 10;
      ref[1] = 10;
      ref[2] = 10;
    } else {
      ref[0] = 1000;
    }
  }
}

const tuint* FlxKLelementProp_3D::refine_single(tuint &maxtree_single,tdoublePtr& cutcells)
{
  const tuint min = (integ1l_min_level?integ1l_min_level->cast2tuintW0():2);
  maxtree_single = (integ1l_max_level?integ1l_max_level->cast2tuintW0():7);
  return refine_mesh(min,maxtree_single,cutcells);
}

const tuint* FlxKLelementProp_3D::refine_outer(tuint& maxtree_outer, tdoublePtr& cutcells)
{
  const tuint min = (outer_min_level?outer_min_level->cast2tuintW0():3);
  maxtree_outer = (outer_max_level?outer_max_level->cast2tuintW0():6);
  return refine_mesh(min,maxtree_outer,cutcells);
}

const tuint* FlxKLelementProp_3D::refine_inner_s(tuint& maxtree_inner, tdoublePtr& cutcells)
{
  const tuint min = (inner_s_min_level?inner_s_min_level->cast2tuintW0():2);
  maxtree_inner = (inner_s_max_level?inner_s_max_level->cast2tuintW0():6);
  return refine_mesh(min,maxtree_inner,cutcells);
}

const tuint* FlxKLelementProp_3D::refine_err_is(tdoublePtr& cutcells)
{
  const tuint min = (err_is_min_level?err_is_min_level->cast2tuintW0():2);
  const tuint max = (err_is_max_level?err_is_max_level->cast2tuintW0():6);
  return refine_mesh(min,max,cutcells);
}

void FlxKLelementProp_3D::set_box(const flxBox* boxVv)
{
  boxV = boxVv;
}

