1 /**@file
2  *
3  * An obscure basis-function set, which lives on the master-elements
4  * of a given trace-mesh, e.g. to augment a given finite element space
5  * with trace-bubbles and the like.
6  *
7  * Mmmh. To complicated. Abandoned in favour of a bulk-trace-bubble.
8  *
9  *      author:  Claus-Justus Heine
10  *               Abteilung fuer Angewandte Mathematik
11  *               Albert-Ludwigs-Universitaet Freiburg
12  *               Hermann-Herder-Str. 10
13  *               79104 Freiburg i.Br.
14  *               Germany
15  *               claus@mathematik.uni-freiburg.de
16  *
17  * Copyright (C) by Claus-Justus Heine (2008).
18  *
19  */
20 
21 #if HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24 
25 #include <alberta.h>
26 
27 #include "albas.h"
28 
29 typedef struct trace_bulk_data
30 {
31   const EL        *cur_el;
32   const EL_INFO   *cur_el_info;
33   int             cur_wall;
34   const EL        *cur_tr_el;
35   INIT_EL_TAG_CTX tag_ctx;     /**< Tag context for caching purposes. */
36   MESH            *trace_mesh; /**< Out dedicated trace mesh. */
37   const BAS_FCTS  *bulk_bfcts; /**< The local basis function set in the bulk.*/
38   INIT_EL_TAG     bulk_tag;
39   const int       *trace_dof_map;
40   EL_BNDRY_VEC    *bndry_loc;
41   EL_REAL_VEC_D   *ipol_dow_loc;
42   EL_REAL_VEC     *ipol_loc;
43   EL_REAL_D_VEC   *ipol_d_loc;
44   strucbult bfcts {
45     BAS_FCT       *phi;
46     GRD_BAS_FCT   *grd_phi;
47     D2_BAS_FCT    *D2_phi;
48     BAS_FCT_D     *phi_d;
49     GRD_BAS_FCT_D *grd_phi_d;
50     D2_BAS_FCT_D  *D2_phi_d;
51   } bfcts[N_WALLS_MAX];
52   bool dir_pw_const;
53 } TB_DATA;
54 
tb_phi(const REAL_B lambda,const BAS_FCTS * self,int nr)55 static REAL tb_phi(const REAL_B lambda, const BAS_FCTS *self, int nr)
56 {
57   TB_DATA *data = (TB_DATA *)self->ext_data;
58 
59   return PHI(data->bulk_bfcts, nr, lambda);
60 }
61 
tb_grd_phi(const REAL_B lambda,const BAS_FCTS * self,int nr)62 static const REAL *tb_grd_phi(const REAL_B lambda, const BAS_FCTS *self, int nr)
63 {
64   TB_DATA *data = (TB_DATA *)self->ext_data;
65 
66   return GRD_PHI(data->bulk_bfcts, nr, lambda);
67 }
68 
69 static
tb_D2_phi(const REAL_B lambda,const BAS_FCTS * self,int nr)70 const REAL_B *tb_D2_phi(const REAL_B lambda, const BAS_FCTS *self, int nr)
71 {
72   TB_DATA *data = (TB_DATA *)self->ext_data;
73 
74   return D2_PHI(data->bulk_bfcts, nr, lambda);
75 }
76 
tb_phi_d(const REAL_B lambda,const BAS_FCTS * self,int nr)77 static const REAL *tb_phi_d(const REAL_B lambda, const BAS_FCTS *self, int nr)
78 {
79   TB_DATA *data = (TB_DATA *)self->ext_data;
80 
81   return PHI_D(data->bulk_bfcts, nr, lambda);
82 }
83 
84 static
tb_grd_phi_d(const REAL_B lambda,const BAS_FCTS * self,int nr)85 const REAL_B *tb_grd_phi_d(const REAL_B lambda, const BAS_FCTS *self, int nr)
86 {
87   TB_DATA *data = (TB_DATA *)self->ext_data;
88 
89   return GRD_PHI_D(data->bulk_bfcts, nr, lambda);
90 }
91 
92 static
tb_D2_phi_d(const REAL_B lambda,const BAS_FCTS * self,int nr)93 const REAL_BB *tb_D2_phi_d(const REAL_B lambda, const BAS_FCTS *self, int nr)
94 {
95   TB_DATA *data = (TB_DATA *)self->ext_data;
96 
97   return D2_PHI_D(data->bulk_bfcts, nr, lambda);
98 }
99 
100 #ifdef DEFUN_PHI
101 # undef DEFUN_PHI
102 #endif
103 #define DEFUN_PHI(nr)							\
104   static REAL tb_phi_##nr(const REAL_B lambda, const BAS_FCTS *self)	\
105   {									\
106     return PHI(self, nr, lambda);					\
107   }									\
108   static								\
109   const REAL *tb_grd_phi_##nr(const REAL_B lambda, const BAS_FCTS *self) \
110   {									\
111     return GRD_PHI(self, nr, lambda);					\
112   }									\
113   static								\
114   const REAL_B *tb_D2_phi_##nr(const REAL_B lambda, const BAS_FCTS *self) \
115   {									\
116     return D2_PHI(self, nr, lambda);					\
117   }									\
118   static const REAL *tb_phi_d_##nr(const REAL_B lambda, const BAS_FCTS *self) \
119   {									\
120     return PHI_D(self, nr, lambda);					\
121   }									\
122   static								\
123   const REAL_B *tb_grd_phi_d_##nr(const REAL_B lambda, const BAS_FCTS *self) \
124   {									\
125     return GRD_PHI_D(self, nr, lambda);					\
126   }									\
127   static								\
128   const REAL_BB *tb_D2_phi_d_##nr(const REAL_B lambda, const BAS_FCTS *self) \
129   {									\
130     return D2_PHI_D(self, nr, lambda);					\
131   }									\
132   struct _AI_semicolon_dummy
133 
134 DEFUN_PHI(0);
135 DEFUN_PHI(1);
136 DEFUN_PHI(2);
137 DEFUN_PHI(3);
138 DEFUN_PHI(4);
139 DEFUN_PHI(5);
140 DEFUN_PHI(6);
141 DEFUN_PHI(7);
142 DEFUN_PHI(8);
143 DEFUN_PHI(9);
144 
145 DEFUN_PHI(10);
146 DEFUN_PHI(11);
147 DEFUN_PHI(12);
148 DEFUN_PHI(13);
149 DEFUN_PHI(14);
150 DEFUN_PHI(15);
151 DEFUN_PHI(16);
152 DEFUN_PHI(17);
153 DEFUN_PHI(18);
154 DEFUN_PHI(19);
155 
156 DEFUN_PHI(20);
157 DEFUN_PHI(21);
158 DEFUN_PHI(22);
159 DEFUN_PHI(23);
160 DEFUN_PHI(24);
161 DEFUN_PHI(25);
162 DEFUN_PHI(26);
163 DEFUN_PHI(27);
164 DEFUN_PHI(28);
165 DEFUN_PHI(29);
166 
167 DEFUN_PHI(30);
168 DEFUN_PHI(31);
169 DEFUN_PHI(32);
170 DEFUN_PHI(33);
171 DEFUN_PHI(34);
172 DEFUN_PHI(35);
173 DEFUN_PHI(36);
174 DEFUN_PHI(37);
175 DEFUN_PHI(38);
176 DEFUN_PHI(39);
177 
178 DEFUN_PHI(40);
179 DEFUN_PHI(41);
180 DEFUN_PHI(42);
181 DEFUN_PHI(43);
182 DEFUN_PHI(44);
183 DEFUN_PHI(45);
184 DEFUN_PHI(46);
185 DEFUN_PHI(47);
186 DEFUN_PHI(48);
187 DEFUN_PHI(49);
188 
189 DEFUN_PHI(50);
190 DEFUN_PHI(51);
191 DEFUN_PHI(52);
192 DEFUN_PHI(53);
193 DEFUN_PHI(54);
194 DEFUN_PHI(55);
195 DEFUN_PHI(56);
196 DEFUN_PHI(57);
197 DEFUN_PHI(58);
198 DEFUN_PHI(59);
199 
200 static BAS_FCT phi_table[] = {
201   tb_phi_0, tb_phi_1, tb_phi_2, tb_phi_3, tb_phi_4,
202   tb_phi_5, tb_phi_6, tb_phi_7, tb_phi_8, tb_phi_9,
203 
204   tb_phi_10, tb_phi_11, tb_phi_12, tb_phi_13, tb_phi_14,
205   tb_phi_15, tb_phi_16, tb_phi_17, tb_phi_18, tb_phi_19,
206 
207   tb_phi_20, tb_phi_21, tb_phi_22, tb_phi_23, tb_phi_24,
208   tb_phi_25, tb_phi_26, tb_phi_27, tb_phi_28, tb_phi_29,
209 
210   tb_phi_30, tb_phi_31, tb_phi_32, tb_phi_33, tb_phi_34,
211   tb_phi_35, tb_phi_36, tb_phi_37, tb_phi_38, tb_phi_39,
212 
213   tb_phi_40, tb_phi_41, tb_phi_42, tb_phi_43, tb_phi_44,
214   tb_phi_45, tb_phi_46, tb_phi_47, tb_phi_48, tb_phi_49,
215 
216   tb_phi_50, tb_phi_51, tb_phi_52, tb_phi_53, tb_phi_54,
217   tb_phi_55, tb_phi_56, tb_phi_57, tb_phi_58, tb_phi_59,
218 };
219 
220 static GRD_BAS_FCT grd_phi_table[] = {
221   tb_grd_phi_0, tb_grd_phi_1, tb_grd_phi_2, tb_grd_phi_3, tb_grd_phi_4,
222   tb_grd_phi_5, tb_grd_phi_6, tb_grd_phi_7, tb_grd_phi_8, tb_grd_phi_9,
223 
224   tb_grd_phi_10, tb_grd_phi_11, tb_grd_phi_12, tb_grd_phi_13, tb_grd_phi_14,
225   tb_grd_phi_15, tb_grd_phi_16, tb_grd_phi_17, tb_grd_phi_18, tb_grd_phi_19,
226 
227   tb_grd_phi_20, tb_grd_phi_21, tb_grd_phi_22, tb_grd_phi_23, tb_grd_phi_24,
228   tb_grd_phi_25, tb_grd_phi_26, tb_grd_phi_27, tb_grd_phi_28, tb_grd_phi_29,
229 
230   tb_grd_phi_30, tb_grd_phi_31, tb_grd_phi_32, tb_grd_phi_33, tb_grd_phi_34,
231   tb_grd_phi_35, tb_grd_phi_36, tb_grd_phi_37, tb_grd_phi_38, tb_grd_phi_39,
232 
233   tb_grd_phi_40, tb_grd_phi_41, tb_grd_phi_42, tb_grd_phi_43, tb_grd_phi_44,
234   tb_grd_phi_45, tb_grd_phi_46, tb_grd_phi_47, tb_grd_phi_48, tb_grd_phi_49,
235 
236   tb_grd_phi_50, tb_grd_phi_51, tb_grd_phi_52, tb_grd_phi_53, tb_grd_phi_54,
237   tb_grd_phi_55, tb_grd_phi_56, tb_grd_phi_57, tb_grd_phi_58, tb_grd_phi_59,
238 };
239 
240 static D2_BAS_FCT D2_phi_table[] = {
241   tb_D2_phi_0, tb_D2_phi_1, tb_D2_phi_2, tb_D2_phi_3, tb_D2_phi_4,
242   tb_D2_phi_5, tb_D2_phi_6, tb_D2_phi_7, tb_D2_phi_8, tb_D2_phi_9,
243 
244   tb_D2_phi_10, tb_D2_phi_11, tb_D2_phi_12, tb_D2_phi_13, tb_D2_phi_14,
245   tb_D2_phi_15, tb_D2_phi_16, tb_D2_phi_17, tb_D2_phi_18, tb_D2_phi_19,
246 
247   tb_D2_phi_20, tb_D2_phi_21, tb_D2_phi_22, tb_D2_phi_23, tb_D2_phi_24,
248   tb_D2_phi_25, tb_D2_phi_26, tb_D2_phi_27, tb_D2_phi_28, tb_D2_phi_29,
249 
250   tb_D2_phi_30, tb_D2_phi_31, tb_D2_phi_32, tb_D2_phi_33, tb_D2_phi_34,
251   tb_D2_phi_35, tb_D2_phi_36, tb_D2_phi_37, tb_D2_phi_38, tb_D2_phi_39,
252 
253   tb_D2_phi_40, tb_D2_phi_41, tb_D2_phi_42, tb_D2_phi_43, tb_D2_phi_44,
254   tb_D2_phi_45, tb_D2_phi_46, tb_D2_phi_47, tb_D2_phi_48, tb_D2_phi_49,
255 
256   tb_D2_phi_50, tb_D2_phi_51, tb_D2_phi_52, tb_D2_phi_53, tb_D2_phi_54,
257   tb_D2_phi_55, tb_D2_phi_56, tb_D2_phi_57, tb_D2_phi_58, tb_D2_phi_59,
258 };
259 
260 static BAS_FCT_D phi_d_table[] = {
261   tb_phi_d_0, tb_phi_d_1, tb_phi_d_2, tb_phi_d_3, tb_phi_d_4,
262   tb_phi_d_5, tb_phi_d_6, tb_phi_d_7, tb_phi_d_8, tb_phi_d_9,
263 
264   tb_phi_d_10, tb_phi_d_11, tb_phi_d_12, tb_phi_d_13, tb_phi_d_14,
265   tb_phi_d_15, tb_phi_d_16, tb_phi_d_17, tb_phi_d_18, tb_phi_d_19,
266 
267   tb_phi_d_20, tb_phi_d_21, tb_phi_d_22, tb_phi_d_23, tb_phi_d_24,
268   tb_phi_d_25, tb_phi_d_26, tb_phi_d_27, tb_phi_d_28, tb_phi_d_29,
269 
270   tb_phi_d_30, tb_phi_d_31, tb_phi_d_32, tb_phi_d_33, tb_phi_d_34,
271   tb_phi_d_35, tb_phi_d_36, tb_phi_d_37, tb_phi_d_38, tb_phi_d_39,
272 
273   tb_phi_d_40, tb_phi_d_41, tb_phi_d_42, tb_phi_d_43, tb_phi_d_44,
274   tb_phi_d_45, tb_phi_d_46, tb_phi_d_47, tb_phi_d_48, tb_phi_d_49,
275 
276   tb_phi_d_50, tb_phi_d_51, tb_phi_d_52, tb_phi_d_53, tb_phi_d_54,
277   tb_phi_d_55, tb_phi_d_56, tb_phi_d_57, tb_phi_d_58, tb_phi_d_59,
278 };
279 
280 static GRD_BAS_FCT_D grd_phi_d_table[] = {
281   tb_grd_phi_d_0, tb_grd_phi_d_1, tb_grd_phi_d_2, tb_grd_phi_d_3,
282   tb_grd_phi_d_4,
283   tb_grd_phi_d_5, tb_grd_phi_d_6, tb_grd_phi_d_7, tb_grd_phi_d_8,
284   tb_grd_phi_d_9,
285 
286   tb_grd_phi_d_10, tb_grd_phi_d_11, tb_grd_phi_d_12, tb_grd_phi_d_13,
287   tb_grd_phi_d_14,
288   tb_grd_phi_d_15, tb_grd_phi_d_16, tb_grd_phi_d_17, tb_grd_phi_d_18,
289   tb_grd_phi_d_19,
290 
291   tb_grd_phi_d_20, tb_grd_phi_d_21, tb_grd_phi_d_22, tb_grd_phi_d_23,
292   tb_grd_phi_d_24,
293   tb_grd_phi_d_25, tb_grd_phi_d_26, tb_grd_phi_d_27, tb_grd_phi_d_28,
294   tb_grd_phi_d_29,
295 
296   tb_grd_phi_d_30, tb_grd_phi_d_31, tb_grd_phi_d_32, tb_grd_phi_d_33,
297   tb_grd_phi_d_34,
298   tb_grd_phi_d_35, tb_grd_phi_d_36, tb_grd_phi_d_37, tb_grd_phi_d_38,
299   tb_grd_phi_d_39,
300 
301   tb_grd_phi_d_40, tb_grd_phi_d_41, tb_grd_phi_d_42, tb_grd_phi_d_43,
302   tb_grd_phi_d_44,
303   tb_grd_phi_d_45, tb_grd_phi_d_46, tb_grd_phi_d_47, tb_grd_phi_d_48,
304   tb_grd_phi_d_49,
305 
306   tb_grd_phi_d_50, tb_grd_phi_d_51, tb_grd_phi_d_52, tb_grd_phi_d_53,
307   tb_grd_phi_d_54,
308   tb_grd_phi_d_55, tb_grd_phi_d_56, tb_grd_phi_d_57, tb_grd_phi_d_58,
309   tb_grd_phi_d_59,
310 };
311 
312 static D2_BAS_FCT_D D2_phi_d_table[] = {
313   tb_D2_phi_d_0, tb_D2_phi_d_1, tb_D2_phi_d_2, tb_D2_phi_d_3,
314   tb_D2_phi_d_4,
315   tb_D2_phi_d_5, tb_D2_phi_d_6, tb_D2_phi_d_7, tb_D2_phi_d_8,
316   tb_D2_phi_d_9,
317 
318   tb_D2_phi_d_10, tb_D2_phi_d_11, tb_D2_phi_d_12, tb_D2_phi_d_13,
319   tb_D2_phi_d_14,
320   tb_D2_phi_d_15, tb_D2_phi_d_16, tb_D2_phi_d_17, tb_D2_phi_d_18,
321   tb_D2_phi_d_19,
322 
323   tb_D2_phi_d_20, tb_D2_phi_d_21, tb_D2_phi_d_22, tb_D2_phi_d_23,
324   tb_D2_phi_d_24,
325   tb_D2_phi_d_25, tb_D2_phi_d_26, tb_D2_phi_d_27, tb_D2_phi_d_28,
326   tb_D2_phi_d_29,
327 
328   tb_D2_phi_d_30, tb_D2_phi_d_31, tb_D2_phi_d_32, tb_D2_phi_d_33,
329   tb_D2_phi_d_34,
330   tb_D2_phi_d_35, tb_D2_phi_d_36, tb_D2_phi_d_37, tb_D2_phi_d_38,
331   tb_D2_phi_d_39,
332 
333   tb_D2_phi_d_40, tb_D2_phi_d_41, tb_D2_phi_d_42, tb_D2_phi_d_43,
334   tb_D2_phi_d_44,
335   tb_D2_phi_d_45, tb_D2_phi_d_46, tb_D2_phi_d_47, tb_D2_phi_d_48,
336   tb_D2_phi_d_49,
337 
338   tb_D2_phi_d_50, tb_D2_phi_d_51, tb_D2_phi_d_52, tb_D2_phi_d_53,
339   tb_D2_phi_d_54,
340   tb_D2_phi_d_55, tb_D2_phi_d_56, tb_D2_phi_d_57, tb_D2_phi_d_58,
341   tb_D2_phi_d_59,
342 };
343 
344 static const int id_map[] = {
345   0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
346   10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
347   20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
348   30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
349   40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
350   50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
351 };
352 
353 static
fill_jump_tables(struct bfcts * jump_table,const int trace_map[],int n_trace_fcts)354 void fill_jump_tables(struct bfcts *jump_table,
355 		      const int trace_map[],
356 		      int n_trace_fcts)
357 {
358   int i;
359 
360   if (jump_table->phi) {
361     for (i = 0; i < n_trace_fcts; i++) {
362       jump_table->phi[i] = phi_table[trace_map[i]];
363     }
364   }
365   if (jump_table->grd_phi) {
366     for (i = 0; i < n_trace_fcts; i++) {
367       jump_table->grd_phi[i] = grd_phi_table[trace_map[i]];
368     }
369   }
370   if (jump_table->D2_phi) {
371     for (i = 0; i < n_trace_fcts; i++) {
372       jump_table->D2_phi[i] = D2_phi_table[trace_map[i]];
373     }
374   }
375   if (jump_table->phi_d) {
376     for (i = 0; i < n_trace_fcts; i++) {
377       jump_table->phi_d[i] = phi_d_table[trace_map[i]];
378     }
379   }
380   if (jump_table->grd_phi_d) {
381     for (i = 0; i < n_trace_fcts; i++) {
382       jump_table->grd_phi_d[i] = grd_phi_d_table[trace_map[i]];
383     }
384   }
385   if (jump_table->D2_phi_d) {
386     for (i = 0; i < n_trace_fcts; i++) {
387       jump_table->D2_phi_d[i] = D2_phi_d_table[trace_map[i]];
388     }
389   }
390 }
391 
392 static
trace_bulk_init_element(const EL_INFO * el_info,void * thisptr)393 INIT_EL_TAG trace_bulk_init_element(const EL_INFO *el_info, void *thisptr)
394 {
395   FUNCNAME("trace_bulk_init_element");
396   BAS_FCTS *self = (BAS_FCTS *)thisptr;
397   TB_DATA *data = (TB_DATA *)self->ext_data;
398   MESH *mesh;
399   int w, dim;
400   INIT_EL_TAG bulk_tag;
401   const EL *tr_el;
402 
403   if (el_info == NULL) {
404     self->n_bas_fcts = 0;
405     self->dir_pw_const = true;
406     data->cur_el = NULL;
407     data->cur_el_info = NULL;
408     INIT_OBJECT(data->bulk_bfcts);
409     INIT_EL_TAG_CTX_DFLT(&data->tag_ctx);
410     return INIT_EL_TAG_CTX_TAG(&data->tag_ctx);
411   }
412 
413   if (data->cur_el == el_info->el && data->cur_el_info == el_info) {
414     return INIT_EL_TAG_CTX_TAG(&data->tag_ctx);
415   }
416   data->cur_el      = el_info->el;
417   data->cur_el_info = el_info;
418 
419   mesh = el_info->mesh;
420   dim = mesh->dim;
421 
422   for (w = 0; w < N_WALLS(dim); w++) {
423     int o, t;
424     if ((tr_el = get_slave_el(el_info->el, w, data->trace_mesh)) == NULL) {
425       continue;
426     }
427     bulk_tag = INIT_ELEMENT(el_info, data->bulk_bfcts);
428     TEST_EXIT(bulk_tag == INIT_EL_TAG_DFLT);
429     o = el_info->orientation < 0;
430     t = el_info->el_type > 0;
431     data->trace_dof_map = data->bulk_bfcts->trace_dof_map[t][o][w];
432     if (data->cur_wall != w || bulk_tag != data->bulk_tag) {
433       data->bndry_loc->n_components = data->bulk_bfcts->n_trace_bas_fcts[w];
434       self->phi          = data->bfcts[w].phi;
435       self->grd_phi      = data->bfcts[w].grd_phi;
436       self->d2_phi       = data->bfcts[w].d2_phi;
437       self->phi_d        = data->bfcts[w].phi_d;
438       self->grd_phi_d    = data->bfcts[w].grd_phi_d;
439       self->d2_phi_d     = data->bfcts[w].d2_phi_d;
440       data->cur_wall     = w;
441       self->dir_pw_const = data->dir_pw_const;
442       INIT_EL_TAG_CTX_UNIQ(&self->tag_ctx);
443     }
444     data->bulk_tag = bulk_tag;
445     break;
446   }
447 
448   data->tr_el = tr_el;
449 
450   return INIT_EL_TAG_CTX_TAG(&data->tag_ctx);
451 }
452 
453 static const EL_DOF_VEC *
tb_get_dof_indices(DOF * dof,const EL * el,const DOF_ADMIN * admin,const BAS_FCTGS * self)454 tb_get_dof_indices(DOF *dof,
455 		   const EL *el,
456 		   const DOF_ADMIN *admin,
457 		   const BAS_FCTGS *self)
458 {
459   TB_DATA *data = (TB_DATA *)self->ext_data;
460 
461   return GET_DOF_INDICES(
462     data->bulk_bfcts->trace_bas_fcts, data->tr_el, admin, dof);
463 }
464 
465 static const EL_BNDRY_VEC *
tb_get_bound(BNDRY_FLAGS * bound,const EL_INFO * el_info,const BAS_FCTS * self)466 tb_get_bound(BNDRY_FLAGS *bound,
467 	     const EL_INFO *el_info,
468 	     const BAS_FCTS *self)
469 {
470   TB_DATA *data = (TB_DATA *)self->ext_data;
471   BNDRY_FLAGS bndry_loc[data->bulk_bfcts->n_bas_fcts];
472   BNDRY_FLAGS *vec = bound == NULL ? data->bndry_loc->vec : bound;
473   int i;
474 
475   GET_BOUND(data->bulk_bfcts, el_info, bndry_loc);
476   for (i = 0; i < self->n_bas_fcts; i++) {
477     vec[i] = bndry_loc[data->trace_dof_map[i]];
478   }
479   return bound == NULL ? data->bndry_loc : bound;
480 }
481 
tb_interpol(EL_REAL_VEC * coeff,const EL_INFO * el_info,int wall,int n,const int * indices,LOC_FCT_AT_QP f,void * f_data,const BAS_FCTS * thisptr)482 static void tb_interpol(EL_REAL_VEC *coeff,
483 			const EL_INFO *el_info, int wall,
484 			int n, const int *indices,
485 			LOC_FCT_AT_QP f, void *f_data,
486 			const BAS_FCTS *thisptr)
487 {
488   TB_DATA *data = (TB_DATA *)self->ext_data;
489   REAL tmp_coeff[self->n_bas_fcts];
490 
491   if (wall
492 
493   if (indices) {
494     int tmp_indices[data->bulk_bfcts->n_bas_fcts];
495     memcpy(tmp_coeff, coeff->vec, self->n_bas_fcts * sizeof(REAL));
496     coeff->n_components = data->bulk_bfcts->n_bas_fcts;
497     memset(coeff->vec, 0, sizeof(REAL) * coeff->n_components);
498     for (i = 0; i < coeff->n_components; i++) {
499       coeff->vec[data->trace_dof_map[i]] = tmp_coeff[i];
500     }
501     for (i = 0; i < n; i++) {
502       tmp_indices[i] = data->trace_dof_map[indices[i]];
503     }
504     INTERPOL(coeff,
505 	     el_info, data->cur_wall, n, tmp_indices,
506 	     f, f_data, data->bulk_bfcts);
507     for (i = 0; i < self->n_bas_fcts; i++) {
508       tmp_coeff[i] = coeff->vec[data->trace_dof_map[i]];
509     }
510     for (i = 0; i < self->n_bas_fcts; i++) {
511       coeff->vec[i] = temp_coeff[i];
512     }
513   } else {
514 
515 
516 
517   if (indices == NULL) {
518     for (i = 0; i < self->n_bas_fcts; i++) {
519       tmp_coeff =
520 
521       coeff->vec[i] = coeff
522 data->ipol_loc_dow[data->trace_dof_map[i]];
523     }
524   } else {
525     for (i = 0; i < n; i++) {
526       int dst = b_no[i];
527       int src = data->trace_dof_map[dst];
528       vec->vec[dst] = data->ipol_loc_dow[src];
529     }
530   }
531 }
532 
533 static void tb_interpol_d(EL_REAL_D_VEC *coeff,
534 			  const EL_INFO *el_info, int wall,
535 			  int n, const int *indices,
536 			  LOC_FCT_D_AT_QP f, void *f_data,
537 			  const BAS_FCTS *thisptr)
538 {
539   TB_DATA *data = (TB_DATA *)self->ext_data;
540 
541   INTERPOL_D(data->ipol_loc_dow,
542 	     el_info, data->cur_wall, -1, NULL, f, f_data, data->bulk_bfcts);
543 
544   if (indices == NULL) {
545     for (i = 0; i < self->n_bas_fcts; i++) {
546       COPY_DOW(data->ipol_loc_dow[data->trace_dof_map[i]], vec->vec[i]);
547     }
548   } else {
549     for (i = 0; i < n; i++) {
550       int dst = b_no[i];
551       int src = data->trace_dof_map[dst];
552       COPY_DOW(data->ipol_loc_dow[src], vec->vec[dst]);
553     }
554   }
555 }
556 
557 static void tb_interpol_dow(EL_REAL_VEC_D *vec,
558 			    const EL_INFO *el_info, int wall,
559 			    int no, const int *b_no,
560 			    LOC_FCT_D_AT_QP f, void *f_data,
561 			    const BAS_FCTS *self)
562 {
563   TB_DATA *data = (TB_DATA *)self->ext_data;
564 
565   INTERPOL_DOW(data->ipol_loc_dow,
566 	       el_info, data->cur_wall, -1, NULL, f, f_data, data->bulk_bfcts);
567 
568   if (b_no == NULL) {
569     for (i = 0; i < self->n_bas_fcts; i++) {
570       vec->vec[i] = data->ipol_loc_dow[data->trace_dof_map[i]];
571     }
572   } else {
573     for (i = 0; i < no; i++) {
574       int dst = b_no[i];
575       int src = data->trace_dof_map[dst];
576       vec->vec[dst] = data->ipol_loc_dow[src];
577     }
578   }
579 }
580 
581 const BAS_FCTS *get_trace_bulk_space(const BAS_FCTS *bulk_bfcts,
582 				     MESH *trace_mesh)
583 {
584   FUNCNAME("get_trace_bulk_space");
585   BAS_FCTS *trace_bulk_bfcts;
586   TB_DATA  *data;
587   int dim = bulk_bfcts->dim;
588   char *name;
589   int i;
590 
591   TEST_EXIT(dim == trace_mesh->dim + 1,
592 	    "Wrong dimensions: bulk-bas-fcts: %d, trace-mesh: %d\n",
593 	    dim, trace_mesh->dim);
594 
595   trace_bulk_bfcts = MEM_CALLOC(1, BAS_FCTS);
596   trace_bulk_bfcts->name = name =
597     malloc(sizeof("TraceBulk@@")+strlen(bulk_bfcts)+strlen(trace_mesh->name));
598   sprintf(name, "TraceBulk@%s@", trace_mesh->name, bulk_bfcts->name);
599   trace_bulk_bfcts->dim    = bulk_bfcts->dim;
600   trace_bulk_bfcts->rdim   = bulk_bfcts->rdim;
601   trace_bulk_bfcts->degree = bulk_bfcts->degree;
602   trace_bulk_bfcts->n_bas_fcts = 0;
603   /* Fake to many basis functions in order to make it easier to
604    * forward some call-back functions to the underlying bulk basis
605    * functions.
606    */
607   trace_bulk_bfcts->n_bas_fcts_max =
608     N_WALLS_MAX * bulk_bfcts->trace_bas_fcs->n_bas_fcts_max;
609 
610   trace_bulk_bfcts->n_dof[VERTEX] = bulk_bfcts->trace_bas_fcs->n_dof[VERTEX];
611   trace_bulk_bfcts->n_dof[CENTER] = bulk_bfcts->trace_bas_fcs->n_dof[CENTER];
612   trace_bulk_bfcts->n_dof[EDGE]   = bulk_bfcts->trace_bas_fcs->n_dof[EDGE];
613   trace_bulk_bfcts->n_dof[FACE]   = bulk_bfcts->trace_bas_fcs->n_dof[FACE];
614 
615   CHAIN_INIT(trace_bulk_bfcts);
616   trace_bulk_bfcts->unchained = trace_bulk_bfcts;
617 
618   trace_bulk_bfcts->trace_bas_fcts = bulk_bfcts->trace_bas_fcts;
619   for (w = 0; w < N_WALLS(dim); w++) {
620     trace_bulk_bfcts->n_trace_bas_fcts = 0;
621     for (t = 0; t < 1; t++) {
622       for (o = 0; o < 1; o++) {
623 	trace_bulk_bfcts->trace_dof_map[t][o][w] = id_map;
624       }
625     }
626   }
627   trace_bulk_bfcts->get_dof_indices = tb_get_dof_indices;
628   trace_bulk_bfcts->get_dof_indices = tb_get_bound;
629   trace_bulk_bfcts->interpol        = tb_interpol;
630   trace_bulk_bfcts->interpol_d      = tb_interpol_d;
631   trace_bulk_bfcts->interpol_dow    = tb_interpol_dow;
632 
633   trace_bulk_bfcts->dir_pw_const    = bulk_bas_fcts->dir_pw_const;
634 
635   /* Hook in the default get_FOOBAR_vec() routines */
636   trace_bulk_bfcts->get_int_vec     = default_get_int_vec;
637   trace_bulk_bfcts->get_real_vec    = default_get_real_vec;
638   trace_bulk_bfcts->get_real_d_vec  = default_get_real_d_vec;
639   trace_bulk_bfcts->get_real_vec_d  = default_get_real_vec_d;
640   trace_bulk_bfcts->get_uchar_vec   = default_get_uchar_vec;
641   trace_bulk_bfcts->get_schar_vec   = default_get_schar_vec;
642   trace_bulk_bfcts->get_ptr_vec     = default_get_ptr_vec;
643 
644   /* */
645 }
646 
647