def test_2D_cartesian_recovery(geometry, element, mesh, expr): family = "RTCF" if element == "quadrilateral" else "BDM" # horizontal base spaces cell = mesh.ufl_cell().cellname() # DG1 DG1_elt = FiniteElement("DG", cell, 1, variant="equispaced") DG1 = FunctionSpace(mesh, DG1_elt) vec_DG1 = VectorFunctionSpace(mesh, DG1_elt) # spaces DG0 = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) Vu = FunctionSpace(mesh, family, 1) vec_CG1 = VectorFunctionSpace(mesh, "CG", 1) # our actual theta and rho and v rho_CG1_true = Function(CG1).interpolate(expr) v_CG1_true = Function(vec_CG1).interpolate(as_vector([expr, expr])) # make the initial fields by projecting expressions into the lowest order spaces rho_DG0 = Function(DG0).interpolate(expr) rho_CG1 = Function(CG1) v_Vu = Function(Vu).project(as_vector([expr, expr])) v_CG1 = Function(vec_CG1) # make the recoverers and do the recovery rho_recoverer = Recoverer(rho_DG0, rho_CG1, VDG=DG1, boundary_method=Boundary_Method.dynamics) v_recoverer = Recoverer(v_Vu, v_CG1, VDG=vec_DG1, boundary_method=Boundary_Method.dynamics) rho_recoverer.project() v_recoverer.project() rho_diff = errornorm(rho_CG1, rho_CG1_true) / norm(rho_CG1_true) v_diff = errornorm(v_CG1, v_CG1_true) / norm(v_CG1_true) tolerance = 1e-7 error_message = (""" Incorrect recovery for {variable} with {boundary} boundary method on {geometry} 2D Cartesian plane with {element} elements """) assert rho_diff < tolerance, error_message.format(variable='rho', boundary='dynamics', geometry=geometry, element=element) assert v_diff < tolerance, error_message.format(variable='v', boundary='dynamics', geometry=geometry, element=element)
def setup_2d_recovery(dirname): L = 100. W = 100. deltax = L / 5. deltay = W / 5. ncolumnsx = int(L / deltax) ncolumnsy = int(W / deltay) mesh = PeriodicRectangleMesh(ncolumnsx, ncolumnsy, L, W, direction='y', quadrilateral=True) x, y = SpatialCoordinate(mesh) # spaces VDG0 = FunctionSpace(mesh, "DG", 0) VCG1 = FunctionSpace(mesh, "CG", 1) VDG1 = FunctionSpace(mesh, "DG", 1) Vu = FunctionSpace(mesh, "RTCF", 1) VuCG1 = VectorFunctionSpace(mesh, "CG", 1) VuDG1 = VectorFunctionSpace(mesh, "DG", 1) # set up initial conditions np.random.seed(0) expr = np.random.randn() + np.random.randn() * x # our actual theta and rho and v rho_CG1_true = Function(VCG1).interpolate(expr) v_CG1_true = Function(VuCG1).interpolate(as_vector([expr, expr])) # make the initial fields by projecting expressions into the lowest order spaces rho_DG0 = Function(VDG0).interpolate(expr) rho_CG1 = Function(VCG1) v_Vu = Function(Vu).project(as_vector([expr, expr])) v_CG1 = Function(VuCG1) # make the recoverers and do the recovery rho_recoverer = Recoverer(rho_DG0, rho_CG1, VDG=VDG1, boundary_method=Boundary_Method.dynamics) v_recoverer = Recoverer(v_Vu, v_CG1, VDG=VuDG1, boundary_method=Boundary_Method.dynamics) rho_recoverer.project() v_recoverer.project() rho_diff = errornorm(rho_CG1, rho_CG1_true) / norm(rho_CG1_true) v_diff = errornorm(v_CG1, v_CG1_true) / norm(v_CG1_true) return (rho_diff, v_diff)
def test_scalar_diffusion(tmpdir, DG, tracer_setup): setup = tracer_setup(tmpdir, geometry="slice", blob=True) state = setup.state f_init = setup.f_init tmax = setup.tmax tol = 5.e-2 kappa = 1. f_end_expr = (1 / (1 + 4 * tmax)) * f_init**(1 / (1 + 4 * tmax)) if DG: V = state.spaces("DG", "DG", 1) else: V = state.spaces("theta", degree=1) mu = 5. diffusion_params = DiffusionParameters(kappa=kappa, mu=mu) eqn = DiffusionEquation(state, V, "f", diffusion_parameters=diffusion_params) diffusion_scheme = [(eqn, BackwardEuler(state))] state.fields("f").interpolate(f_init) f_end = run(state, diffusion_scheme, tmax) assert errornorm(f_end_expr, f_end) < tol
def test_1D_recovery(geometry, mesh, expr): # horizontal base spaces cell = mesh.ufl_cell().cellname() # DG1 DG1_elt = FiniteElement("DG", cell, 1, variant="equispaced") DG1 = FunctionSpace(mesh, DG1_elt) # spaces DG0 = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) # our actual theta and rho and v rho_CG1_true = Function(CG1).interpolate(expr) # make the initial fields by projecting expressions into the lowest order spaces rho_DG0 = Function(DG0).interpolate(expr) rho_CG1 = Function(CG1) # make the recoverers and do the recovery rho_recoverer = Recoverer(rho_DG0, rho_CG1, VDG=DG1, boundary_method=Boundary_Method.dynamics) rho_recoverer.project() rho_diff = errornorm(rho_CG1, rho_CG1_true) / norm(rho_CG1_true) tolerance = 1e-7 error_message = (""" Incorrect recovery for {variable} with {boundary} boundary method on {geometry} 1D domain """) assert rho_diff < tolerance, error_message.format(variable='rho', boundary='dynamics', geometry=geometry)
def heat(n, deg, time_stages, stage_type="deriv", splitting=IA): N = 2**n msh = UnitIntervalMesh(N) params = { "snes_type": "ksponly", "ksp_type": "preonly", "mat_type": "aij", "pc_type": "lu" } V = FunctionSpace(msh, "CG", deg) x, = SpatialCoordinate(msh) t = Constant(0.0) dt = Constant(2.0 / N) uexact = exp(-t) * sin(pi * x) rhs = expand_derivatives(diff(uexact, t)) - div(grad(uexact)) butcher_tableau = GaussLegendre(time_stages) u = project(uexact, V) v = TestFunction(V) F = (inner(Dt(u), v) * dx + inner(grad(u), grad(v)) * dx - inner(rhs, v) * dx) bc = DirichletBC(V, Constant(0), "on_boundary") stepper = TimeStepper(F, butcher_tableau, t, dt, u, bcs=bc, solver_parameters=params, stage_type=stage_type, splitting=splitting) while (float(t) < 1.0): if (float(t) + float(dt) > 1.0): dt.assign(1.0 - float(t)) stepper.advance() t.assign(float(t) + float(dt)) return errornorm(uexact, u) / norm(uexact)
def test_solver_no_flow_region(): mesh = fd.Mesh("./2D_mesh.msh") no_flow = [2] no_flow_markers = [1] mesh = mark_no_flow_regions(mesh, no_flow, no_flow_markers) P2 = fd.VectorElement("CG", mesh.ufl_cell(), 1) P1 = fd.FiniteElement("CG", mesh.ufl_cell(), 1) TH = P2 * P1 W = fd.FunctionSpace(mesh, TH) (v, q) = fd.TestFunctions(W) # Stokes 1 w_sol1 = fd.Function(W) nu = fd.Constant(0.05) F = NavierStokesBrinkmannForm(W, w_sol1, nu, beta_gls=2.0) x, y = fd.SpatialCoordinate(mesh) u_mms = fd.as_vector( [sin(2.0 * pi * x) * sin(pi * y), sin(pi * x) * sin(2.0 * pi * y)]) p_mms = -0.5 * (u_mms[0]**2 + u_mms[1]**2) f_mms_u = (grad(u_mms) * u_mms + grad(p_mms) - 2.0 * nu * div(sym(grad(u_mms)))) f_mms_p = div(u_mms) F += -inner(f_mms_u, v) * dx - f_mms_p * q * dx bc1 = fd.DirichletBC(W.sub(0), u_mms, "on_boundary") bc2 = fd.DirichletBC(W.sub(1), p_mms, "on_boundary") bc_no_flow = InteriorBC(W.sub(0), fd.Constant((0.0, 0.0)), no_flow_markers) solver_parameters = {"ksp_max_it": 500, "ksp_monitor": None} problem1 = fd.NonlinearVariationalProblem(F, w_sol1, bcs=[bc1, bc2, bc_no_flow]) solver1 = NavierStokesBrinkmannSolver( problem1, options_prefix="navier_stokes", solver_parameters=solver_parameters, ) solver1.solve() u_sol, _ = w_sol1.split() u_mms_func = fd.interpolate(u_mms, W.sub(0)) error = fd.errornorm(u_sol, u_mms_func) assert error < 0.07
def run_solver(r): mesh = fd.UnitSquareMesh(2**r, 2**r) P2 = fd.VectorElement("CG", mesh.ufl_cell(), 1) P1 = fd.FiniteElement("CG", mesh.ufl_cell(), 1) TH = P2 * P1 W = fd.FunctionSpace(mesh, TH) (v, q) = fd.TestFunctions(W) # Stokes 1 w_sol1 = fd.Function(W) nu = fd.Constant(0.05) F = NavierStokesBrinkmannForm(W, w_sol1, nu, beta_gls=2.0) from firedrake import sin, grad, pi, sym, div, inner x, y = fd.SpatialCoordinate(mesh) u_mms = fd.as_vector( [sin(2.0 * pi * x) * sin(pi * y), sin(pi * x) * sin(2.0 * pi * y)]) p_mms = -0.5 * (u_mms[0]**2 + u_mms[1]**2) f_mms_u = (grad(u_mms) * u_mms + grad(p_mms) - 2.0 * nu * div(sym(grad(u_mms)))) f_mms_p = div(u_mms) F += -inner(f_mms_u, v) * dx - f_mms_p * q * dx bc1 = fd.DirichletBC(W.sub(0), u_mms, "on_boundary") bc2 = fd.DirichletBC(W.sub(1), p_mms, "on_boundary") solver_parameters = {"ksp_max_it": 200} problem1 = fd.NonlinearVariationalProblem(F, w_sol1, bcs=[bc1, bc2]) solver1 = NavierStokesBrinkmannSolver( problem1, options_prefix="navier_stokes", solver_parameters=solver_parameters, ) solver1.solve() u_sol, _ = w_sol1.split() fd.File("test_u_sol.pvd").write(u_sol) u_mms_func = fd.interpolate(u_mms, W.sub(0)) error = fd.errornorm(u_sol, u_mms_func) print(f"Error: {error}") return error
def test_cone_cg_2D(): mesh = fd.UnitSquareMesh(100, 100) V = fd.FunctionSpace(mesh, "CG", 1) radius = 0.2 x, y = fd.SpatialCoordinate(mesh) x_shift = 0.5 phi_init = ((x - x_shift) * (x - x_shift) + (y - 0.5) * (y - 0.5) - radius**2) phi0 = fd.Function(V).interpolate(phi_init) phi_pvd = fd.File("phi_reinit.pvd") reinit_solver = ReinitSolverCG(V) phin = reinit_solver.solve(phi0, iters=10) phi_pvd.write(phin) phi_solution = fd.interpolate( sqrt((x - x_shift) * (x - x_shift) + (y - 0.5) * (y - 0.5)) - radius, V, ) error_numeri = fd.errornorm(phin, phi_solution) print(f"error: {error_numeri}") assert error_numeri < 1e-4
def test_vector_diffusion(tmpdir, DG, tracer_setup): setup = tracer_setup(tmpdir, geometry="slice", blob=True) state = setup.state f_init = setup.f_init tmax = setup.tmax tol = 3.e-2 kappa = 1. f_end_expr = (1 / (1 + 4 * tmax)) * f_init**(1 / (1 + 4 * tmax)) kappa = Constant([[kappa, 0.], [0., kappa]]) if DG: V = VectorFunctionSpace(state.mesh, "DG", 1) else: V = state.spaces("HDiv", "CG", 1) f_init = as_vector([f_init, 0.]) f_end_expr = as_vector([f_end_expr, 0.]) mu = 5. diffusion_params = DiffusionParameters(kappa=kappa, mu=mu) eqn = DiffusionEquation(state, V, "f", diffusion_parameters=diffusion_params) if DG: state.fields("f").interpolate(f_init) else: state.fields("f").project(f_init) diffusion_scheme = [(eqn, BackwardEuler(state))] f_end = run(state, diffusion_scheme, tmax) assert errornorm(f_end_expr, f_end) < tol
'friction': 'manning', # I/O 'plot_bathymetry': True, 'plot_pvd': True, 'input_dir': inputdir, 'output_dir': outputdir, } op = BeachOptions(**kwargs) if os.getenv('REGRESSION_TEST') is not None: op.end_time = op.dt * op.dt_per_export swp = AdaptiveProblem(op) t1 = time.time() swp.solve_forward() t2 = time.time() if os.getenv('REGRESSION_TEST') is not None: sys.exit(0) print(t2 - t1) new_mesh = RectangleMesh(880, 20, 220, 10) bath = Function(FunctionSpace(new_mesh, "CG", 1)).project(swp.fwd_solutions_bathymetry[0]) bath_real = initialise_bathymetry(new_mesh, 'hydrodynamics_beach_bath_new_880') print('L2') print(fire.errornorm(bath, bath_real))
def setup_3d_recovery(dirname): L = 100. H = 10. W = 1. deltax = L / 5. deltay = W / 5. deltaz = H / 5. nlayers = int(H / deltaz) ncolumnsx = int(L / deltax) ncolumnsy = int(W / deltay) m = RectangleMesh(ncolumnsx, ncolumnsy, L, W, quadrilateral=True) mesh = ExtrudedMesh(m, layers=nlayers, layer_height=H / nlayers) x, y, z = SpatialCoordinate(mesh) # horizontal base spaces cell = mesh._base_mesh.ufl_cell().cellname() u_hori = FiniteElement("RTCF", cell, 1) w_hori = FiniteElement("DG", cell, 0) # vertical base spaces u_vert = FiniteElement("DG", interval, 0) w_vert = FiniteElement("CG", interval, 1) # build elements u_element = HDiv(TensorProductElement(u_hori, u_vert)) w_element = HDiv(TensorProductElement(w_hori, w_vert)) theta_element = TensorProductElement(w_hori, w_vert) v_element = u_element + w_element # spaces VDG0 = FunctionSpace(mesh, "DG", 0) VCG1 = FunctionSpace(mesh, "CG", 1) VDG1 = FunctionSpace(mesh, "DG", 1) Vt = FunctionSpace(mesh, theta_element) Vt_brok = FunctionSpace(mesh, BrokenElement(theta_element)) Vu = FunctionSpace(mesh, v_element) VuCG1 = VectorFunctionSpace(mesh, "CG", 1) VuDG1 = VectorFunctionSpace(mesh, "DG", 1) # set up initial conditions np.random.seed(0) expr = np.random.randn( ) + np.random.randn() * x + np.random.randn() * y + np.random.randn( ) * z + np.random.randn() * x * y + np.random.randn( ) * x * z + np.random.randn() * y * z + np.random.randn() * x * y * z # our actual theta and rho and v rho_CG1_true = Function(VCG1).interpolate(expr) theta_CG1_true = Function(VCG1).interpolate(expr) v_CG1_true = Function(VuCG1).interpolate(as_vector([expr, expr, expr])) rho_Vt_true = Function(Vt).interpolate(expr) # make the initial fields by projecting expressions into the lowest order spaces rho_DG0 = Function(VDG0).interpolate(expr) rho_CG1 = Function(VCG1) theta_Vt = Function(Vt).interpolate(expr) theta_CG1 = Function(VCG1) v_Vu = Function(Vu).project(as_vector([expr, expr, expr])) v_CG1 = Function(VuCG1) rho_Vt = Function(Vt) # make the recoverers and do the recovery rho_recoverer = Recoverer(rho_DG0, rho_CG1, VDG=VDG1, boundary_method=Boundary_Method.dynamics) theta_recoverer = Recoverer(theta_Vt, theta_CG1, VDG=VDG1, boundary_method=Boundary_Method.dynamics) v_recoverer = Recoverer(v_Vu, v_CG1, VDG=VuDG1, boundary_method=Boundary_Method.dynamics) rho_Vt_recoverer = Recoverer(rho_DG0, rho_Vt, VDG=Vt_brok, boundary_method=Boundary_Method.physics) rho_recoverer.project() theta_recoverer.project() v_recoverer.project() rho_Vt_recoverer.project() rho_diff = errornorm(rho_CG1, rho_CG1_true) / norm(rho_CG1_true) theta_diff = errornorm(theta_CG1, theta_CG1_true) / norm(theta_CG1_true) v_diff = errornorm(v_CG1, v_CG1_true) / norm(v_CG1_true) rho_Vt_diff = errornorm(rho_Vt, rho_Vt_true) / norm(rho_Vt_true) return (rho_diff, theta_diff, v_diff, rho_Vt_diff)
def unsaturated_hydrostatic_balance(state, theta_d, H, exner0=None, top=False, exner_boundary=Constant(1.0), max_outer_solve_count=40, max_inner_solve_count=20): """ Given vertical profiles for dry potential temperature and relative humidity compute hydrostatically balanced virtual potential temperature, dry density and water vapour profiles. The general strategy is to split up the solving into two steps: 1) finding rho to balance the theta profile 2) finding theta_v and r_v to get back theta_d and H We iteratively solve these steps until we (hopefully) converge to a solution. :arg state: The :class:`State` object. :arg theta_d: The initial dry potential temperature profile. :arg H: The relative humidity profile. :arg exner0: Optional function to put exner pressure into. :arg top: If True, set a boundary condition at the top, otherwise it will be at the bottom. :arg exner_boundary: The value of exner on the specified boundary. :arg max_outer_solve_count: Max number of iterations for outer loop of balance solver. :arg max_inner_solve_count: Max number of iterations for inner loop of balanace solver. """ theta0 = state.fields('theta') rho0 = state.fields('rho') mr_v0 = state.fields('vapour_mixing_ratio') # Calculate hydrostatic exner pressure Vt = theta0.function_space() Vr = rho0.function_space() R_d = state.parameters.R_d R_v = state.parameters.R_v epsilon = R_d / R_v VDG = state.spaces("DG") if any(deg > 2 for deg in VDG.ufl_element().degree()): logger.warning( "default quadrature degree most likely not sufficient for this degree element" ) # apply first guesses theta0.assign(theta_d * 1.01) mr_v0.assign(0.01) v_deg = Vr.ufl_element().degree()[1] if v_deg == 0: method = Boundary_Method.physics else: method = None rho_h = Function(Vr) rho_averaged = Function(Vt) Vt_broken = FunctionSpace(state.mesh, BrokenElement(Vt.ufl_element())) rho_recoverer = Recoverer(rho0, rho_averaged, VDG=Vt_broken, boundary_method=method) w_h = Function(Vt) delta = 1.0 # make expressions for determining mr_v0 exner = thermodynamics.exner_pressure(state.parameters, rho_averaged, theta0) p = thermodynamics.p(state.parameters, exner) T = thermodynamics.T(state.parameters, theta0, exner, mr_v0) r_v_expr = thermodynamics.r_v(state.parameters, H, T, p) # make expressions to evaluate residual exner_ev = thermodynamics.exner_pressure(state.parameters, rho_averaged, theta0) p_ev = thermodynamics.p(state.parameters, exner_ev) T_ev = thermodynamics.T(state.parameters, theta0, exner_ev, mr_v0) RH_ev = thermodynamics.RH(state.parameters, mr_v0, T_ev, p_ev) RH = Function(Vt) for i in range(max_outer_solve_count): # solve for rho with theta_vd and w_v guesses compressible_hydrostatic_balance(state, theta0, rho_h, top=top, exner_boundary=exner_boundary, mr_t=mr_v0, solve_for_rho=True) # damp solution rho0.assign(rho0 * (1 - delta) + delta * rho_h) # calculate averaged rho rho_recoverer.project() RH.assign(RH_ev) if errornorm(RH, H) < 1e-10: break # now solve for r_v for j in range(max_inner_solve_count): w_h.interpolate(r_v_expr) mr_v0.assign(mr_v0 * (1 - delta) + delta * w_h) # compute theta_vd theta0.assign(theta_d * (1 + mr_v0 / epsilon)) # test quality of solution by re-evaluating expression RH.assign(RH_ev) if errornorm(RH, H) < 1e-10: break if i == max_outer_solve_count: raise RuntimeError( 'Hydrostatic balance solve has not converged within %i' % i, 'iterations') if exner0 is not None: exner = thermodynamics.exner_pressure(state.parameters, rho0, theta0) exner0.interpolate(exner) # do one extra solve for rho compressible_hydrostatic_balance(state, theta0, rho0, top=top, exner_boundary=exner_boundary, mr_t=mr_v0, solve_for_rho=True)
def errornorm(uh, v): return fd.errornorm(uh, v)
def verify_spatial_order_of_accuracy(sim_module, manufactured_solution, meshes, norms, expected_orders, decimal_places, sim_kwargs={}, endtime=0., strong_residual=None, dirichlet_boundary_conditions=None, starttime=0., outfile=None, write_simulation_outputs=False): MMSVerificationSimulation = make_mms_verification_sim_class( sim_module=sim_module, manufactured_solution=manufactured_solution, write_simulation_outputs=write_simulation_outputs, strong_residual=strong_residual, mms_dirichlet_boundary_conditions=dirichlet_boundary_conditions) table = sapphire.table.Table( ("h", "cellcount", "dofcount", "errors", "spatial_orders")) print("") for mesh in meshes: h = mesh.cell_sizes((0., ) * mesh.geometric_dimension()) sim = MMSVerificationSimulation(mesh=mesh, **sim_kwargs) if sim.time_discrete_terms() is not None: # If time-dependent sim.states = sim.run(endtime=endtime) else: sim.solution = sim.solve() errors = [] w = manufactured_solution(sim) wh = sim.solution if type(w) is not type((0, )): w = (w, ) for w_i, wh_i, norm in zip(w, wh.split(), norms): if norm is not None: errors.append(fe.errornorm(w_i, wh_i, norm_type=norm)) else: errors.append(None) cellcount = mesh.topology.num_cells() dofcount = len(wh.vector().array()) table.append({ "h": h, "cellcount": cellcount, "dofcount": dofcount, "errors": errors }) if len(table) > 1: h, e = table.data["h"], table.data["errors"] log = math.log orders = [] for i in range(len(sim.solution.split())): if e[0][i] is None: orders.append(None) else: r = h[-2] / h[-1] orders.append(log(e[-2][i] / e[-1][i]) / log(r)) table.data["spatial_orders"][-1] = orders print(str(table)) print("Last observed spatial orders of accuracy are {}".format(orders)) if outfile: print("Writing convergence table to {}".format(outfile.name)) outfile.write(str(table)) for order, expected_order in zip(orders, expected_orders): if expected_order is None: continue order = round(order, decimal_places) expected_order = round(float(expected_order), decimal_places) if not (order == expected_order): raise ValueError( "\n" + "\tObserved order {} differs from\n".format(order) + "\texpected order {}".format(expected_order))
} # --- Create solver and copy initial solution ep = AdaptiveProblem(CosinePrescribedVelocityOptions(**kwargs)) ep.set_initial_condition() init_sol = ep.fwd_solutions_tracer[0].copy(deepcopy=True) init_norm = norm(init_sol) # --- Eulerian interpretation ep.solve_forward() final_sol_eulerian = ep.fwd_solutions_tracer[-1] relative_error_eulerian = abs(errornorm(init_sol, final_sol_eulerian)/init_norm) print_output("Relative error in Eulerian case: {:.2f}%".format(100*relative_error_eulerian)) # --- Lagrangian interpretation kwargs['approach'] = 'lagrangian' lp = AdaptiveProblem(CosinePrescribedVelocityOptions(**kwargs)) lp.set_initial_condition() init_sol = lp.fwd_solutions_tracer[0].copy(deepcopy=True) init_coords = lp.meshes[0].coordinates.dat.data.copy() lp.solve_forward() final_sol_lagrangian = lp.fwd_solutions_tracer[-1] final_coords = lp.meshes[-1].coordinates.dat.data final_coords[:] -= [10.0, 0.0] # TODO: Implement periodicity
def dump_diagnostics(self, t, failed=False): """ Dump the diagnostic values. :arg t: time. """ print(self.out_string, 't = %.3f' % t) self.data_file.variables['time'][self.t_idx:self.t_idx + 1] = t u = self.prognostic_variables.u if 'm' in self.prognostic_variables.fields.keys(): m = self.prognostic_variables.m elif 'm' in self.diagnostic_variables.fields.keys(): m = self.diagnostic_variables.fields['m'] alphasq = self.simulation_parameters['alphasq'][-1] Ld = self.simulation_parameters['Ld'][-1] periodic = self.simulation_parameters['periodic'][-1] # Need to evaluate periodic factor because we need a number from Firedrake constants periodic_factor = (1 - exp(-Ld / sqrt(alphasq))) periodic_factor = periodic_factor.evaluate(0, 0, 0, 0) for diagnostic in self.diagnostic_values: if failed: output = [[np.nan], [np.nan]] if diagnostic == 'mu' else np.nan elif diagnostic == 'energy': output = assemble( (dot(u, u) + alphasq * dot(u.dx(0), u.dx(0))) * dx) elif diagnostic == 'l2_m': output = norm(m, norm_type='L2') elif diagnostic == 'l2_u': output = norm(u, norm_type='L2') elif diagnostic == 'h1_u': output = norm(u, norm_type='H1') elif diagnostic == 'h1_m': output = norm(m, norm_type='H1') elif diagnostic == 'mass_m': output = assemble(m * dx) elif diagnostic == 'mass_m2': output = assemble(m * m * dx) elif diagnostic == 'mass_u': output = assemble(u * dx) elif diagnostic == 'min_u': output = 1 if norm(u_min, norm_type='L2') > 1e-10 else 0 elif diagnostic == 'max_jump_local': output = find_max(self.diagnostic_variables.fields['jump_du'], self.diagnostic_variables.coords)[0] elif diagnostic == 'max_jump_global': output = find_max( self.diagnostic_variables.fields['du'], self.diagnostic_variables.coords)[0] - find_min( self.diagnostic_variables.fields['du'], self.diagnostic_variables.coords)[0] elif diagnostic == 'max_du_loc': output = find_max(self.diagnostic_variables.fields['du'], self.diagnostic_variables.coords)[1] elif diagnostic == 'min_du_loc': output = find_min(self.diagnostic_variables.fields['du'], self.diagnostic_variables.coords)[1] elif diagnostic == 'max_du_smooth_loc': output = find_max( self.diagnostic_variables.fields['du_smooth'], self.diagnostic_variables.smooth_coords)[1] elif diagnostic == 'min_du_smooth_loc': output = find_min( self.diagnostic_variables.fields['du_smooth'], self.diagnostic_variables.smooth_coords)[1] elif diagnostic == 'max_du': output = np.max( self.diagnostic_variables.fields['du'].dat.data[:]) elif diagnostic == 'min_du': output = np.min( self.diagnostic_variables.fields['du'].dat.data[:]) elif diagnostic == 'mu': old_mu, alt_mu = find_mus( u, self.diagnostic_variables.fields['du'], self.diagnostic_variables.coords) output = [old_mu, alt_mu] elif diagnostic == 'a': output = self.diagnostic_variables.fields['a'].at( self.data_file['x'][:], tolerance=1e-6) elif diagnostic == 'b': output = self.diagnostic_variables.fields['b'].at( self.data_file['x'][:], tolerance=1e-6) elif diagnostic == 'l2_kdv_1': output = norm(self.diagnostic_variables.fields['kdv_1'], norm_type='L2') elif diagnostic == 'l2_kdv_2': output = norm(self.diagnostic_variables.fields['kdv_2'], norm_type='L2') elif diagnostic == 'l2_kdv_3': output = norm(self.diagnostic_variables.fields['kdv_3'], norm_type='L2') elif diagnostic == 'p_pde': if periodic: output = np.max(u.dat.data[:]) * periodic_factor else: output = np.max(u.dat.data[:]) elif diagnostic == 'q_pde': output = self.diagnostic_variables.coords.dat.data[np.argmax( u.dat.data[:])] elif diagnostic == 'm_max': output = np.max(m.dat.data[:]) elif diagnostic == 'E_0': # use the calculated du du = self.diagnostic_variables.fields['du'] output = assemble(0.5 * (u**2 + alphasq * du**2) * dx) elif diagnostic == 'E_1': # just straightforwardly use u output = assemble(0.5 * (u**2 + alphasq * u.dx(0)**2) * dx) elif diagnostic == 'E_2': # use m output = assemble(0.5 * u * m * dx) elif diagnostic == 'E_3': # solve for uxx u_xx = self.diagnostic_variables.fields['u_xx'] output = assemble(0.5 * u * (u + alphasq * u_xx) * dx) elif diagnostic == 'u_error_with_sde': u_hat = self.diagnostic_variables.fields['u_sde'] output = errornorm(u, u_hat) elif diagnostic == 'u_error_weak': u_hat_weak = self.diagnostic_variables.fields['u_sde_weak'] output = norm(u_hat_weak) elif diagnostic == 'u_error_with_sde_mean': u_hat = self.diagnostic_variables.fields['u_sde_mean'] output = errornorm(u, u_hat) elif diagnostic == 'u_error_weak_mean': u_hat_weak = self.diagnostic_variables.fields[ 'u_sde_weak_mean'] output = norm(u_hat_weak) elif diagnostic == 'u_field': output = u.dat.data[:] elif diagnostic == 'peakon_suite': output = peakon_diagnostics( u, self.diagnostic_variables.fields['du'], self.diagnostic_variables.coords) else: raise ValueError('Diagnostic %s not recgonised.' % diagnostic) if diagnostic in ('a', 'b'): self.data_file[diagnostic][[slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = output elif diagnostic == 'mu': # we cannot store arrays of mus, so have to do them each separately for i in range(4): if i < len(output[0]): # output[0] is the old mu, output[1] is the new mu self.data_file[diagnostic + '_' + str(i)][ [slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = output[0][i] self.data_file['alt_' + diagnostic + '_' + str(i)][ [slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = output[1][i] else: self.data_file[diagnostic + '_' + str(i)][ [slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = np.nan self.data_file['alt_' + diagnostic + '_' + str(i)][ [slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = np.nan elif diagnostic == 'peakon_suite': for peakon_diag in self.list_of_peakon_diagnostics: self.data_file[peakon_diag][ [slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = output[peakon_diag] else: self.data_file[diagnostic][[slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = output if self.peakon_equations is not None: self.data_file['p'][[slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = self.peakon_equations.p self.data_file['q'][[slice(self.t_idx, self.t_idx + 1)] + self.index_slices] = self.peakon_equations.q self.t_idx += 1
def verify_temporal_order_of_accuracy(sim_module, manufactured_solution, timestep_sizes, endtime, norms, expected_orders, decimal_places, sim_kwargs={}, starttime=0., strong_residual=None, dirichlet_boundary_conditions=None, outfile=None, write_simulation_outputs=False): MMSVerificationSimulation = make_mms_verification_sim_class( sim_module=sim_module, manufactured_solution=manufactured_solution, write_simulation_outputs=write_simulation_outputs, strong_residual=strong_residual, mms_dirichlet_boundary_conditions=dirichlet_boundary_conditions) table = sapphire.table.Table(("Delta_t", "errors", "temporal_orders")) print("") for timestep_size in timestep_sizes: sim = MMSVerificationSimulation(**sim_kwargs) assert (len(sim.solutions) > 1) sim.timestep_size = sim.timestep_size.assign(timestep_size) sim.time = sim.time.assign(starttime) sim.states = sim.run(endtime=endtime) errors = [] w = manufactured_solution(sim) wh = sim.solution if type(w) is not type((0, )): w = (w, ) for w_i, wh_i, norm in zip(w, wh.split(), norms): if norm is not None: errors.append(fe.errornorm(w_i, wh_i, norm_type=norm)) else: errors.append(None) table.append({"Delta_t": timestep_size, "errors": errors}) if len(table) > 1: Delta_t, e = table.data["Delta_t"], table.data["errors"] log = math.log orders = [] for i in range(len(sim.solution.split())): if e[0][i] is None: orders.append(None) else: r = Delta_t[-2] / Delta_t[-1] orders.append(log(e[-2][i] / e[-1][i]) / log(r)) table.data["temporal_orders"][-1] = orders print(str(table)) print("Last observed temporal orders of accuracy are {}".format(orders)) if outfile: print("Writing convergence table to {}".format(outfile.name)) outfile.write(str(table)) for order, expected_order in zip(orders, expected_orders): if expected_order is None: continue order = round(order, decimal_places) expected_order = round(float(expected_order), decimal_places) if not (order == expected_order): raise ValueError( "\n" + "\tObserved order {} differs from\n".format(order) + "\texpected order {}".format(expected_order))
def heat(butcher_tableau): N = 4 dt = Constant(1.0 / N) t = Constant(0.0) msh = UnitSquareMesh(N, N) deg = 2 V = FunctionSpace(msh, "CG", deg) x, y = SpatialCoordinate(msh) uexact = t * (x + y) rhs = expand_derivatives(diff(uexact, t)) - div(grad(uexact)) sols = [] luparams = { "mat_type": "aij", "snes_type": "ksponly", "ksp_type": "preonly", "pc_type": "lu" } ranaLD = { "mat_type": "aij", "snes_type": "ksponly", "ksp_type": "gmres", "ksp_monitor": None, "pc_type": "python", "pc_python_type": "irksome.RanaLD", "aux": { "pc_type": "fieldsplit", "pc_fieldsplit_type": "multiplicative" } } per_field = {"ksp_type": "preonly", "pc_type": "gamg"} for s in range(butcher_tableau.num_stages): ranaLD["fieldsplit_%s" % (s, )] = per_field ranaDU = { "mat_type": "aij", "snes_type": "ksponly", "ksp_type": "gmres", "ksp_monitor": None, "pc_type": "python", "pc_python_type": "irksome.RanaDU", "aux": { "pc_type": "fieldsplit", "pc_fieldsplit_type": "multiplicative" } } for s in range(butcher_tableau.num_stages): ranaLD["fieldsplit_%s" % (s, )] = per_field params = [luparams, ranaLD, ranaDU] for solver_parameters in params: F, u, bc = Fubc(V, uexact, rhs) stepper = TimeStepper(F, butcher_tableau, t, dt, u, bcs=bc, solver_parameters=solver_parameters) stepper.advance() sols.append(u) errs = [errornorm(sols[0], uu) for uu in sols[1:]] return numpy.max(errs)
def test_3D_cartesian_recovery(geometry, element, mesh, expr): family = "RTCF" if element == "quadrilateral" else "BDM" # horizontal base spaces cell = mesh._base_mesh.ufl_cell().cellname() u_hori = FiniteElement(family, cell, 1) w_hori = FiniteElement("DG", cell, 0) # vertical base spaces u_vert = FiniteElement("DG", interval, 0) w_vert = FiniteElement("CG", interval, 1) # build elements u_element = HDiv(TensorProductElement(u_hori, u_vert)) w_element = HDiv(TensorProductElement(w_hori, w_vert)) theta_element = TensorProductElement(w_hori, w_vert) v_element = u_element + w_element # DG1 DG1_hori = FiniteElement("DG", cell, 1, variant="equispaced") DG1_vert = FiniteElement("DG", interval, 1, variant="equispaced") DG1_elt = TensorProductElement(DG1_hori, DG1_vert) DG1 = FunctionSpace(mesh, DG1_elt) vec_DG1 = VectorFunctionSpace(mesh, DG1_elt) # spaces DG0 = FunctionSpace(mesh, "DG", 0) CG1 = FunctionSpace(mesh, "CG", 1) Vt = FunctionSpace(mesh, theta_element) Vt_brok = FunctionSpace(mesh, BrokenElement(theta_element)) Vu = FunctionSpace(mesh, v_element) vec_CG1 = VectorFunctionSpace(mesh, "CG", 1) # our actual theta and rho and v rho_CG1_true = Function(CG1).interpolate(expr) theta_CG1_true = Function(CG1).interpolate(expr) v_CG1_true = Function(vec_CG1).interpolate(as_vector([expr, expr, expr])) rho_Vt_true = Function(Vt).interpolate(expr) # make the initial fields by projecting expressions into the lowest order spaces rho_DG0 = Function(DG0).interpolate(expr) rho_CG1 = Function(CG1) theta_Vt = Function(Vt).interpolate(expr) theta_CG1 = Function(CG1) v_Vu = Function(Vu).project(as_vector([expr, expr, expr])) v_CG1 = Function(vec_CG1) rho_Vt = Function(Vt) # make the recoverers and do the recovery rho_recoverer = Recoverer(rho_DG0, rho_CG1, VDG=DG1, boundary_method=Boundary_Method.dynamics) theta_recoverer = Recoverer(theta_Vt, theta_CG1, VDG=DG1, boundary_method=Boundary_Method.dynamics) v_recoverer = Recoverer(v_Vu, v_CG1, VDG=vec_DG1, boundary_method=Boundary_Method.dynamics) rho_Vt_recoverer = Recoverer(rho_DG0, rho_Vt, VDG=Vt_brok, boundary_method=Boundary_Method.physics) rho_recoverer.project() theta_recoverer.project() v_recoverer.project() rho_Vt_recoverer.project() rho_diff = errornorm(rho_CG1, rho_CG1_true) / norm(rho_CG1_true) theta_diff = errornorm(theta_CG1, theta_CG1_true) / norm(theta_CG1_true) v_diff = errornorm(v_CG1, v_CG1_true) / norm(v_CG1_true) rho_Vt_diff = errornorm(rho_Vt, rho_Vt_true) / norm(rho_Vt_true) tolerance = 1e-7 error_message = (""" Incorrect recovery for {variable} with {boundary} boundary method on {geometry} 3D Cartesian domain with {element} elements """) assert rho_diff < tolerance, error_message.format(variable='rho', boundary='dynamics', geometry=geometry, element=element) assert v_diff < tolerance, error_message.format(variable='v', boundary='dynamics', geometry=geometry, element=element) assert theta_diff < tolerance, error_message.format(variable='rho', boundary='dynamics', geometry=geometry, element=element) assert rho_Vt_diff < tolerance, error_message.format(variable='rho', boundary='physics', geometry=geometry, element=element)
print(gamma) new_mesh = RectangleMesh(880, 20, 220, 10) bath = Function(FunctionSpace(new_mesh, "CG", 1)).project(swp.fwd_solutions_bathymetry[0]) fpath = "hydrodynamics_beach_bath_mov_{:d}_{:d}_{:d}_{:d}_{:d}" fpath = fpath.format(op.dt_per_export, int(fac_x * 220), alpha, beta, gamma) export_bathymetry(bath, os.path.join("adapt_output", fpath), op=op) bath_real = initialise_bathymetry( new_mesh, 'fixed_output/hydrodynamics_beach_bath_fixed_440_10') print('L2') print(fire.errornorm(bath, bath_real)) print(kappa) V = FunctionSpace(new_mesh, 'CG', 1) x, y = SpatialCoordinate(new_mesh) bath_mod = Function(V).interpolate(conditional(x > 70, bath, Constant(0.0))) bath_real_mod = Function(V).interpolate( conditional(x > 70, bath_real, Constant(0.0))) print('subdomain') print(fire.errornorm(bath_mod, bath_real_mod)) print('tolerance value')
cg_ilu_params['ksp_monitor_true_residual'] = None rho_solver = LinearVariationalSolver(rho_problem, solver_parameters=cg_ilu_params) max_outer_solve_count = 20 max_inner_solve_count = 10 PETSc.Sys.Print("Starting rho solver loop...\n") for i in range(max_outer_solve_count): # calculate averaged rho rho_recoverer.project() RH.assign(RH_ev) if errornorm(RH, H) < 1e-10: break # first solve for r_v for j in range(max_inner_solve_count): w_h.interpolate(r_v_expr) water_v0.assign(water_v0 * (1 - delta) + delta * w_h) # compute theta_vd theta0.assign(theta_d * (1 + water_v0 / epsilon)) # test quality of solution by re-evaluating expression RH.assign(RH_ev) if errornorm(RH, H) < 1e-10: break
# increase dt until error > error_threshold while error < error_threshold: # error < error_threshold so increase dt by small amount dt = dt + step # NB: prolong does not copy so we must re-assign ref sol. fine = Function(V_fine).assign(ref) # Run the simulation with this dt try: sol = solver_CG(mesh, el=cell_type, space=space, deg=degree, T=0.50, dt=dt) error = errornorm(ref, prolong(sol, fine)) except Exception: # numerical instability occurred, exit with last stable dt dt = dt - step error = 1e10 print( "For degree {}, the error is {} using a {} s timestep".format( degree, error, dt)) # error > error_threshold, print( "Highest stable dt is {} s for a degree {} for a an error threshold of {}" .format(dt, degree, error_threshold)) dts[i, j] = dt print("------FINISHED------") print(dts)
f.interpolate(fexpr) # Coriolis frequency (1/s) u0.project(uexpr) D0.interpolate(Dexpr) state.initialise([('u', u0), ('D', D0)]) ueqn = VectorInvariant(state, u0.function_space()) Deqn = AdvectionEquation(state, D0.function_space(), equation_form="continuity") advected_fields = [] advected_fields.append(("u", ThetaMethod(state, u0, ueqn))) advected_fields.append(("D", SSPRK3(state, D0, Deqn, subcycles=2))) linear_solver = ShallowWaterSolver(state) # Set up forcing sw_forcing = ShallowWaterForcing(state, euler_poincare=False) # build time stepper stepper = CrankNicolson(state, advected_fields, linear_solver, sw_forcing) stepper.run(t=0, tmax=tmax) xn = state.xn un, Dn = xn.split() uerr = errornorm(u0, un, norm_type="L2") Derr = errornorm(D0, Dn, norm_type="L2")
def verify_order_of_accuracy( discretization_parameter_name, discretization_parameter_values, Simulation, manufactured_solution, norms, points_in_rate_estimator=2, expected_orders=None, # a.k.a. convergence rates decimal_places=2, time_dependent=True, sim_kwargs={}, endtime=0., strong_residual=None, dirichlet_boundary_conditions=None, starttime=0., outfile=None, write_simulation_outputs=False): n = points_in_rate_estimator pname = discretization_parameter_name pvalues = discretization_parameter_values if n > 3: raise NotImplementedError("Max `points_in_rate_estimator` is 3.") if len(pvalues) < n: raise ValueError("There must be a discretization parameter value " "for each point in the rate estimation.") fieldcount = len(norms) if expected_orders: assert (len(expected_orders) == len(norms)) for pvalue in pvalues: if not pvalue > 0: raise ("`discretization_parameter_values` must be positive.") r = pvalues[0] / pvalues[1] # Refinement rate if r < 0: raise ("`discretization_parameter_values` must be " "a descending sequence.") if n > 2: for iv in range(1, len(pvalues)): if not numpy.isclose(pvalues[iv - 1] / pvalues[iv], r): raise ("`discretization_parameter_values` must be " "a geometric sequence when using more than two " "points in the rate estimator.") MMSVerificationSimulation = make_mms_verification_sim_class( Simulation=Simulation, manufactured_solution=manufactured_solution, write_simulation_outputs=write_simulation_outputs, strong_residual=strong_residual, mms_dirichlet_boundary_conditions=dirichlet_boundary_conditions) columns = [ pname, ] for i, norm in enumerate(norms): if norm is not None: columns += ["error{}".format(i), "order{}".format(i)] table = pandas.DataFrame(index=range(len(pvalues)), columns=columns) for iv, pval in enumerate(pvalues): table[pname][iv] = pval print() print(str(table).replace(" NaN", "None")) for iv, pval in enumerate(pvalues): sim_kwargs[pname] = pval sim = MMSVerificationSimulation(**sim_kwargs) wh = sim.solution assert (len(wh.split()) == fieldcount) if time_dependent: sim.states = sim.run(endtime=endtime) else: sim.solution = sim.solve() w = manufactured_solution(sim) if type(w) is not tuple: w = (w, ) for iw, w_i, wh_i, norm in zip(range(fieldcount), w, wh.split(), norms): if norm is not None: table["error{}".format(iw)][iv] = fe.errornorm(w_i, wh_i, norm_type=norm) if iv >= (n - 1): h = table[pname] log = math.log for iw in range(fieldcount): if norms[iw] is not None: e = table["error{}".format(iw)] if n == 2: order = log(e[iv - 1] / e[iv]) / log(r) elif n == 3: order = log((e[iv - 2] - e[iv - 1]) / (e[iv - 1] - e[iv])) / log(r) table["order{}".format(iw)][iv] = order print() print(str(table).replace(" NaN", "None")) if outfile: print("Writing convergence table to {}".format(outfile.name)) outfile.write(table.to_csv()) if expected_orders: for iorder, expected_order in enumerate(expected_orders): if expected_order is not None: order = table.iloc[-1]["order{}".format(iorder)] order = round(order, decimal_places) expected_order = round(float(expected_order), decimal_places) if not (order == expected_order): raise ValueError( "\n" + "\tObserved order {} differs from\n".format(order) + "\texpected order {}".format(expected_order)) print() print("Formatted for LaTeX:") print(format_for_latex(table, norms=norms)) return table
def saturated_hydrostatic_balance(state, theta_e, mr_t, exner0=None, top=False, exner_boundary=Constant(1.0), max_outer_solve_count=40, max_theta_solve_count=5, max_inner_solve_count=3): """ Given a wet equivalent potential temperature, theta_e, and the total moisture content, mr_t, compute a hydrostatically balance virtual potential temperature, dry density and water vapour profile. The general strategy is to split up the solving into two steps: 1) finding rho to balance the theta profile 2) finding theta_v and r_v to get back theta_e and saturation We iteratively solve these steps until we (hopefully) converge to a solution. :arg state: The :class:`State` object. :arg theta_e: The initial wet equivalent potential temperature profile. :arg mr_t: The total water pseudo-mixing ratio profile. :arg exner0: Optional function to put exner pressure into. :arg top: If True, set a boundary condition at the top, otherwise it will be at the bottom. :arg exner_boundary: The value of exner on the specified boundary. :arg max_outer_solve_count: Max number of outer iterations for balance solver. :arg max_theta_solve_count: Max number of iterations for theta solver (middle part of solve). :arg max_inner_solve_count: Max number of iterations on the inner most loop for the water vapour solver. """ theta0 = state.fields('theta') rho0 = state.fields('rho') mr_v0 = state.fields('vapour_mixing_ratio') # Calculate hydrostatic exner pressure Vt = theta0.function_space() Vr = rho0.function_space() VDG = state.spaces("DG") if any(deg > 2 for deg in VDG.ufl_element().degree()): logger.warning( "default quadrature degree most likely not sufficient for this degree element" ) theta0.interpolate(theta_e) mr_v0.interpolate(mr_t) v_deg = Vr.ufl_element().degree()[1] if v_deg == 0: boundary_method = Boundary_Method.physics else: boundary_method = None rho_h = Function(Vr) Vt_broken = FunctionSpace(state.mesh, BrokenElement(Vt.ufl_element())) rho_averaged = Function(Vt) rho_recoverer = Recoverer(rho0, rho_averaged, VDG=Vt_broken, boundary_method=boundary_method) w_h = Function(Vt) theta_h = Function(Vt) theta_e_test = Function(Vt) delta = 0.8 # expressions for finding theta0 and mr_v0 from theta_e and mr_t exner = thermodynamics.exner_pressure(state.parameters, rho_averaged, theta0) p = thermodynamics.p(state.parameters, exner) T = thermodynamics.T(state.parameters, theta0, exner, mr_v0) r_v_expr = thermodynamics.r_sat(state.parameters, T, p) theta_e_expr = thermodynamics.theta_e(state.parameters, T, p, mr_v0, mr_t) for i in range(max_outer_solve_count): # solve for rho with theta_vd and w_v guesses compressible_hydrostatic_balance(state, theta0, rho_h, top=top, exner_boundary=exner_boundary, mr_t=mr_t, solve_for_rho=True) # damp solution rho0.assign(rho0 * (1 - delta) + delta * rho_h) theta_e_test.assign(theta_e_expr) if errornorm(theta_e_test, theta_e) < 1e-8: break # calculate averaged rho rho_recoverer.project() # now solve for r_v for j in range(max_theta_solve_count): theta_h.interpolate(theta_e / theta_e_expr * theta0) theta0.assign(theta0 * (1 - delta) + delta * theta_h) # break when close enough if errornorm(theta_e_test, theta_e) < 1e-6: break for k in range(max_inner_solve_count): w_h.interpolate(r_v_expr) mr_v0.assign(mr_v0 * (1 - delta) + delta * w_h) # break when close enough theta_e_test.assign(theta_e_expr) if errornorm(theta_e_test, theta_e) < 1e-6: break if i == max_outer_solve_count: raise RuntimeError( 'Hydrostatic balance solve has not converged within %i' % i, 'iterations') if exner0 is not None: exner = thermodynamics.exner(state.parameters, rho0, theta0) exner0.interpolate(exner) # do one extra solve for rho compressible_hydrostatic_balance(state, theta0, rho0, top=top, exner_boundary=exner_boundary, mr_t=mr_t, solve_for_rho=True)
def main(): # make function space and function dim = 2 # 2 or 3 order = 1 logger.info(f"building {dim}D source and solution exprs") if dim == 2: m = UnitSquareMesh(32, 32) elif dim == 3: m = UnitCubeMesh(16, 16, 16) else: raise ValueError("dim must be 2 or 3, not %s" % dim) # get spatial coordinate, shifted so that [0,1]^2 -> [-0.5,0.5]^2 xx = SpatialCoordinate(m) shifted_xx = as_tensor([xx_i - 0.5 for xx_i in xx]) norm2 = sum([xx_i * xx_i for xx_i in shifted_xx]) alpha = 10 source_expr = -(4 * alpha**2 * norm2 - 2 * dim * alpha) * exp( -alpha * norm2) sol_expr = exp(-alpha * norm2) logger.info("source_expr : %s" % source_expr) logger.info("sol_expr : %s" % sol_expr) logger.info(f"Building FunctionSpace of order {order}") fspace = FunctionSpace(m, 'DG', order) logger.info("interpolating source and solution") source = Function(fspace).interpolate(source_expr) sol = Function(fspace).interpolate(sol_expr) from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(m.geometric_dimension()) # We could set to a custom group factory if we wanted to, # defaults to recursive nodes with 'lgl' nodes # # from meshmode.discretization.poly_element import ( # PolynomialWarpAndBlendGroupFactory) # grp_factory = PolynomialWarpAndBlendGroupFactory(order) grp_factory = None # Build VolumePotential external operator cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) potential_data = { 'kernel': kernel, 'kernel_type': "Laplace", 'cl_ctx': cl_ctx, 'queue': queue, 'nlevels': 6, 'm_order': 20, 'dataset_filename': f"laplace-order{order}-{dim}D.hdf5", 'grp_factory': grp_factory, 'root_extent': 2, 'table_compute_method': "DrosteSum", 'table_kwargs': { 'force_recompute': False, 'n_brick_quad_points': 100, 'adaptive_level': False, 'use_symmetry': True, 'alpha': 0.1, 'nlevels': 15, }, 'fmm_kwargs': {}, } logger.info("Creating volume potential") # pot = VolumePotential(source, function_space=source.function_space(), operator_data=potential_data) # logger.info("Evaluating potential and assembling L^2 Error") # ell2_difference = sqrt(assemble(inner(pot - sol, pot - sol) * dx)) # print("L^2 difference: %e" % ell2_difference) print("interpolation error: %e" % errornorm(sol_expr, sol))