#
# This file is part of Rheolef.
#
# Copyright (C) 2000-2009 Pierre Saramito 
#
# Rheolef 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 2 of the License, or
# (at your option) any later version.
#
# Rheolef 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 Rheolef; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# -------------------------------------------------------------------------

Demo:
-----
	make
	./P2_tst | more

Objectif :
---------
	- possibilite de bases par calcul formel (degre bas)
	  ou directement en numerique (spectral)
	- ginac ne doit pas etre necessaire dans la distribution :
	  generation du code numerique
	- possibilite de charger des modules independament

First approach
--------------
basic_basis:
	basic_basis : common to basis and p_basis
p_basis:
	add polynomial computations using ginac
	generates some code for basis

generic_basis:
	pure virtual base class for basis_XXX
basis_XXX:
	- a part is automaticaly generated by poly_basis
	- derives from generic_basis
		XXX.h : the basis header
		XXX.cc XXX.so : the module
	  module "XXX.so" returns an initialized
	  pointer to generic_basis:
	  	generic_basis* make_basis_XXX();
basis:
	a pointer to basis_XXX with a constructor
	that takes "XXX" string as argument : load
	module and call initializer.

Inconvenient :
--------------
	- one pointer in basis
	- another for each virtual func call
	- what about Pk spectral element ?
	  	generic_basis* make_basis_XXX(int k);
          where no formal calculus is performed.
Second approach
---------------
	- some code from 
		poly_basis XXX ("XXX");
		XXX('t').add_node(0,0);
		...
		XXX('t').add_poly("1+x+y");
		...
		XXX.cxx_code();

	  should be reused in basis_XXX :
	    XXX.idof(element_type, i_dof_local)
	    XXX.ndof(element_type, i_dof_local)

	  => defines instead a derived class poly_basis_XXX :

		class basic_XXX : basic_basis {
		  ...
	    	   int idof(element_type, i_dof_local) { CODE }
	    	   int ndof(element_type, i_dof_local) { CODE }
		};
	  Then poly_basis_XXX derives from poly_basis and basic_XXX and add the
	  polynoms :

		class poly_basis_XXX : basic_XXX, poly_basis {
		...
		};
		poly_basis_XXX XXX ("XXX");
		XXX('t').add_node(0,0);
		...
		XXX('t').add_poly("1+x+y");
		...
		XXX.cxx_code();
	  
	  Then basis_XXX derives from generic_basis and basic_XXX 
	  and has been generated automatically.

Inconvenient:
-------------
	  - complicated class imbrication
	  - for Pk elements, may precompile all supported k.
	     big code for high k

Third approach
--------------
	- another approach is to build a general loop for 
	  the computation of elementary matrices based on
	  the transformation, the basis and its gradient at
	  quadrature nodes, without any reference to
	  formal calculus : all is numeric.
	  This is the approach for Pk spectral elements :
	  - basis and its derivatives are build explicitely
	  - there are pre-evaluated at quadrature points, one
	    time for all at quadrature points on reference elt.
	  - the transformation is evaluated for each element 
	    at quadrature points.
Inconvenient :
-------------
	risk to make errors in computation for new basis, derivation
	operators and elementary matrices : bubble, etc...
	=> code complication, limit new elements testing


Compromission and flexibility :
	generates automatically some basis and writes
	explicitely some others :

	  class basic_Sk : basic_basis {
	  	   int k;
		  ...
	    	   int idof(element_type, i_dof_local) { CODE }
	    	   int ndof(element_type, i_dof_local) { CODE }
		   - defines a transformation
	  };
	  class basis_Sk : generic_basis, basic_Sk {
	    	- explicit code for basis evaluation
		  and its gradient at any point
		- method for evaluation at some quadrature point list
	  };
	  generic_basis* make_basis_Sk(int k);

	One can skip the basic_Sk class and write directly :

	  class basis_Sk : generic_basis, basic_basis {
	  	- all code grouped in one class
	  };
	elementary matrix :
	  - choose a quadrature formulae
	  - evaluates basis or its gradient
	  - apply transformation, if necessary

Synthesis :
-----------
	- compatible with existing formal calculus approach
	- compatible with existing elementary matrices
	- flexible enough for spectral Pk elements
	- efficient for low orders : precomputed forms

Question :
-----------
	- How to generate Pk discontinuous elements with
	  dofs at external boundary, for discont galerkin ?
	- ndof() and idof() are different
	  some forms are identical : (div(v), q)_K
	  some others not :          (v.n, q)_S
	- Avoid C++ source code redondancy : nodes, polys...
	  derivation of class :
	  
	    class basic_P1gd : basic_P1d {
	    	   int idof(element_type, i_dof_local) { NEW CODE }
	    	   int ndof(element_type, i_dof_local) { NEW CODE }
	    };
	    class poly_basis_P1gd : basic_P1gd, poly_basis_P1d {
	    	   same code for poly
	    };

	- How to handle P2 transformation ? Pk transf ?
		F(hat_x_i) = sum_j c_ij pj(hat_x_i) = a_ik	
			i=1..d
			k=1..dim(Pk)
		for fixed i, linear system of size dim(Pk)
		=> inversion for each element
		   factorize (pj(hat_x_i)) one time for all as LU
	
	- How to handle RT and Nedelec basis ?
	  notion of momentum, no located dofs
	  lagrange interpolation is more complex :
	  uses quadrature formulae on edges, faces, etc...
	  see deal II or others codes... 

	- basis = space_reference_element
  	  geo_element = reference_element apres transformation,
    		mais la transformation fait reference a la CAO,
    	        actuellement lineaire
  	  space_element = basis apres transformation,
    		mais la transformation est approchee par un degree k
    		compatible avec l'approx Pk de la base

Recapitulatif
-------------
	class basic_basis { outils communs }
	class symbolic_basis { manips ginac }
	class numeric_basis { fcts virtuelles }
	class basis { pointeur sur generic_basis }

      1) generation symbolique
         ---------------------
	class basic_XXX : basic_basis { ... } ;
	 = sous classe commune symbolique et numerique
        class symbolic_basis_XXX : basic_XXX, symbolic_basis { } ;
	 => action de generation du code de la classe numerique
	class basis_XXX : basic_XXX, virtual numeric_basis { ...}
      
      2) ecriture directe
         ----------------
	class basis_XXX : basic_basis, virtual numeric_basis { ...}

---------------------------
annexe : hermite H3 element
---------------------------
* BUG:
   Il faut prendre en compte la dérivée de la fonction de Piola pour évaluer u_h sur un élément.
   Explication :
   Soient les fonctions de base de Hermite ê_i(ŷ) sur ŷ dans [0,1]. 
   On a dê0/dy(0) = 0 et dê1/dŷ(0) = 0
        dê2/dy(0) = 1 et dê3/dŷ(0) = 0

   uh est representé par le vecteur ( u0_0 ... u0_{n-1} u1_0 ... u1_{n-1} )
   avec u0_i = u(i) et u1_i = u'_i

   On écrit sur [y_i, y_{i+1}], uh(y) = u0_i ê0(F(y)) + u0_{i+1} ê1(F(y)) + C ( u1_i ê2(F(y)) + u1_{i+1} ê3(F(y)) )

   en y_i, on a donc u'_i = duh/dy (y_i) = C u1_i de2/dy (y_i) = C u1_i dF^{-1}/dy dê2/dŷ (y_i) 

   donc C = dF/dy ≠ 1 ! (h pour F linéaire)

* TODO:
   * field(Vh, 1) must only set 0-order dof to 1.
   * interpolate ?
   * block must distinguish 0-order and first order (for now it blocks only 1st order on endpoints)



   f0(x) = 1+2*x**3-3*x**2
   f1(x) = -2*x**3+3*x**2
   f2(x) = x**3-2*x**2+x
   f3(x) = x**3-x**2

