1 /*******************************************************************************
2 *
3 * ALBERTA: an Adaptive multi Level finite element toolbox using
4 * Bisectioning refinement and Error control by Residual
5 * Techniques
6 *
7 * www.alberta-fem.de
8 *
9 * file: heat.c
10 *
11 * description: solver for parabolic model problem
12 *
13 * u,t - \Delta u = f in \Omega
14 * u = g on \partial \Omega
15 *
16 * This version demonstrates the use of EL_SYS_INFO_INSTAT together with
17 * update_system_instat()
18 *
19 ******************************************************************************
20 *
21 * authors: Alfred Schmidt
22 * Zentrum fuer Technomathematik
23 * Fachbereich 3 Mathematik/Informatik
24 * Universitaet Bremen
25 * Bibliothekstr. 2
26 * D-28359 Bremen, Germany
27 *
28 * Kunibert G. Siebert
29 * Institut fuer Mathematik
30 * Universitaet Augsburg
31 * Universitaetsstr. 14
32 * D-86159 Augsburg, Germany
33 *
34 * (c) by A. Schmidt and K.G. Siebert (1996-2003)
35 *
36 ******************************************************************************/
37
38
39 #include <alberta/alberta.h>
40
41 #include "alberta-demo.h"
42
43
44 static bool do_graphics = true; /* global graphics "kill-switch" */
45
46 /*******************************************************************************
47 * global variables: finite element space, discrete solution, discrete
48 * solution from previous time step, load vector,
49 * system matrix, and structure for adaptive procedure
50 *
51 * These variables are kept global because they are shared across build(),
52 * solve() and estimate().
53 ******************************************************************************/
54
55 static const FE_SPACE *fe_space; /* initialized by main() */
56 static DOF_REAL_VEC *u_h = NULL; /* initialized by main() */
57 static DOF_REAL_VEC *u_old = NULL; /* initialized by main() */
58 static DOF_REAL_VEC *f_h = NULL; /* initialized by main() */
59 static DOF_MATRIX *matrix = NULL; /* initialized by main() */
60 static ADAPT_INSTAT *adapt_instat; /* initialized by main() */
61 static BNDRY_FLAGS dirichlet_mask; /* initialized by main() */
62
63 static REAL theta = 0.5; /* parameter of the time discretization */
64 static REAL err_L2 = 0.0; /* spatial error in a single time step */
65
66
67 /*******************************************************************************
68 * struct heat_leaf_data: structure for storing one REAL value on each
69 * leaf element as LEAF_DATA
70 * rw_el_est(): return a pointer to the memory for storing the element
71 * estimate (stored as LEAF_DATA), called by heat_est()
72 * get_el_est(): return the value of the element estimates (from LEAF_DATA),
73 * called by adapt_method_stat() and graphics()
74 ******************************************************************************/
75
76 struct heat_leaf_data
77 {
78 REAL estimate; /* one real for the estimate */
79 REAL est_c; /* one real for the coarsening estimate */
80 };
81
rw_el_est(EL * el)82 static REAL *rw_el_est(EL *el)
83 {
84 if (IS_LEAF_EL(el))
85 return &((struct heat_leaf_data *)LEAF_DATA(el))->estimate;
86 else
87 return NULL;
88 }
89
get_el_est(EL * el)90 static REAL get_el_est(EL *el)
91 {
92 if (IS_LEAF_EL(el))
93 return ((struct heat_leaf_data *)LEAF_DATA(el))->estimate;
94 else
95 return 0.0;
96 }
97
rw_el_estc(EL * el)98 static REAL *rw_el_estc(EL *el)
99 {
100 if (IS_LEAF_EL(el))
101 return &((struct heat_leaf_data *)LEAF_DATA(el))->est_c;
102 else
103 return NULL;
104 }
105
get_el_estc(EL * el)106 static REAL get_el_estc(EL *el)
107 {
108 if (IS_LEAF_EL(el))
109 return ((struct heat_leaf_data *)LEAF_DATA(el))->est_c;
110 else
111 return 0.0;
112 }
113
114 static REAL time_est = 0.0;
115
get_time_est(MESH * mesh,ADAPT_INSTAT * adapt)116 static REAL get_time_est(MESH *mesh, ADAPT_INSTAT *adapt)
117 {
118 return time_est;
119 }
120
121 /*******************************************************************************
122 * For test purposes: exact solution and its gradient (optional)
123 ******************************************************************************/
124
125 static REAL eval_time_u = 0.0;
u(const REAL_D x)126 static REAL u(const REAL_D x)
127 {
128 return sin(M_PI*eval_time_u)*exp(-10.0*SCP_DOW(x,x));
129 }
130
131 static REAL eval_time_u0 = 0.0;
u0(const REAL_D x)132 static REAL u0(const REAL_D x)
133 {
134 eval_time_u = eval_time_u0;
135 return u(x);
136 }
137
138 /*******************************************************************************
139 * problem data: right hand side, boundary values
140 ******************************************************************************/
141
142 static REAL eval_time_g = 0.0;
g(const REAL_D x)143 static REAL g(const REAL_D x) /* boundary values, not optional */
144 {
145 eval_time_u = eval_time_g;
146 return u(x);
147 }
148
149 static REAL eval_time_f = 0.0;
f(const REAL_D x)150 static REAL f(const REAL_D x) /* -Delta u, not optional */
151 {
152 REAL r2 = SCP_DOW(x,x), ux = sin(M_PI*eval_time_f)*exp(-10.0*r2);
153 REAL ut = M_PI*cos(M_PI*eval_time_f)*exp(-10.0*r2);
154 return ut - (400.0*r2 - 20.0*DIM_OF_WORLD)*ux;
155 }
156
157
158 /*******************************************************************************
159 * write error and estimator data to files
160 ******************************************************************************/
161
write_statistics(const char * path,ADAPT_INSTAT * adapt,int n_dof,REAL space_est,REAL time_est,REAL err_L2)162 static void write_statistics(const char *path, ADAPT_INSTAT *adapt, int n_dof,
163 REAL space_est, REAL time_est, REAL err_L2)
164 {
165 static FILE *file_ndof = NULL, *file_tau = NULL;
166 static FILE *file_space_est = NULL, *file_time_est = NULL, *file_L2_err = NULL;
167 const char *name = fe_space->bas_fcts->name;
168 REAL time = adapt->time;
169 char filename[1024];
170
171 if (!file_ndof)
172 {
173 sprintf(filename, "%s/n_dof-%s.agr", path ? path : ".", name);
174 file_ndof = fopen(filename, "w");
175 }
176
177 if (!file_tau)
178 {
179 sprintf(filename, "%s/tau-%s.agr", path ? path : ".", name);
180 file_tau = fopen(filename, "w");
181 }
182
183 if (!file_space_est)
184 {
185 sprintf(filename, "%s/space_est-%s.agr", path ? path : ".", name);
186 file_space_est = fopen(filename, "w");
187 }
188
189 if (!file_time_est)
190 {
191 sprintf(filename, "%s/time_est-%s.agr", path ? path : ".", name);
192 file_time_est = fopen(filename, "w");
193 }
194
195 if (!file_L2_err)
196 {
197 sprintf(filename, "%s/L2_err-%s.agr", path ? path : ".", name);
198 file_L2_err = fopen(filename, "w");
199 }
200
201 if (file_ndof)
202 fprintf(file_ndof, "%.6le %d\n", time, n_dof);
203
204 /*--- don't print zeros, zeros do not allow log display of estimate ---*/
205 if (file_space_est)
206 fprintf(file_space_est, "%.6le %.6le\n", time, MAX(space_est,1.e-20));
207
208 if (time > adapt->start_time)
209 {
210 if (file_tau)
211 {
212 fprintf(file_tau, "%.6le %.6le\n", time, adapt->timestep);
213 }
214 /*--- don't print zeros, zeros do not allow log display of estimate ---*/
215 if (file_time_est)
216 fprintf(file_time_est, "%.6le %.6le\n", time, MAX(time_est,1.e-20));
217 }
218
219 /*--- don't print zeros, zeros do not allow log display of error ---*/
220 if (file_L2_err)
221 fprintf(file_L2_err, "%.6le %.6le\n", time, MAX(err_L2,1.e-20));
222
223 if (time >= adapt->end_time)
224 {
225 if (file_ndof) fclose(file_ndof);
226 if (file_tau) fclose(file_tau);
227 if (file_space_est) fclose(file_space_est);
228 if (file_time_est) fclose(file_time_est);
229 if (file_L2_err) fclose(file_L2_err);
230 }
231 else
232 {
233 fflush(NULL);
234 }
235
236 return;
237 }
238
239 /*******************************************************************************
240 * interpolation is solve on the initial grid
241 ******************************************************************************/
242
interpol_u0(MESH * mesh)243 static void interpol_u0(MESH *mesh)
244 {
245 dof_compress(mesh);
246 interpol(u0, u_h);
247
248 return;
249 }
250
init_timestep(MESH * mesh,ADAPT_INSTAT * adapt)251 static void init_timestep(MESH *mesh, ADAPT_INSTAT *adapt)
252 {
253 FUNCNAME("init_timestep");
254
255 INFO(adapt_instat->info,1,
256 "---8<---------------------------------------------------\n");
257 INFO(adapt_instat->info, 1,"starting new timestep\n");
258
259 dof_copy(u_h, u_old);
260 return;
261 }
262
set_time(MESH * mesh,ADAPT_INSTAT * adapt)263 static void set_time(MESH *mesh, ADAPT_INSTAT *adapt)
264 {
265 FUNCNAME("set_time");
266
267 INFO(adapt->info,1,
268 "---8<---------------------------------------------------\n");
269 if (adapt->time == adapt->start_time)
270 {
271 INFO(adapt->info, 1,"start time: %.4le\n", adapt->time);
272 }
273 else
274 {
275 INFO(adapt->info, 1,"timestep for (%.4le %.4le), tau = %.4le\n",
276 adapt->time-adapt->timestep, adapt->time,
277 adapt->timestep);
278 }
279
280 eval_time_f = adapt->time - (1 - theta)*adapt->timestep;
281 eval_time_g = adapt->time;
282
283 return;
284 }
285
close_timestep(MESH * mesh,ADAPT_INSTAT * adapt)286 static void close_timestep(MESH *mesh, ADAPT_INSTAT *adapt)
287 {
288 FUNCNAME("close_timestep");
289 static REAL err_max = 0.0; /* max space-time error */
290 static REAL est_max = 0.0; /* max space-time estimate */
291 static int write_fe_data = 0, write_stat_data = 0;
292 static int step = 0;
293 static char path[256] = "./";
294
295 REAL space_est = adapt->adapt_space->err_sum;
296 REAL tolerance = adapt->rel_time_error*adapt->tolerance;
297
298 err_max = MAX(err_max, err_L2);
299 est_max = MAX(est_max, space_est + time_est);
300
301 INFO(adapt->info,1,
302 "---8<---------------------------------------------------\n");
303
304 if (adapt->time == adapt->start_time) {
305 tolerance = adapt->adapt_initial->tolerance;
306 INFO(adapt->info,1,"start time: %.4le\n", adapt->time);
307 } else {
308 tolerance += adapt->adapt_space->tolerance;
309 INFO(adapt->info,1,"timestep for (%.4le %.4le), tau = %.4le\n",
310 adapt->time-adapt->timestep, adapt->time,
311 adapt->timestep);
312 }
313 INFO(adapt->info,2,"max. est. = %.4le, tolerance = %.4le\n",
314 est_max, tolerance);
315 INFO(adapt->info,2,"max. error = %.4le, ratio = %.2lf\n",
316 err_max, err_max/MAX(est_max,1.0e-20));
317
318 if (!step) {
319 GET_PARAMETER(1, "write finite element data", "%d", &write_fe_data);
320 GET_PARAMETER(1, "write statistical data", "%d", &write_stat_data);
321 GET_PARAMETER(1, "data path", "%s", path);
322 }
323
324 /*****************************************************************************
325 * write mesh and discrete solution to file for post-processing
326 ****************************************************************************/
327
328 if (write_fe_data) {
329 const char *fn;
330
331 fn= generate_filename(path, "mesh", step);
332 write_mesh_xdr(mesh, fn, adapt->time);
333 fn= generate_filename(path, "u_h", step);
334 write_dof_real_vec_xdr(u_h, fn);
335 }
336
337 step++;
338
339 /*****************************************************************************
340 * write data about estimate, error, time step size, etc.
341 ****************************************************************************/
342
343 if (write_stat_data) {
344 int n_dof = fe_space->admin->size_used;
345 write_statistics(path, adapt, n_dof, space_est, time_est, err_L2);
346 }
347
348 if (do_graphics) {
349 graphics(mesh, u_h, get_el_est, u, adapt->time);
350 }
351
352 return;
353 }
354
355
356 /*--------------------------------------------------------------------------*/
357 /* build(): assemblage of the linear system: matrix, load vector, */
358 /* boundary values, called by adapt_method_stat() */
359 /* on the first call initialize u_h, f_h, matrix and information */
360 /* for assembling the system matrix */
361 /* */
362 /* struct op_data: structure for passing information from init_element() to*/
363 /* LALt() */
364 /* init_element(): initialization on the element; calculates the */
365 /* coordinates and |det DF_S| used by LALt; passes these */
366 /* values to LALt via user_data, */
367 /* called on each element by update_matrix() */
368 /* LALt(): implementation of -Lambda id Lambda^t for -Delta u, */
369 /* called by update_matrix() */
370 /* c(): implementation of 1/tau*m(,) */
371 /*--------------------------------------------------------------------------*/
372
373 struct op_data /* application data (AKA "user_data") */
374 {
375 REAL_BD Lambda; /* the gradient of the barycentric coordinates */
376 REAL det; /* |det D F_S| */
377
378 REAL tau_1;
379 };
380
LALt(const EL_INFO * el_info,const QUAD * quad,int iq,void * ud)381 static const REAL_B *LALt(const EL_INFO *el_info, const QUAD *quad,
382 int iq, void *ud)
383 {
384 struct op_data *info = (struct op_data *)ud;
385 int i, j, k, dim = el_info->mesh->dim;
386 static REAL_BB LALt;
387
388 for (i = 0; i <= dim; i++)
389 for (j = i; j <= dim; j++)
390 {
391 for (LALt[i][j] = k = 0; k < DIM_OF_WORLD; k++)
392 LALt[i][j] += info->Lambda[i][k]*info->Lambda[j][k];
393 LALt[i][j] *= info->det;
394 LALt[j][i] = LALt[i][j];
395 }
396 return (const REAL_B *)LALt;
397 }
398
c(const EL_INFO * el_info,const QUAD * quad,int iq,void * ud)399 static REAL c(const EL_INFO *el_info, const QUAD *quad, int iq, void *ud)
400 {
401 struct op_data *info = (struct op_data *)ud;
402
403 return info->tau_1*info->det;
404 }
405
assemble(DOF_MATRIX * matrix,DOF_REAL_VEC * fh,DOF_REAL_VEC * uh,const DOF_REAL_VEC * u_old,REAL theta,REAL tau,REAL (* f)(const REAL_D),REAL (* g)(const REAL_D),const BNDRY_FLAGS dirichlet_mask)406 static void assemble(DOF_MATRIX *matrix, DOF_REAL_VEC *fh, DOF_REAL_VEC *uh,
407 const DOF_REAL_VEC *u_old,
408 REAL theta, REAL tau,
409 REAL (*f)(const REAL_D), REAL (*g)(const REAL_D),
410 const BNDRY_FLAGS dirichlet_mask)
411 {
412 /* Some quantities remembered across calls. Think of this routine
413 * like being a "library function" ... The stuff is re-initialized
414 * whenever the finite element space changes. We use fe_space->admin
415 * to check for changes in the finite element space because
416 * DOF_ADMIN's are persisitent within ALBERTA, while fe-space are
417 * not.
418 */
419 static EL_MATRIX_INFO stiff_elmi, mass_elmi;
420 static const DOF_ADMIN *admin = NULL;
421 static const QUAD *quad = NULL;
422 static struct op_data op_data[1]; /* storage for det and Lambda */
423
424 /* Remaining (non-static) variables. */
425 const BAS_FCTS *bas_fcts;
426 FLAGS fill_flag;
427 EL_SCHAR_VEC *bound;
428
429 /* Initialize persistent variables. */
430 if (admin != uh->fe_space->admin) {
431 OPERATOR_INFO stiff_opi = { NULL, }, mass_opi = { NULL, };
432
433 admin = uh->fe_space->admin;
434
435 stiff_opi.row_fe_space = uh->fe_space;
436 stiff_opi.quad[2] = quad;
437 stiff_opi.LALt.real = LALt;
438 stiff_opi.LALt_pw_const = true;
439 stiff_opi.LALt_symmetric = true;
440 stiff_opi.user_data = op_data;
441
442 fill_matrix_info(&stiff_opi, &stiff_elmi);
443
444 mass_opi.row_fe_space = uh->fe_space;
445 mass_opi.quad[0] = quad;
446 mass_opi.c.real = c;
447 mass_opi.c_pw_const = true;
448 mass_opi.user_data = op_data;
449
450 fill_matrix_info(&mass_opi, &mass_elmi);
451
452 quad = get_quadrature(uh->fe_space->bas_fcts->dim,
453 2*uh->fe_space->bas_fcts->degree);
454 }
455
456 op_data->tau_1 = 1.0/tau;
457
458 /* Assemble the matrix and the right hand side. The idea is to
459 * assemble the local mass and stiffness matrices only once, and to
460 * use it to update both, the system matrix and the contribution of
461 * the time discretisation to the RHS.
462 */
463 clear_dof_matrix(matrix);
464 dof_set(0.0, fh);
465
466 bas_fcts = uh->fe_space->bas_fcts;
467
468 bound = get_el_schar_vec(bas_fcts);
469
470 fill_flag = CALL_LEAF_EL|FILL_COORDS|FILL_BOUND;
471 TRAVERSE_FIRST(uh->fe_space->mesh, -1, fill_flag) {
472 const EL_REAL_VEC *u_old_loc;
473 const EL_DOF_VEC *dof;
474 const EL_BNDRY_VEC *bndry_bits;
475 const EL_MATRIX *stiff_loc, *mass_loc;
476
477 /* Get the local coefficients of u_old, boundary info, dof-mapping */
478 u_old_loc = fill_el_real_vec(NULL, el_info->el, u_old);
479 dof = get_dof_indices(NULL, uh->fe_space, el_info->el);
480 bndry_bits = get_bound(NULL, bas_fcts, el_info);
481
482 /* Initialization of values used by LALt and c. It is not
483 * necessary to introduce an extra "init_element()" hook for our
484 * OPERATOR_INFO structures; the line below is just what would be
485 * contained in that function (compare with ellipt.c).
486 *
487 * Beware to replace the "..._0cd()" for co-dimension 0 by its
488 * proper ..._dim() variant if ever "porting" this stuff to
489 * parametric meshes on manifolds.
490 */
491 op_data->det = el_grd_lambda_0cd(el_info, op_data->Lambda);
492
493 /* Obtain the local (i.e. per-element) matrices. */
494 stiff_loc = stiff_elmi.el_matrix_fct(el_info, stiff_elmi.fill_info);
495 mass_loc = mass_elmi.el_matrix_fct(el_info, mass_elmi.fill_info);
496
497 /* Translate the geometric boundary classification into
498 * Dirichlet/Neumann/Interior boundary condition
499 * interpretation. Inside the loop over the mesh-elements we need
500 * only to care about Dirichlet boundary conditions.
501 */
502 dirichlet_map(bound, bndry_bits, dirichlet_mask);
503
504 /* add theta*a(psi_i,psi_j) + 1/tau*m(4*u^3*psi_i,psi_j) */
505 if (theta) {
506 add_element_matrix(matrix,
507 theta, stiff_loc, NoTranspose, dof, dof, bound);
508 }
509 add_element_matrix(matrix, 1.0, mass_loc, NoTranspose, dof, dof, bound);
510
511 /* compute the contributions from the old time-step:
512 *
513 * f += -(1-theta)*a(u_old,psi_i) + 1/tau*m(u_old,psi_i)
514 */
515 bi_mat_el_vec(-(1.0 - theta), stiff_loc,
516 1.0, mass_loc, u_old_loc,
517 1.0, fh, dof, bound);
518
519 } TRAVERSE_NEXT();
520
521 free_el_schar_vec(bound);
522
523 /* Indicate that the boundary conditions are built into the matrix,
524 * needed e.g. by the hierarchical preconditioners.
525 */
526 BNDRY_FLAGS_CPY(matrix->dirichlet_bndry, dirichlet_mask);
527
528 /* Add the "force-term" to the right hand side (L2scp_...() is additive) */
529 L2scp_fct_bas(f, quad, fh);
530
531 /* Close the system by imposing suitable boundary conditions. Have a
532 * look at ellipt.c for how to impose more complicated stuff; here
533 * we only use Dirichlet b.c.
534 */
535 dirichlet_bound(fh, uh, NULL, dirichlet_mask, g);
536 }
537
build(MESH * mesh,U_CHAR flag)538 static void build(MESH *mesh, U_CHAR flag)
539 {
540 FUNCNAME("build");
541
542 dof_compress(mesh);
543
544 INFO(adapt_instat->adapt_space->info, 2,
545 "%d DOFs for %s\n", fe_space->admin->size_used, fe_space->name);
546
547 assemble(matrix, f_h, u_h, u_old, theta, adapt_instat->timestep,
548 f, g, dirichlet_mask);
549 }
550
551 /*--------------------------------------------------------------------------*/
552 /* solve(): solve the linear system, called by adapt_method_stat() */
553 /*--------------------------------------------------------------------------*/
554
solve(MESH * mesh)555 static void solve(MESH *mesh)
556 {
557 FUNCNAME("solve");
558 static REAL tol = 1.e-8, ssor_omega = 1.0;
559 static int max_iter = 1000, info = 2, restart = 0, ssor_iter = 1, ilu_k = 8;
560 static OEM_PRECON icon = DiagPrecon;
561 static OEM_SOLVER solver = NoSolver;
562 const PRECON *precon;
563
564 if (solver == NoSolver) {
565 GET_PARAMETER(1, "solver", "%d", &solver);
566 GET_PARAMETER(1, "solver tolerance", "%f", &tol);
567 GET_PARAMETER(1, "solver precon", "%d", &icon);
568 GET_PARAMETER(1, "solver max iteration", "%d", &max_iter);
569 GET_PARAMETER(1, "solver info", "%d", &info);
570 if (icon == __SSORPrecon) {
571 GET_PARAMETER(1, "precon ssor omega", "%f", &ssor_omega);
572 GET_PARAMETER(1, "precon ssor iter", "%d", &ssor_iter);
573 }
574 if (icon == ILUkPrecon)
575 GET_PARAMETER(1, "precon ilu(k)", "%d", &ilu_k);
576 if (solver == GMRes) {
577 GET_PARAMETER(1, "solver restart", "%d", &restart);
578 }
579 }
580
581 if (icon == ILUkPrecon)
582 precon = init_oem_precon(matrix, NULL, info, ILUkPrecon, ilu_k);
583 else
584 precon = init_oem_precon(matrix, NULL, info, icon, ssor_omega, ssor_iter);
585 oem_solve_s(matrix, NULL, f_h, u_h,
586 solver, tol, precon, restart, max_iter, info);
587 }
588
589 /*--------------------------------------------------------------------------*/
590 /* Functions for error estimate: */
591 /* estimate(): calculates error estimate via heat_est() */
592 /* calculates exact error also (only for test purpose), */
593 /* called by adapt_method_stat() */
594 /*--------------------------------------------------------------------------*/
595
r(const EL_INFO * el_info,const QUAD * quad,int iq,REAL uh_at_qp,const REAL_D grd_uh_at_qp,REAL t)596 static REAL r(const EL_INFO *el_info,
597 const QUAD *quad, int iq,
598 REAL uh_at_qp, const REAL_D grd_uh_at_qp,
599 REAL t)
600 {
601 REAL_D x;
602
603 coord_to_world(el_info, quad->lambda[iq], x);
604 eval_time_f = t;
605
606 return -f(x);
607 }
608
609
estimate(MESH * mesh,ADAPT_STAT * adapt)610 static REAL estimate(MESH *mesh, ADAPT_STAT *adapt)
611 {
612 FUNCNAME("estimate");
613 static REAL C[4] = {-1.0, 1.0, 1.0, 1.0};
614 static REAL_DD A = {{0.0}};
615 FLAGS r_flag = 0; /* = (INIT_UH|INIT_GRD_UH), if needed by r() */
616 int n;
617 REAL space_est;
618
619 eval_time_u = adapt_instat->time;
620
621 if (C[0] < 0) {
622 C[0] = 1.0;
623 GET_PARAMETER(1, "estimator C0", "%f", &C[0]);
624 GET_PARAMETER(1, "estimator C1", "%f", &C[1]);
625 GET_PARAMETER(1, "estimator C2", "%f", &C[2]);
626 GET_PARAMETER(1, "estimator C3", "%f", &C[3]);
627
628 for (n = 0; n < DIM_OF_WORLD; n++) {
629 A[n][n] = 1.0; /* set diogonal of A; all other elements are zero */
630 }
631 }
632
633 time_est = heat_est(u_h, u_old, adapt_instat, rw_el_est, rw_el_estc,
634 -1 /* quad_degree */,
635 C, (const REAL_D *)A, dirichlet_mask,
636 r, r_flag, NULL /* gn() */, 0 /* gn_flag */);
637
638 space_est = adapt_instat->adapt_space->err_sum;
639 err_L2 = L2_err(u, u_h, NULL, false, false, NULL, NULL);
640
641 INFO(adapt_instat->info,2,
642 "---8<---------------------------------------------------\n");
643 INFO(adapt_instat->info, 2,"time = %.4le with timestep = %.4le\n",
644 adapt_instat->time, adapt_instat->timestep);
645 INFO(adapt_instat->info, 2,"estimate = %.4le, max = %.4le\n", space_est,
646 sqrt(adapt_instat->adapt_space->err_max));
647 INFO(adapt_instat->info, 2,"||u-uh||L2 = %.4le, ratio = %.2lf\n", err_L2,
648 err_L2/MAX(space_est,1.e-20));
649
650 return adapt_instat->adapt_space->err_sum;
651 }
652
est_initial(MESH * mesh,ADAPT_STAT * adapt)653 static REAL est_initial(MESH *mesh, ADAPT_STAT *adapt)
654 {
655 err_L2 = adapt->err_sum =
656 L2_err(u0, u_h, NULL, false, false, rw_el_est, &adapt->err_max);
657 return adapt->err_sum;
658 }
659
660 /*--------------------------------------------------------------------------*/
661 /* main program */
662 /*--------------------------------------------------------------------------*/
663
main(int argc,char ** argv)664 int main(int argc, char **argv)
665 {
666 FUNCNAME("main");
667 MACRO_DATA *data;
668 MESH *mesh;
669 const BAS_FCTS *lagrange;
670 int n_refine = 0, p = 1, dim;
671 char filename[PATH_MAX];
672 REAL fac = 1.0;
673
674 /*****************************************************************************
675 * first of all, initialize the access to parameters of the init file
676 ****************************************************************************/
677 parse_parameters(argc, argv, "INIT/heat.dat");
678
679 GET_PARAMETER(1, "mesh dimension", "%d", &dim);
680 GET_PARAMETER(1, "macro file name", "%s", filename);
681 GET_PARAMETER(1, "global refinements", "%d", &n_refine);
682 GET_PARAMETER(1, "parameter theta", "%e", &theta);
683 GET_PARAMETER(1, "polynomial degree", "%d", &p);
684 GET_PARAMETER(1, "online graphics", "%d", &do_graphics);
685
686 /*****************************************************************************
687 * get a mesh, and read the macro triangulation from file
688 ****************************************************************************/
689 data = read_macro(filename);
690 mesh = GET_MESH(dim, "ALBERTA mesh", data,
691 NULL /* init_node_projection() */,
692 NULL /* init_wall_trafos() */);
693 free_macro_data(data);
694
695 init_leaf_data(mesh, sizeof(struct heat_leaf_data),
696 NULL /* refine_leaf_data() */,
697 NULL /* coarsen_leaf_data() */);
698
699 /* Finite element spaces can be added at any time, but it is more
700 * efficient to do so before refining the mesh a lot.
701 */
702 lagrange = get_lagrange(mesh->dim, p);
703 TEST_EXIT(lagrange, "no lagrange BAS_FCTS\n");
704
705 fe_space = get_fe_space(mesh, lagrange->name, lagrange, 1, ADM_FLAGS_DFLT);
706
707 global_refine(mesh, n_refine * dim, FILL_NOTHING);
708
709 /*****************************************************************************
710 * initialize the global variables shared across build(), solve()
711 * and estimate().
712 ****************************************************************************/
713 matrix = get_dof_matrix("A", fe_space, NULL);
714 f_h = get_dof_real_vec("f_h", fe_space);
715 u_h = get_dof_real_vec("u_h", fe_space);
716 u_h->refine_interpol = fe_space->bas_fcts->real_refine_inter;
717 u_h->coarse_restrict = fe_space->bas_fcts->real_coarse_inter;
718 u_old = get_dof_real_vec("u_old", fe_space);
719 u_old->refine_interpol = fe_space->bas_fcts->real_refine_inter;
720 u_old->coarse_restrict = fe_space->bas_fcts->real_coarse_inter;
721 dof_set(0.0, u_h); /* initialize u_h ! */
722
723 BNDRY_FLAGS_ALL(dirichlet_mask); /* Only Dirichlet b.c. supported here */
724
725 /*****************************************************************************
726 * init adapt_instat structure
727 ****************************************************************************/
728 adapt_instat = get_adapt_instat(dim, "heat", "adapt", 2, adapt_instat);
729
730 /* Some animation in between ... */
731 if (do_graphics) {
732 graphics(mesh, NULL, NULL, NULL, adapt_instat->start_time);
733 }
734
735 /*****************************************************************************
736 * adapt time step size to refinement level and polynomial degree,
737 * based on the known L2-error error estimates.
738 ****************************************************************************/
739 if (theta < 0.5) {
740 WARNING("You are using the explicit Euler scheme\n");
741 WARNING("Use a sufficiently small time step size!!!\n");
742 fac = 1.0e-3;
743 }
744
745 if (theta == 0.5) {
746 adapt_instat->timestep *= fac*pow(2, -(REAL)(p*(n_refine))/2.0);
747 } else {
748 adapt_instat->timestep *= fac*pow(2, -(REAL)(p*(n_refine)));
749 }
750 MSG("using initial timestep size = %.4le\n", adapt_instat->timestep);
751
752 eval_time_u0 = adapt_instat->start_time;
753
754 adapt_instat->adapt_initial->get_el_est = get_el_est;
755 adapt_instat->adapt_initial->estimate = est_initial;
756 adapt_instat->adapt_initial->solve = interpol_u0;
757
758 adapt_instat->adapt_space->get_el_est = get_el_est;
759 adapt_instat->adapt_space->get_el_estc = get_el_estc;
760 adapt_instat->adapt_space->estimate = estimate;
761 adapt_instat->adapt_space->build_after_coarsen = build;
762 adapt_instat->adapt_space->solve = solve;
763
764 adapt_instat->init_timestep = init_timestep;
765 adapt_instat->set_time = set_time;
766 adapt_instat->get_time_est = get_time_est;
767 adapt_instat->close_timestep = close_timestep;
768
769 /*****************************************************************************
770 * ... off we go ...
771 ****************************************************************************/
772 adapt_method_instat(mesh, adapt_instat);
773
774 WAIT_REALLY;
775
776 return 0;
777 }
778