/*******************************************************************************
 *
 * ALBERTA:  an Adaptive multi Level finite element toolbox using           
 *           Bisectioning refinement and Error control by Residual          
 *           Techniques for scientific Applications                         
 *                                                                          
 * www.alberta-fem.de                                                       
 *                                                                          
 * file:     assemble_bndry.h                                               
 *                                                                          
 * description: assemblage of boundary integral contributions               
 *                                                                          
 *******************************************************************************
 *                                                                          
 * This file's authors: Claus-Justus Heine                                  
 *                      Abteilung fuer Angewandte Mathematik
 *                      Universitaet Freiburg
 *                      Hermann-Herder-Str. 10
 *                      79104 Freiburg, Germany                             
 *                                                                          
 *  (c) by C.-J. Heine (2006-2009)                                          
 *                                                                          
 ******************************************************************************/

#ifndef _ALBERTA_ASSEMBLE_BNDRY_H_
#define _ALBERTA_ASSEMBLE_BNDRY_H_

#include "alberta.h"

typedef void (*AI_BNDRY_EL_MAT_FCT)(const EL_INFO *el_info,
				    const void *fill_info,
				    EL_MATRIX *el_mat);

typedef struct bndry_fill_info BNDRY_FILL_INFO;
struct bndry_fill_info 
{
  BNDRY_OPERATOR_INFO  op_info;

  /* the block-matrix type of the underlying integral kernel */
  MATENT_TYPE          krn_blk_type;
  
  DBL_LIST_NODE row_chain;
  DBL_LIST_NODE col_chain;

  const WALL_QUAD_FAST *row_wquad_fast[3]; /* rows, i.e. range */
  const WALL_QUAD_FAST *col_wquad_fast[3]; /* cols, i.e. domain */

  /* if op_info->tangential == true, then we need to cache the trace
   * mapping in order to assemble jump-contributions correctly
   * (assemble_neigh.c). The column trace-map does not need caching,
   * because potential per-element initializers are called on the
   * neighbour element before calling the element function.
   */
  const int *row_fcts_trace_map[N_WALLS_MAX];
  int n_trace_row_fcts[N_WALLS_MAX];

  /* The space of test-functions is always taken on the current
   * element, but during assembling of jump contributions the space of
   * ansatz functions has to be taken on the neighbour.
   */
  const QUAD_FAST      *col_quad_fast[3];
  const EL             *cur_el;
  const EL_INFO        *cur_el_info;

  EL_MATRIX            *el_mat;
  /* temporary el-mat for vector valued bas-fcts. */
  void                 *scl_el_mat;
  int                  n_row_max, n_col_max;

  PARAMETRIC           *parametric;

  const AI_BNDRY_EL_MAT_FCT *el_matrix_fct;
  const EL_MATRIX_FCT       *neigh_el_mat_fcts;

  void (*dflt_second_order[N_WALLS_MAX])(const EL_INFO *el_info,
					 const BNDRY_FILL_INFO *info,
					 void **el_mat);
  void (*dflt_first_order[N_WALLS_MAX])(const EL_INFO *el_info,
					const BNDRY_FILL_INFO *info,
					void **el_mat);
  void (*dflt_zero_order[N_WALLS_MAX])(const EL_INFO *el_info,
				       const BNDRY_FILL_INFO *info,
				       void **el_mat);
  void (*fast_second_order[N_WALLS_MAX])(const EL_INFO *el_info,
					 const BNDRY_FILL_INFO *info,
					 void **el_mat);
  void (*fast_first_order[N_WALLS_MAX])(const EL_INFO *el_info,
					const BNDRY_FILL_INFO *info,
					void **el_mat);
  void (*fast_zero_order[N_WALLS_MAX])(const EL_INFO *el_info,
				       const BNDRY_FILL_INFO *info,
				       void **el_mat);

  BNDRY_FILL_INFO *next;
};

typedef void (*AI_EL_WALL_FCT)(const EL_INFO *el_info,
			       const BNDRY_FILL_INFO *fill_info,
			       void **el_mat);

/* for computing the offset into the el_wall_fcts table */
#define WALL_FCT_MIX (1 << 0)
#define WALL_FCT_SYM (1 << 1)
#define WALL_FCT_TAN (1 << 2)
#define WALL_FCT_PWC (1 << 3)

/* Assembling over walls on a given element. */
extern AI_EL_WALL_FCT (*SS_el_wall_fcts[])[N_WALLS_MAX][5][16];
#if VECTOR_BASIS_FUNCTIONS
extern AI_EL_WALL_FCT (*SV_el_wall_fcts[])[N_WALLS_MAX][5][16];
extern AI_EL_WALL_FCT (*VS_el_wall_fcts[])[N_WALLS_MAX][5][16];
extern AI_EL_WALL_FCT (*CV_el_wall_fcts[])[N_WALLS_MAX][5][16];
extern AI_EL_WALL_FCT (*VC_el_wall_fcts[])[N_WALLS_MAX][5][16];
extern AI_EL_WALL_FCT (*VV_el_wall_fcts[])[N_WALLS_MAX][5][16];
#endif

extern AI_EL_WALL_FCT
(**_AI_el_wall_fcts[N_OP_BLOCK_TYPES])[N_WALLS_MAX][5][16];

extern AI_BNDRY_EL_MAT_FCT SS_el_mat_fct_table[256][N_WALLS_MAX];
#if VECTOR_BASIS_FUNCTIONS
extern AI_BNDRY_EL_MAT_FCT SV_el_mat_fct_table[256][N_WALLS_MAX];
extern AI_BNDRY_EL_MAT_FCT VS_el_mat_fct_table[256][N_WALLS_MAX];
extern AI_BNDRY_EL_MAT_FCT CV_el_mat_fct_table[256][N_WALLS_MAX];
extern AI_BNDRY_EL_MAT_FCT VC_el_mat_fct_table[256][N_WALLS_MAX];
extern AI_BNDRY_EL_MAT_FCT VV_el_mat_fct_table[256][N_WALLS_MAX];
#endif

extern BNDRY_FILL_INFO *AI_get_bndry_fill_info(const BNDRY_OPERATOR_INFO *oinfo,
					       MATENT_TYPE kern_blk_type);

/* Same for assembling jumps over walls (e.g. for DG) */
extern EL_MATRIX_FCT SS_neigh_el_mat_fct_table[256][N_WALLS_MAX];
#if VECTOR_BASIS_FUNCTIONS
extern EL_MATRIX_FCT SV_neigh_el_mat_fct_table[256][N_WALLS_MAX];
extern EL_MATRIX_FCT VS_neigh_el_mat_fct_table[256][N_WALLS_MAX];
extern EL_MATRIX_FCT CV_neigh_el_mat_fct_table[256][N_WALLS_MAX];
extern EL_MATRIX_FCT VC_neigh_el_mat_fct_table[256][N_WALLS_MAX];
extern EL_MATRIX_FCT VV_neigh_el_mat_fct_table[256][N_WALLS_MAX];
#endif

extern BNDRY_FILL_INFO *AI_get_neigh_fill_info(const BNDRY_OPERATOR_INFO *oinfo,
					       MATENT_TYPE kern_blk_type);

#endif

