def p_convergence(config: ConfigParser, solver: Solver, sol: GridFunction, var: str) -> None: """ Function to check p (interpolat polynomial order) convergence and print results. Args: config: Config file from which to grab solver: The solver used sol: Gridfunction that contains the current solution var: The variable of interest. """ num_refinements = config.get_item(['ERROR ANALYSIS', 'num_refinements'], int) average_lst = config.get_list(['ERROR ANALYSIS', 'error_average'], str, quiet=True) component = solver.model.model_components[var] average = component in average_lst # Reload the model's mesh and finite element space so convergence tests can be chained and don't affect each other. solver.model.load_mesh_fes(mesh=True, fes=True) # First solve used the default settings. if component is None: err = norm('l2_norm', sol, solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes, average) else: err = norm('l2_norm', sol.components[component], solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes.components[component], average) # Track the convergence information. num_dofs_lst = [solver.model.fes.ndof] interp_ord_lst = [solver.model.interp_ord[var]] error_lst = [err] # Then run through a series of interpolant refinements. for n in range(num_refinements): solver.model.interp_ord = {key: val + 1 for key, val in solver.model.interp_ord.items()} solver.model.load_mesh_fes(mesh=False, fes=True) solver.reset_model() sol = solver.solve() if component is None: err = norm('l2_norm', sol, solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes, average) else: err = norm('l2_norm', sol.components[component], solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes.components[component], average) num_dofs_lst.append(solver.model.fes.ndof) interp_ord_lst.append(solver.model.interp_ord[var]) error_lst.append(err) print('L2 norm at refinement {0}: {1}'.format(n, err)) # Display the results nicely. convergence_table = [['Interpolant Order', 'DOFs', 'Error', 'Convergence Rate']] convergence_table.append([interp_ord_lst[0], num_dofs_lst[0], error_lst[0], 0]) for n in range(num_refinements): # TODO: Not sure if this is the correct equation for p-convergence. convergence_rate = math.log(error_lst[n] / error_lst[n + 1]) / math.log(num_dofs_lst[n + 1] / num_dofs_lst[n]) convergence_table.append([interp_ord_lst[n + 1], num_dofs_lst[n + 1], error_lst[n + 1], convergence_rate]) print(tabulate.tabulate(convergence_table, headers='firstrow', floatfmt=['.1f', '.1f', '.3e', '.2f']))
def h_convergence(config: ConfigParser, solver: Solver, sol: GridFunction, var: str) -> None: """ Function to check h (mesh element size) convergence and print results. Args: config: Config file from which to grab solver: The solver used sol: Gridfunction that contains the current solution var: The variable of interest. """ num_refinements = config.get_item(['ERROR ANALYSIS', 'num_refinements'], int) average_lst = config.get_list(['ERROR ANALYSIS', 'error_average'], str, quiet=True) component = solver.model.model_components[var] average = component in average_lst # Reload the model's mesh and finite element space so convergence tests can be chained and don't affect each other. solver.model.load_mesh_fes(mesh=True, fes=True) # First solve used the default settings. if component is None: err = norm('l2_norm', sol, solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes, average) else: err = norm('l2_norm', sol.components[component], solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes.components[component], average) # Track the convergence information. num_dofs_lst = [solver.model.fes.ndof] error_lst = [err] # Then run through a series of mesh refinements and resolve on each # refined mesh. for n in range(num_refinements): solver.model.mesh.Refine() solver.model.fes.Update() solver.reset_model() sol = solver.solve() if component is None: err = norm('l2_norm', sol, solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes, average) else: err = norm('l2_norm', sol.components[component], solver.model.ref_sol['ref_sols'][var], solver.model.mesh, solver.model.fes.components[component], average) num_dofs_lst.append(solver.model.fes.ndof) error_lst.append(err) print('L2 norm at refinement {0}: {1}'.format(n, err)) # Display the results nicely. convergence_table = [['Refinement Level', 'DOFs', 'Error', 'Convergence Rate']] convergence_table.append([1, num_dofs_lst[0], error_lst[0], 0]) for n in range(num_refinements): ref_level = '1/{}'.format(int(2 ** (n + 1))) convergence_rate = math.log(error_lst[n] / error_lst[n + 1]) / \ (math.log(num_dofs_lst[n + 1] / (num_dofs_lst[n] * 2.0 ** (solver.model.mesh.dim - 1)))) convergence_table.append([ref_level, num_dofs_lst[n + 1], error_lst[n + 1], convergence_rate]) print(tabulate.tabulate(convergence_table, headers='firstrow', floatfmt=('.1f', '.1f', '.3e', '.2f')))