/* * authors: Claus-Justus Heine * Abteilung fuer Angewandte Mathematik * Albert-Ludwigs-Universit"at Freiburg * Hermann-Herder-Str. 10 * 79104 Freiburg * Germany * claus@mathematik.uni-freiburg.de * * Copyright (c) by C.-J. Heine (2005-2007) * * Generic support for assembling linear systems for time dependent problems. */ #include "alberta_intern.h" #include "alberta.h" /** Theta-splitting scheme, given the element mass matrix and the part * of the stiffness matrix which is subject to the \theta-splitting. * * Parameters: * * @param[in] el_info Element descriptor, filled as specified by * ::EL_MATRIX_INFO::fill_flag. * @param[in,out] dof_matrix The (global) system matrix. * @param[in,out] f_h The righ-hand-side vector. * @param[in] u_h The interpolation of the old solution onto the new * mesh. * @param[in] tau Time-step size. * @param[in] mass_info The fill-info for the element mass matrix. * @param[in] theta The splitting coefficient for the elliptic part. * @param[in] stiff_info The fill-info for the element stiffness matrix, * the elliptic part of the PDE. * */ typedef struct system_fill_info_instat { EL_SYS_INFO_INSTAT elsii; const DOF_REAL_VEC *u_h; const EL_MATRIX_INFO *stiff_info; const EL_MATRIX_INFO *mass_info; int n_row; int n_col; int n_row_max; int n_col_max; } SYSTEM_FILL_INFO_INSTAT; typedef struct system_fill_info_dow_instat { EL_SYS_INFO_DOW_INSTAT elsii; const DOF_REAL_VEC_D *u_h_d; const EL_MATRIX_INFO *stiff_info; const EL_MATRIX_INFO *mass_info; int n_row; int n_col; int n_row_max; int n_col_max; } SYSTEM_FILL_INFO_DOW_INSTAT; static INIT_EL_TAG element_system_instat(const EL_INFO *el_info, REAL tau, REAL theta, EL_SYS_INFO_INSTAT *thisptr) { SYSTEM_FILL_INFO_INSTAT *info = (SYSTEM_FILL_INFO_INSTAT *)thisptr; REAL theta1 = 1.0 - theta; REAL tau1 = 1.0/tau; int n_row, n_col; /* First compute the element matrices, el_matrix_fct() will call all * necessary INIT_ELEMENT() methods for us. */ thisptr->el_stiff = info->stiff_info->el_matrix_fct(el_info, info->stiff_info->fill_info); if (thisptr->el_stiff == NULL) { return INIT_EL_TAG_NULL; } thisptr->el_mass = info->mass_info->el_matrix_fct(el_info, info->mass_info->fill_info); if (thisptr->el_mass == NULL) { return INIT_EL_TAG_NULL; } thisptr->el_matrix->n_row = n_row = thisptr->row_fe_space->bas_fcts->n_bas_fcts; thisptr->el_matrix->n_col = n_col = thisptr->col_fe_space->bas_fcts->n_bas_fcts; info->n_row = n_row; info->n_col = n_col; fill_el_real_vec((EL_REAL_VEC *)thisptr->u_h_loc, el_info->el, info->u_h); /* f += -(1-theta)*a(u_old,psi_i) + 1/tau*m(u_old,psi_i) */ if (theta1) { el_bi_mat_vec(-theta1, thisptr->el_stiff, tau1, thisptr->el_mass, thisptr->u_h_loc, 1.0, thisptr->el_load); } else { el_mat_vec(tau1, thisptr->el_mass, thisptr->u_h_loc, thisptr->el_load); } /* initialize with 1/tau*m(psi_i,psi_j) */ el_mat_axey(tau1, thisptr->el_mass, thisptr->el_matrix); /* add theta*a(psi_i,psi_j) */ if (theta) { el_mat_axpy(theta, thisptr->el_stiff, thisptr->el_matrix); } return INIT_EL_TAG_DFLT; } static INIT_EL_TAG element_system_dow_instat(const EL_INFO *el_info, REAL tau, REAL theta, EL_SYS_INFO_DOW_INSTAT *thisptr) { SYSTEM_FILL_INFO_DOW_INSTAT *info = (SYSTEM_FILL_INFO_DOW_INSTAT *)thisptr; REAL theta1 = 1.0 - theta; REAL tau1 = 1.0/tau; int n_row, n_col; /* First compute the element matrices, el_matrix_fct() will call all * necessary INIT_ELEMENT() methods for us. */ thisptr->el_stiff = info->stiff_info->el_matrix_fct(el_info, info->stiff_info->fill_info); if (thisptr->el_stiff == NULL) { return INIT_EL_TAG_NULL; } thisptr->el_mass = info->mass_info->el_matrix_fct(el_info, info->mass_info->fill_info); if (thisptr->el_mass == NULL) { return INIT_EL_TAG_NULL; } thisptr->el_matrix->n_row = n_row = thisptr->row_fe_space->bas_fcts->n_bas_fcts; thisptr->el_matrix->n_col = n_col = thisptr->col_fe_space->bas_fcts->n_bas_fcts; info->n_row = n_row; info->n_col = n_col; fill_el_real_vec_d( (EL_REAL_VEC_D *)thisptr->u_h_loc, el_info->el, info->u_h_d); /* f += -(1-theta)*a(u_old,psi_i) + 1/tau*m(u_old,psi_i) */ if (theta1) { el_bi_mat_vec_dow(-theta1, thisptr->el_stiff, tau1, thisptr->el_mass, thisptr->u_h_loc, 1.0, thisptr->el_load); } else { el_mat_vec_dow(tau1, thisptr->el_mass, thisptr->u_h_loc, thisptr->el_load); } /* initialize with 1/tau*m(psi_i,psi_j) */ el_mat_axey(tau1, thisptr->el_mass, thisptr->el_matrix); /* add theta*a(psi_i,psi_j) */ if (theta) { el_mat_axpy(theta, thisptr->el_stiff, thisptr->el_matrix); } return INIT_EL_TAG_DFLT; } EL_SYS_INFO_INSTAT *fill_sys_info_instat(const OPERATOR_INFO *stiff_info, const OPERATOR_INFO *mass_info, const DOF_REAL_VEC *u_h) { SYSTEM_FILL_INFO_INSTAT *info; info = MEM_CALLOC(1, SYSTEM_FILL_INFO_INSTAT); info->stiff_info = fill_matrix_info(stiff_info, NULL); info->mass_info = fill_matrix_info(mass_info, NULL); info->elsii.row_fe_space = info->mass_info->row_fe_space; info->elsii.col_fe_space = info->mass_info->col_fe_space; if (info->elsii.col_fe_space == NULL) { info->elsii.col_fe_space = info->elsii.row_fe_space; } info->elsii.el_update_fct = element_system_instat; info->n_row = info->elsii.row_fe_space->bas_fcts->n_bas_fcts; info->n_row_max = info->elsii.row_fe_space->bas_fcts->n_bas_fcts_max; info->n_col = info->elsii.col_fe_space->bas_fcts->n_bas_fcts; info->n_col_max = info->elsii.col_fe_space->bas_fcts->n_bas_fcts_max; info->elsii.el_matrix = get_el_matrix(info->elsii.row_fe_space, info->elsii.col_fe_space, MATENT_REAL); info->elsii.el_load = get_el_real_vec(info->elsii.row_fe_space->bas_fcts); info->elsii.u_h_loc = get_el_real_vec(info->elsii.col_fe_space->bas_fcts); info->elsii.fill_flag = info->stiff_info->fill_flag | info->mass_info->fill_flag; BNDRY_FLAGS_CPY(info->elsii.dirichlet_bndry, info->mass_info->dirichlet_bndry); BNDRY_FLAGS_OR(info->elsii.dirichlet_bndry, info->stiff_info->dirichlet_bndry); if (!BNDRY_FLAGS_IS_INTERIOR(info->elsii.dirichlet_bndry)) { info->elsii.fill_flag |= FILL_BOUND; if (info->elsii.row_fe_space->mesh->is_periodic && !(info->elsii.row_fe_space->admin->flags & ADM_PERIODIC)) info->elsii.fill_flag |= FILL_NON_PERIODIC; } info->u_h = u_h; return &info->elsii; } EL_SYS_INFO_DOW_INSTAT * fill_sys_info_instat_dow(const OPERATOR_INFO *stiff_info, const OPERATOR_INFO *mass_info, const DOF_REAL_VEC_D *u_h_d) { SYSTEM_FILL_INFO_DOW_INSTAT *info; info = MEM_CALLOC(1, SYSTEM_FILL_INFO_DOW_INSTAT); info->stiff_info = fill_matrix_info(stiff_info, NULL); info->mass_info = fill_matrix_info(mass_info, NULL); info->elsii.krn_blk_type = info->stiff_info->krn_blk_type; info->elsii.row_fe_space = info->mass_info->row_fe_space; info->elsii.col_fe_space = info->mass_info->col_fe_space; if (info->elsii.col_fe_space == NULL) { info->elsii.col_fe_space = info->elsii.row_fe_space; } info->elsii.el_update_fct = element_system_dow_instat; info->n_row = info->elsii.row_fe_space->bas_fcts->n_bas_fcts; info->n_row_max = info->elsii.row_fe_space->bas_fcts->n_bas_fcts_max; info->n_col = info->elsii.col_fe_space->bas_fcts->n_bas_fcts; info->n_col_max = info->elsii.col_fe_space->bas_fcts->n_bas_fcts_max; info->elsii.el_matrix = get_el_matrix(info->elsii.row_fe_space, info->elsii.col_fe_space, info->elsii.krn_blk_type); info->elsii.el_load = get_el_real_vec_d(info->elsii.row_fe_space->bas_fcts); info->elsii.u_h_loc = get_el_real_vec_d(info->elsii.col_fe_space->bas_fcts); info->elsii.fill_flag = info->stiff_info->fill_flag | info->mass_info->fill_flag; BNDRY_FLAGS_CPY(info->elsii.dirichlet_bndry, info->mass_info->dirichlet_bndry); BNDRY_FLAGS_OR(info->elsii.dirichlet_bndry, info->stiff_info->dirichlet_bndry); if (!BNDRY_FLAGS_IS_INTERIOR(info->elsii.dirichlet_bndry)) { info->elsii.fill_flag |= FILL_BOUND; if (info->elsii.row_fe_space->mesh->is_periodic && !(info->elsii.row_fe_space->admin->flags & ADM_PERIODIC)) info->elsii.fill_flag |= FILL_NON_PERIODIC; } info->u_h_d = u_h_d; return &info->elsii; } void free_sys_info_instat(EL_SYS_INFO_INSTAT *elsii) { SYSTEM_FILL_INFO_INSTAT *info = (SYSTEM_FILL_INFO_INSTAT *)elsii; free_el_matrix(elsii->el_matrix); free_el_real_vec(elsii->el_load); free_el_real_vec((EL_REAL_VEC *)elsii->u_h_loc); MEM_FREE(info->stiff_info, 1, EL_MATRIX_INFO); MEM_FREE(info->mass_info, 1, EL_MATRIX_INFO); MEM_FREE(info, 1, SYSTEM_FILL_INFO_INSTAT); } void free_sys_info_dow_instat(EL_SYS_INFO_DOW_INSTAT *elsii) { SYSTEM_FILL_INFO_DOW_INSTAT *info = (SYSTEM_FILL_INFO_DOW_INSTAT *)elsii; free_el_matrix(elsii->el_matrix); free_el_real_vec_d(elsii->el_load); free_el_real_vec_d((EL_REAL_VEC_D *)elsii->u_h_loc); MEM_FREE(info->stiff_info, 1, EL_MATRIX_INFO); MEM_FREE(info->mass_info, 1, EL_MATRIX_INFO); MEM_FREE(info, 1, SYSTEM_FILL_INFO_DOW_INSTAT); } /* Assemble (1/tau M + theta S) and add (1/tau M uh + (1-theta) S uh) * to fh. */ void update_system_instat(DOF_MATRIX *dof_matrix, DOF_REAL_VEC *f_h, REAL tau, REAL theta, EL_SYS_INFO_INSTAT *elsii) { const BAS_FCTS *row_bfcts = elsii->row_fe_space->bas_fcts; const EL_DOF_VEC *row_dof, *col_dof; EL_SCHAR_VEC *bound = NULL; const EL_BNDRY_VEC *bndry_bits; bool use_get_bound; BNDRY_FLAGS_CPY(dof_matrix->dirichlet_bndry, elsii->dirichlet_bndry); use_get_bound = !BNDRY_FLAGS_IS_INTERIOR(dof_matrix->dirichlet_bndry); if (use_get_bound) { bound = get_el_schar_vec(elsii->row_fe_space->bas_fcts); } TRAVERSE_FIRST(dof_matrix->row_fe_space->mesh, -1, elsii->fill_flag|CALL_LEAF_EL|FILL_COORDS) { if (elsii->el_update_fct(el_info, tau, theta, elsii) == INIT_EL_TAG_NULL) { continue; } row_dof = get_dof_indices(NULL, f_h->fe_space, el_info->el); if (elsii->row_fe_space != elsii->col_fe_space) { col_dof = get_dof_indices(NULL, elsii->col_fe_space, el_info->el); } else { col_dof = row_dof; } if (use_get_bound) { bndry_bits = get_bound(NULL, row_bfcts, el_info); dirichlet_map(bound, bndry_bits, dof_matrix->dirichlet_bndry); } add_element_matrix(dof_matrix, 1.0, elsii->el_matrix, NoTranspose, row_dof, col_dof, bound); add_element_vec(f_h, 1.0, elsii->el_load, row_dof, bound); } TRAVERSE_NEXT(); if (use_get_bound) { free_el_schar_vec(bound); } } void update_system_instat_dow(DOF_MATRIX *dof_matrix, DOF_REAL_VEC_D *f_h, REAL tau, REAL theta, EL_SYS_INFO_DOW_INSTAT *elsii) { const BAS_FCTS *row_bfcts = elsii->row_fe_space->bas_fcts; const EL_DOF_VEC *row_dof, *col_dof; EL_SCHAR_VEC *bound = NULL; const EL_BNDRY_VEC *bndry_bits; bool use_get_bound; BNDRY_FLAGS_CPY(dof_matrix->dirichlet_bndry, elsii->dirichlet_bndry); use_get_bound = !BNDRY_FLAGS_IS_INTERIOR(dof_matrix->dirichlet_bndry); if (use_get_bound) { bound = get_el_schar_vec(elsii->row_fe_space->bas_fcts); } TRAVERSE_FIRST(dof_matrix->row_fe_space->mesh, -1, elsii->fill_flag|CALL_LEAF_EL|FILL_COORDS) { if (elsii->el_update_fct(el_info, tau, theta, elsii) == INIT_EL_TAG_NULL) { continue; } row_dof = get_dof_indices(NULL, f_h->fe_space, el_info->el); if (elsii->row_fe_space != elsii->col_fe_space) { col_dof = get_dof_indices(NULL, elsii->col_fe_space, el_info->el); } else { col_dof = row_dof; } if (use_get_bound) { bndry_bits = get_bound(NULL, row_bfcts, el_info); dirichlet_map(bound, bndry_bits, dof_matrix->dirichlet_bndry); } add_element_matrix(dof_matrix, 1.0, elsii->el_matrix, NoTranspose, row_dof, col_dof, bound); add_element_vec_dow(f_h, 1.0, elsii->el_load, row_dof, bound); } TRAVERSE_NEXT(); if (use_get_bound) { free_el_schar_vec(bound); } }