def test_assign(): c0 = Constant(1.) assert c0.values() == (1,) c0.assign(Constant(3)) assert c0.values() == (3,) c1 = Constant([1, 2]) assert (c1.values() == (1, 2)).all() c1.assign(Constant([3, 4])) assert (c1.values() == (3, 4)).all()
def _product(thetas: ThetaType, operators: tuple_of(Form)): try: output = _product_forms_output_cache[operators] except KeyError: # Keep the operators as Forms and delay assembly as long as possible output = 0 constants = list() for (theta, operator) in zip(thetas, operators): theta = float(theta) constant = Constant(theta) output += constant * operator constants.append(constant) output = ProductOutput(output) _product_forms_output_cache[operators] = output _product_forms_constants_cache[operators] = constants return output else: constants = _product_forms_constants_cache[operators] for (theta, constant) in zip(thetas, constants): theta = float(theta) constant.assign(theta) return output
def test_unsteady_stokes(): nx, ny = 15, 15 k = 1 nu = Constant(1.0e-0) dt = Constant(2.5e-2) num_steps = 20 theta0 = 1.0 # Initial theta value theta1 = 0.5 # Theta after 1 step theta = Constant(theta0) mesh = UnitSquareMesh(nx, ny) # The 'unsteady version' of the benchmark in the 2012 paper by Labeur&Wells u_exact = Expression( ( "sin(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ -6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-sin(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), t=0, degree=7, domain=mesh, ) p_exact = Expression("sin(t) * x[0]*(1.0 - x[0])", t=0, degree=7, domain=mesh) du_exact = Expression( ( "cos(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-cos(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ -6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), t=0, degree=7, domain=mesh, ) ux_exact = Expression( ( "x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])", ), degree=7, domain=mesh, ) px_exact = Expression("x[0]*(1.0 - x[0])", degree=7, domain=mesh) sin_ext = Expression("sin(t)", t=0, degree=7, domain=mesh) f = du_exact + sin_ext * div(px_exact * Identity(2) - 2 * sym(grad(ux_exact))) Vhigh = VectorFunctionSpace(mesh, "DG", 7) Phigh = FunctionSpace(mesh, "DG", 7) # New syntax: V = VectorElement("DG", mesh.ufl_cell(), k) Q = FiniteElement("DG", mesh.ufl_cell(), k - 1) Vbar = VectorElement("DGT", mesh.ufl_cell(), k) Qbar = FiniteElement("DGT", mesh.ufl_cell(), k) mixedL = FunctionSpace(mesh, MixedElement([V, Q])) mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar])) V2 = FunctionSpace(mesh, V) Uh = Function(mixedL) Uhbar = Function(mixedG) U0 = Function(mixedL) Uhbar0 = Function(mixedG) u0, p0 = split(U0) ubar0, pbar0 = split(Uhbar0) ustar = Function(V2) # Then the boundary conditions bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma) bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise") bcs = [bc0, bc1] alpha = Constant(6 * k * k) forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha).forms_unsteady(ustar, dt, nu, f) ssc = StokesStaticCondensation( mesh, forms_stokes["A_S"], forms_stokes["G_S"], forms_stokes["G_ST"], forms_stokes["B_S"], forms_stokes["Q_S"], forms_stokes["S_S"], ) t = 0.0 step = 0 for step in range(num_steps): step += 1 t += float(dt) if comm.Get_rank() == 0: print("Step " + str(step) + " Time " + str(t)) # Set time level in exact solution u_exact.t = t p_exact.t = t du_exact.t = t - (1 - float(theta)) * float(dt) sin_ext.t = t - (1 - float(theta)) * float(dt) ssc.assemble_global_lhs() ssc.assemble_global_rhs() for bc in bcs: ssc.apply_boundary(bc) ssc.solve_problem(Uhbar, Uh, "none", "default") assign(U0, Uh) assign(ustar, U0.sub(0)) assign(Uhbar0, Uhbar) if step == 1: theta.assign(theta1) udiv_e = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0)) * dx)) u_ex_h = interpolate(u_exact, Vhigh) p_ex_h = interpolate(p_exact, Phigh) u_error = sqrt(assemble(dot(Uh.sub(0) - u_ex_h, Uh.sub(0) - u_ex_h) * dx)) p_error = sqrt(assemble(dot(Uh.sub(1) - p_ex_h, Uh.sub(1) - p_ex_h) * dx)) assert udiv_e < 1e-12 assert u_error < 1.5e-4 assert p_error < 1e-2
class VariableDensityModel(MultiPhaseModel): description = 'A variable density DG transport equation model' def __init__(self, simulation): """ A variable density scheme solving D/Dt(rho)=0 with a constant kinematic vosicsity nu and a variable dynamic visocisty mu (depending on rho) """ self.simulation = simulation simulation.log.info('Creating variable density multiphase model') # Define function space and solution function V = simulation.data['Vrho'] self.rho = simulation.data['rho'] = Function(V) self.rho_p = simulation.data['rho_p'] = Function(V) self.rho_pp = simulation.data['rho_pp'] = Function(V) # Get the physical properties inp = simulation.input self.rho_min = inp.get_value('physical_properties/rho_min', required_type='float') self.rho_max = inp.get_value('physical_properties/rho_max', required_type='float') self.nu = inp.get_value('physical_properties/nu', required_type='float') # Create the equations when the simulation starts simulation.hooks.add_pre_simulation_hook( self.on_simulation_start, 'VariableDensityModel setup equations') # Update the rho and nu fields before each time step simulation.hooks.add_pre_timestep_hook( self.update, 'VariableDensityModel - update density field') simulation.hooks.register_custom_hook_point('MultiPhaseModelUpdated') self.use_analytical_solution = inp.get_value( 'multiphase_solver/analytical_solution', False, 'bool') self.use_rk_method = inp.get_value( 'multiphase_solver/explicit_rk_method', False, 'bool') self.is_first_timestep = True @classmethod def create_function_space(cls, simulation): mesh = simulation.data['mesh'] cd = simulation.data['constrained_domain'] Vr_name = simulation.input.get_value( 'multiphase_solver/function_space_rho', 'Discontinuous Lagrange', 'string') Pr = simulation.input.get_value( 'multiphase_solver/polynomial_degree_rho', 1, 'int') Vrho = dolfin.FunctionSpace(mesh, Vr_name, Pr, constrained_domain=cd) simulation.data['Vrho'] = Vrho simulation.ndofs += Vrho.dim() def on_simulation_start(self): """ This runs when the simulation starts. It does not run in __init__ since the N-S solver needs the density and viscosity we define, and we need the velocity that is defined by the solver """ if self.use_analytical_solution: return sim = self.simulation dirichlet_bcs = sim.data['dirichlet_bcs'].get('rho', []) if self.use_rk_method: V = self.simulation.data['Vrho'] if not V.ufl_element().family() == 'Discontinuous Lagrange': ocellaris_error( 'VariableDensity timestepping error', 'Can only use explicit SSP Runge-Kutta method with DG space for rho', ) Vu = sim.data['Vu'] u_conv, self.funcs_to_extrapolate = [], [] for d in range(sim.ndim): ux = Function(Vu) up = sim.data['up_conv%d' % d] upp = sim.data['upp_conv%d' % d] self.funcs_to_extrapolate.append((ux, up, upp)) u_conv.append(ux) u_conv = dolfin.as_vector(u_conv) from dolfin import dot, div, jump, dS mesh = self.simulation.data['mesh'] re = self.rho_explicit = dolfin.Function(V) c, d = dolfin.TrialFunction(V), dolfin.TestFunction(V) n = dolfin.FacetNormal(mesh) w_nD = (dot(u_conv, n) - abs(dot(u_conv, n))) / 2 dx = dolfin.dx(domain=mesh) eq = c * d * dx # Convection integrated by parts two times to bring back the original # div form (this means we must subtract and add all fluxes) eq += div(re * u_conv) * d * dx # Replace downwind flux with upwind flux on downwind internal facets eq -= jump(w_nD * d) * jump(re) * dS # Replace downwind flux with upwind BC flux on downwind external facets for dbc in dirichlet_bcs: # Subtract the "normal" downwind flux eq -= w_nD * re * d * dbc.ds() # Add the boundary value upwind flux eq += w_nD * dbc.func() * d * dbc.ds() a, L = dolfin.system(eq) self.rk = RungeKuttaDGTimestepping( self.simulation, a, L, self.rho, self.rho_explicit, 'rho', order=None, explicit_funcs=self.funcs_to_extrapolate, bcs=dirichlet_bcs, ) else: # Use backward Euler (BDF1) for timestep 1 self.time_coeffs = Constant([1, -1, 0]) if dolfin.norm(self.rho_pp.vector()) > 0: # Use BDF2 from the start self.time_coeffs.assign(Constant([3 / 2, -2, 1 / 2])) self.simulation.log.info( 'Using second order timestepping from the start in VariableDensity' ) # Define equation for advection of the density # ∂ρ/∂t + ∇⋅(ρ u) = 0 beta = None u_conv = sim.data['u_conv'] forcing_zones = sim.data['forcing_zones'].get('rho', []) self.eq = AdvectionEquation( sim, sim.data['Vrho'], self.rho_p, self.rho_pp, u_conv, beta, self.time_coeffs, dirichlet_bcs, forcing_zones, ) self.solver = linear_solver_from_input(sim, 'solver/rho', SOLVER, PRECONDITIONER, None, KRYLOV_PARAMETERS) self.slope_limiter = SlopeLimiter(sim, 'rho', self.rho) self.slope_limiter.set_phi_old(self.rho_p) # Make sure the initial value is included in XDMF results from timestep 0 self.rho.assign(self.rho_p) def get_density(self, k): """ Return the function as defined on timestep t^{n+k} """ if k == 0: return self.rho elif k == -1: return self.rho_p elif k == -2: return self.rho_pp def get_laminar_kinematic_viscosity(self, k): """ It is assumed that the kinematic viscosity is constant """ return Constant(self.nu) def get_laminar_dynamic_viscosity(self, k): """ Calculate the blended dynamic viscosity function as a function of the (constant) nu and (variable) rho Return the function as defined on timestep t^{n+k} """ nu = self.get_laminar_kinematic_viscosity(k) rho = self.get_density(k) return nu * rho def get_density_range(self): """ Return the maximum and minimum densities, rho """ return self.rho_min, self.rho_max def get_laminar_kinematic_viscosity_range(self): """ Return the maximum and minimum kinematic viscosities, nu """ return self.nu, self.nu def get_laminar_dynamic_viscosity_range(self): """ The minimum and maximum laminar dynamic viscosities, mu. """ return self.nu * self.rho_min, self.nu * self.rho_max def update(self, timestep_number, t, dt): """ Update the density field by advecting it for a time dt using the given divergence free velocity field """ timer = dolfin.Timer('Ocellaris update rho') sim = self.simulation if timestep_number != 1: # Update the previous values self.rho_pp.assign(self.rho_p) self.rho_p.assign(self.rho) # Check for steady solution every timestep, this can change over time force_static = sim.input.get_value('multiphase_solver/force_static', FORCE_STATIC, 'bool') if force_static: # Keep the existing solution self.rho.assign(self.rho_p) elif self.use_analytical_solution: # Use an analytical density field for testing other parts of Ocellaris cpp_code = sim.input.get_value('initial_conditions/rho_p/cpp_code', required_type='string') description = 'initial condition for rho_p' V = sim.data['Vrho'] ocellaris_interpolate(sim, cpp_code, description, V, self.rho) elif self.use_rk_method: # Strong-Stability-Preserving Runge-Kutta DG time integration self.rho.assign(self.rho_p) self.rho_explicit.assign(self.rho_p) self.rk.step(dt) else: # Compute global bounds if self.is_first_timestep: lo, hi = self.slope_limiter.set_global_bounds(self.rho) if self.slope_limiter.has_global_bounds: sim.log.info( 'Setting global bounds [%r, %r] in VariableDensity' % (lo, hi)) # Solve the implicit advection equation A = self.eq.assemble_lhs() b = self.eq.assemble_rhs() self.solver.solve(A, self.rho.vector(), b) self.slope_limiter.run() self.time_coeffs.assign(Constant([3 / 2, -2, 1 / 2])) sim.reporting.report_timestep_value('min(rho)', self.rho.vector().min()) sim.reporting.report_timestep_value('max(rho)', self.rho.vector().max()) timer.stop() # Stop timer before hook self.simulation.hooks.run_custom_hook('MultiPhaseModelUpdated') self.is_first_timestep = False
assign(rho0, rho) # Needed for constrained map if projection_type == 'PDE': assign(ubar0_a, Uhbar.sub(0)) assign(u0, ustar) assign(duh00, duh0) assign(duh0, project(Uh.sub(0) - ustar, W_2)) del (t1) t1 = Timer("[P] Update particle field") p.increment(Udiv, ustar, np.array([2, 3], dtype=np.uintp), theta_p, step) del (t1) if step == 2: theta_L.assign(1.0) if step % store_step == 0: t1 = Timer("[P] Storing xdmf fields, just output!") # Set output, also throw out particle output xdmf_rho.write_checkpoint(rho, "rho", t, append=True) xdmf_u.write(Uh.sub(0), t) xdmf_p.write(Uh.sub(1), t) # Save particle data p.dump2file(mesh, fname_list, property_list, 'ab', False) comm.barrier() del (t1) timer.stop()
time = Timer("ZZZ Stokes solve") for bc in bcs: ssc.apply_boundary(bc) ssc.solve_problem(Uhbar.cpp_object(), Uh.cpp_object(), "mumps", "default") del time # Transfer the computed velocity function and compute functionals velocity_assigner.assign(u_vec, Uh.sub(0)) output_data_step(append=False) time_snap_shot_interval = 5.0 next_snap_shot_time = time_snap_shot_interval for j in range(50000): max_u_vec = u_vec.vector().norm("linf") dt.assign(C_CFL * hmin / max_u_vec) t.assign(float(t) + float(dt)) if float(t) > 2000.0: break info("Timestep %d, dt = %.3e, t = %.3e" % (j, float(dt), float(t))) time = Timer("ZZZ Do_step") ap.do_step(float(dt)) del time time = Timer("ZZZ PDE project assemble") pde_projection.assemble(True, True) del time
print(_dmdm_predicted) print() if TEST_SENSITIVITY_REACTION_MEASUREMENTS: logger.info('Test reaction measurement sensitivity') # Uniform perturbation of reaction (traction) measurements perturb_T_msr = np.array([0.1 * Tx_max, 0.0, 0.0]) m0 = np.array(inverse_solver.view_model_parameter_values()) dm = sum( inverse_solver.observe_dmdT_msr(t)[i_msr_f] for t in inverse_solver.observation_times).dot(perturb_T_msr) dT_msr_noise.assign(dolfin.Constant(perturb_T_msr)) n, b = inverse_solver.solve_inverse_problem() # Default times if not b: logger.error('Inverse solver did not converge') m1 = np.array(inverse_solver.view_model_parameter_values()) passed_test_sensitivity_reaction_force = \ np.allclose(m1 - m0, dm, atol=1e-2*np.abs(dm).max()) if passed_test_sensitivity_reaction_force: logger.info('Reaction measurement sensitivity test [PASSED]') else: logger.error('Reaction measurement sensitivity test [FAILED]') print('Reference model parameter values:')
class M3H3(object): def __init__(self, geometry, parameters, *args, **kwargs): self.parameters = parameters self.physics = [Physics(p) for p in parameters.keys() if Physics.has_value(p)] self.interactions = kwargs.get('interactions', []) if len(self.interactions) > 0: self._check_physics_interactions() if 'time' in kwargs.keys(): self.time = kwargs['time'] kwargs.pop('time', None) else: self.time = Constant(self.parameters['start_time']) self._setup_geometries(geometry, self.physics) self._setup_problems(**kwargs) self._setup_solvers(**kwargs) def step(self): # Setup time stepping if running step function for the first time. if self.time.values()[0] == self.parameters['start_time']: self.num_steps, self.max_dt = self._get_num_steps() time = float(self.time) solution_fields = self.get_solution_fields() if Physics.ELECTRO in self.physics: for _ in range(self.num_steps[Physics.ELECTRO]): electro_fields = solution_fields[str(Physics.ELECTRO)] self.electro_solver.step(electro_fields[1]) if Physics.SOLID in self.physics: for _ in range(self.num_steps[Physics.SOLID]): self.solid_solver.step() if Physics.FLUID in self.physics: for _ in range(self.num_steps[Physics.FLUID]): self.fluid_solver.step() if Physics.POROUS in self.physics: for _ in range(self.num_steps[Physics.POROUS]): self.porous_solver.step() self.time.assign(time + self.max_dt) return time, solution_fields def get_solution_fields(self): solution_fields = {} if Physics.ELECTRO in self.physics: solution_fields[str(Physics.ELECTRO)] =\ self.electro_problem._get_solution_fields() if Physics.SOLID in self.physics: pass if Physics.FLUID in self.physics: pass if Physics.POROUS in self.physics: pass return solution_fields def add_stimulus(self, stimulus): assert hasattr(self, 'electro_problem'), \ "Cannot add stimulus if electrophysiology has not been set up." self.electro_problem.add_stimulus(stimulus) def _get_num_steps(self): dt_physics = self._get_physics_dt() min_dt = min(dt_physics.values()) max_dt = max(dt_physics.values()) num_steps = {} if Physics.ELECTRO in self.physics: dt = dt_physics[Physics.ELECTRO] if self._check_dt_is_multiple(dt, min_dt): num_steps[Physics.ELECTRO] = int(max_dt/dt) if Physics.SOLID in self.physics: dt = dt_physics[Physics.SOLID] if self._check_dt_is_multiple(dt, min_dt): num_steps[Physics.SOLID] = int(max_dt/dt) if Physics.FLUID in self.physics: dt = dt_physics[Physics.FLUID] if self._check_dt_is_multiple(dt, min_dt): num_steps[Physics.FLUID] = int(max_dt/dt) if Physics.POROUS in self.physics: dt = dt_physics[Physics.POROUS] if self._check_dt_is_multiple(dt, min_dt): num_steps[Physics.POROUS] = int(max_dt/dt) return num_steps, max_dt def _check_dt_is_multiple(self, dt, min_dt): if not (dt/min_dt).is_integer(): msg = "Time step sizes have to be multiples of each other."\ "{} is not a multiple of {}".format(dt, min_dt) raise ValueError(msg) else: return True def _get_physics_dt(self): dt = {} if Physics.ELECTRO in self.physics: dt[Physics.ELECTRO] = self.parameters[str(Physics.ELECTRO)]['dt'] if Physics.SOLID in self.physics: dt[Physics.SOLID] = self.parameters[str(Physics.SOLID)]['dt'] if Physics.FLUID in self.physics: dt[Physics.FLUID] = self.parameters[str(Physics.FLUID)]['dt'] if Physics.POROUS in self.physics: dt[Physics.POROUS] = self.parameters[str(Physics.POROUS)]['dt'] return dt def _setup_problems(self, **kwargs): if Physics.ELECTRO in self.physics: self.electro_problem = ElectroProblem( self.geometries[Physics.ELECTRO], self.time, self.parameters[str(Physics.ELECTRO)], **kwargs) if Physics.SOLID in self.physics: self.solid_problem = SolidProblem( self.geometries[Physics.SOLID], self.time, self.parameters[str(Physics.SOLID)], **kwargs) if Physics.FLUID in self.physics: self.fluid_problem = FluidProblem( self.geometries[Physics.FLUID], self.time, self.parameters[str(Physics.FLUID)], **kwargs) if Physics.POROUS in self.physics: self.porous_problem = PorousProblem( self.geometries[Physics.POROUS], self.time, self.parameters[str(Physics.POROUS)], **kwargs) def _setup_solvers(self, **kwargs): interval = (self.parameters['start_time'], self.parameters['end_time']) solution_fields = self.get_solution_fields() if Physics.ELECTRO in self.physics: elabel = str(Physics.ELECTRO) electro_fields = solution_fields[elabel] parameters = self.parameters[elabel]['linear_variational_solver'] self.electro_solver = BasicBidomainSolver(self.time, self.electro_problem._form, electro_fields, parameters, **kwargs) if Physics.SOLID in self.physics: parameters = self.parameters[str(Physics.SOLID)] self.solid_solver = SolidSolver( self.solid_problem._form, self.time, interval, parameters['dt'], parameters, **kwargs) if Physics.FLUID in self.physics: parameters = self.parameters[str(Physics.FLUID)] self.fluid_solver = FluidSolver( self.fluid_problem._form, self.time, interval, parameters['dt'], parameters, **kwargs) if Physics.POROUS in self.physics: parameters = self.parameters[str(Physics.POROUS)] self.porous_solver = PorousSolver( self.porous_problem._form, self.time, interval, parameters['dt'], parameters, **kwargs) def _setup_geometries(self, geometry, physics): self.geometries = {} if isinstance(geometry, MultiGeometry): for phys in physics: try: self.geometries[phys] = geometry.geometries[phys.value] except KeyError: msg = "Could not find a geometry for {} physics in "\ "MultiGeometry. Ensure that geometry labels "\ "correspond to values in Physics "\ "enum.".format(phys.value) raise KeyError(msg) assert isinstance(self.geometries[phys], HeartGeometry) elif len(physics) == 1: self.geometries[physics[0]] = geometry else: for phys in physics: self.geometries[phys] = geometry.copy(deepcopy=True) def _check_physics_interactions(self): # If multiple physics are defined, check that all are involved in an # interaction and that physics involved in an interaction are set up if len(self.physics) == 0 and len(self.interactions) > 0: msg = "At least one interaction has been set up, but no physics\n"\ "Interactions: {}".format(self.interactions) raise KeyError(msg) if len(self.physics) > 1: int_physics = set(np.array([ia.to_list() for ia in self.interactions]).flat) for p in int_physics: if p not in self.physics: msg = "Physics {} appears in interaction, but is not set "\ "up.".format(p) raise KeyError(msg) for p in self.physics: if p not in int_physics: msg = "Physcis {} is set up, but does not appear in any "\ "interaction.".format(p) raise KeyError(msg) def _setup_electro_problem(self, parameters): self.electro_problem = ElectroProblem(self.geometries[Physics.ELECTRO], self.time, parameters) def _setup_solid_problem(self, parameters): self.solid_problem = SolidProblem(self.geometries[Physics.SOLID], self.time, parameters) def _setup_fluid_problem(self, parameters): self.fluid_problem = FluidProblem(self.geometries[Physics.FLUID], self.time, parameters) def _setup_porous_problem(self, parameters): self.porous_problem = PorousProblem(self.geometries[Physics.POROUS], self.time, parameters) def update_parameters(self, physics, parameters): if physics == Physics.ELECTRO: self.parameters.set_electro_parameters(parameters) elif physics == Physics.SOLID: self.parameters.set_solid_parameters(parameters) elif physics == Physics.FLUID: self.parameters.set_fluid_parameters(parameters) elif physics == Physics.POROUS: self.parameters.set_porous_parameters(parameters)
def solve_compliance_maximization_problem( W, P, p, p_locals, equilibrium_solve, phasefield_penalty_weight, phasefield_collision_distance, phasefield_iteration_stepsize, phasefield_meanvalue_stepsize, minimum_phasefield_meanvalue=None, maximum_phasefield_meanvalue=None, minimum_residual_energy=None, callback_at_each_phasefield_iteration=None, callback_at_each_phasefield_meanvalue=None, ): ''' Parameters ---------- W : dolfin.Form Energy (`W(u(p), p)`) to be minimized. P : dolfin.Form Phasefield penalty (`P(p)`) to be minimized. p : dolfin.Function Phasefield function (scalar-valued). ''' if not isinstance(p, Function): raise TypeError('Parameter `p` must be a `dolfin.Function`') if not isinstance(p_locals, (list, tuple)): p_locals = (p_locals,) if not all(isinstance(p_i, Function) for p_i in p_locals): raise TypeError('Parameter `p_locals` must be a sequence of `dolfin.Function`s') if callback_at_each_phasefield_meanvalue is None: callback_at_each_phasefield_meanvalue = lambda : None elif not callable(callback_at_each_phasefield_meanvalue): raise TypeError('Parameter `callback_at_each_phasefield_meanvalue` ' 'must be callable without any arguments') if minimum_phasefield_meanvalue is None: minimum_phasefield_meanvalue = 0 if minimum_residual_energy is None: minimum_residual_energy = -np.inf phasefield_meanvalues = [] phasefield_iterations = [] energy_vs_phasefield = [] energy_vs_iterations = [] # Phasefield mean-value target p_mean_target = Constant(0.0) # Phasefield mean-value constraint C = (p - p_mean_target) * dx optimizer = optim.TopologyOptimizer( W, P, C, p, p_locals, equilibrium_solve, callback_at_each_phasefield_iteration) p.vector()[:] = sum(p_i.vector() for p_i in p_locals) phasefield_meanvalue_i = max(minimum_phasefield_meanvalue, assemble(p*dx) / assemble(1*dx(p.function_space().mesh()))) if maximum_phasefield_meanvalue is None: maximum_phasefield_meanvalue = phasefield_meanvalue_i elif maximum_phasefield_meanvalue < phasefield_meanvalue_i: phasefield_meanvalue_i = maximum_phasefield_meanvalue maximum_phasefield_meanvalue += EPS phasefield_iterations_i = 0 iterations_failed = False try: while phasefield_meanvalue_i < maximum_phasefield_meanvalue: logger.info('Solve for phasefield domain fraction ' f'{phasefield_meanvalue_i:.3f}') p_mean_target.assign(phasefield_meanvalue_i) try: iterations_count_i, energy_vs_iterations_i = optimizer.optimize( phasefield_iteration_stepsize, phasefield_penalty_weight, phasefield_collision_distance) except RuntimeError as exc: logger.error(str(exc)) logger.error('Solver failed for domain fraction ' f'{phasefield_meanvalue_i:.3f}') iterations_failed = True break phasefield_iterations_i += iterations_count_i phasefield_iterations.append(phasefield_iterations_i) phasefield_meanvalues.append(phasefield_meanvalue_i) energy_vs_iterations.extend(energy_vs_iterations_i) energy_vs_phasefield.append(energy_vs_iterations_i[-1]) callback_at_each_phasefield_meanvalue() if energy_vs_phasefield[-1] < minimum_residual_energy: logger.info('Energy converged within threshold') break phasefield_meanvalue_i += phasefield_meanvalue_stepsize else: logger.info('Reached phasefield domain fraction limit') except KeyboardInterrupt: logger.info('Caught a keyboard interrupt') return iterations_failed, energy_vs_iterations, energy_vs_phasefield, \ phasefield_meanvalues, phasefield_iterations, optimizer, p_mean_target
class BlendedAlgebraicVofModel(VOFMixin, MultiPhaseModel): description = 'A blended algebraic VOF scheme implementing HRIC/CICSAM type schemes' def __init__(self, simulation): """ A blended algebraic VOF scheme works by using a specific convection scheme in the advection of the colour function that ensures a sharp interface. * The convection scheme should be the name of a convection scheme that is tailored for advection of the colour function, i.e "HRIC", "MHRIC", "RHRIC" etc, * The velocity field should be divergence free The colour function is unity when rho=rho0 and nu=nu0 and zero when rho=rho1 and nu=nu1 """ self.simulation = simulation simulation.log.info('Creating blended VOF multiphase model') # Define function space and solution function V = simulation.data['Vc'] self.degree = V.ufl_element().degree() simulation.data['c'] = Function(V) simulation.data['cp'] = Function(V) simulation.data['cpp'] = Function(V) # The projected density and viscosity functions for the new time step can be made continuous self.continuous_fields = simulation.input.get_value( 'multiphase_solver/continuous_fields', CONTINUOUS_FIELDS, 'bool') if self.continuous_fields: simulation.log.info(' Using continuous rho and nu fields') mesh = simulation.data['mesh'] V_cont = dolfin.FunctionSpace(mesh, 'CG', self.degree + 1) self.continuous_c = dolfin.Function(V_cont) self.continuous_c_old = dolfin.Function(V_cont) self.continuous_c_oldold = dolfin.Function(V_cont) self.force_bounded = simulation.input.get_value( 'multiphase_solver/force_bounded', FORCE_BOUNDED, 'bool') self.force_sharp = simulation.input.get_value( 'multiphase_solver/force_sharp', FORCE_SHARP, 'bool') # Calculate mu from rho and nu (i.e mu is quadratic in c) or directly from c (linear in c) self.calculate_mu_directly_from_colour_function = simulation.input.get_value( 'multiphase_solver/calculate_mu_directly_from_colour_function', CALCULATE_MU_DIRECTLY_FROM_COLOUR_FUNCTION, 'bool', ) # Get the physical properties self.set_physical_properties(read_input=True) # The convection blending function that counteracts numerical diffusion scheme = simulation.input.get_value('convection/c/convection_scheme', CONVECTION_SCHEME, 'string') simulation.log.info( ' Using convection scheme %s for the colour function' % scheme) scheme_class = get_convection_scheme(scheme) self.convection_scheme = scheme_class(simulation, 'c') self.need_gradient = scheme_class.need_alpha_gradient # Create the equations when the simulation starts simulation.hooks.add_pre_simulation_hook( self.on_simulation_start, 'BlendedAlgebraicVofModel setup equations') # Update the rho and nu fields before each time step simulation.hooks.add_pre_timestep_hook( self.update, 'BlendedAlgebraicVofModel - update colour field') simulation.hooks.register_custom_hook_point('MultiPhaseModelUpdated') # Linear solver # This causes the MPI unit tests to fail in "random" places for some reason # Quick fix: lazy loading of the solver LAZY_LOAD_SOLVER = True if LAZY_LOAD_SOLVER: self.solver = None else: self.solver = linear_solver_from_input( self.simulation, 'solver/c', default_parameters=SOLVER_OPTIONS) # Subcycle the VOF calculation multiple times per Navier-Stokes time step self.num_subcycles = scheme = simulation.input.get_value( 'multiphase_solver/num_subcycles', NUM_SUBCYCLES, 'int') if self.num_subcycles < 1: self.num_subcycles = 1 # Time stepping based on the subcycled values if self.num_subcycles == 1: self.cp = simulation.data['cp'] self.cpp = simulation.data['cpp'] else: self.cp = dolfin.Function(V) self.cpp = dolfin.Function(V) # Plot density and viscosity fields for visualization self.plot_fields = simulation.input.get_value( 'multiphase_solver/plot_fields', PLOT_FIELDS, 'bool') if self.plot_fields: V_plot = V if not self.continuous_fields else V_cont self.rho_for_plot = Function(V_plot) self.nu_for_plot = Function(V_plot) self.rho_for_plot.rename('rho', 'Density') self.nu_for_plot.rename('nu', 'Kinematic viscosity') simulation.io.add_extra_output_function(self.rho_for_plot) simulation.io.add_extra_output_function(self.nu_for_plot) # Slope limiter in case we are using DG1, not DG0 self.slope_limiter = SlopeLimiter(simulation, 'c', simulation.data['c']) simulation.log.info(' Using slope limiter: %s' % self.slope_limiter.limiter_method) self.is_first_timestep = True def on_simulation_start(self): """ This runs when the simulation starts. It does not run in __init__ since the solver needs the density and viscosity we define, and we need the velocity that is defined by the solver """ sim = self.simulation beta = self.convection_scheme.blending_function # The time step (real value to be supplied later) self.dt = Constant(sim.dt / self.num_subcycles) # Setup the equation to solve c = sim.data['c'] cp = self.cp cpp = self.cpp dirichlet_bcs = sim.data['dirichlet_bcs'].get('c', []) # Use backward Euler (BDF1) for timestep 1 self.time_coeffs = Constant([1, -1, 0]) if dolfin.norm(cpp.vector()) > 0 and self.num_subcycles == 1: # Use BDF2 from the start self.time_coeffs.assign(Constant([3 / 2, -2, 1 / 2])) sim.log.info( 'Using second order timestepping from the start in BlendedAlgebraicVOF' ) # Make sure the convection scheme has something useful in the first iteration c.assign(sim.data['cp']) if self.num_subcycles > 1: cp.assign(sim.data['cp']) # Plot density and viscosity self.update_plot_fields() # Define equation for advection of the colour function # ∂c/∂t + ∇⋅(c u) = 0 Vc = sim.data['Vc'] project_dgt0 = sim.input.get_value( 'multiphase_solver/project_uconv_dgt0', True, 'bool') if self.degree == 0 and project_dgt0: self.vel_dgt0_projector = VelocityDGT0Projector( sim, sim.data['u_conv']) self.u_conv = self.vel_dgt0_projector.velocity else: self.u_conv = sim.data['u_conv'] forcing_zones = sim.data['forcing_zones'].get('c', []) self.eq = AdvectionEquation( sim, Vc, cp, cpp, self.u_conv, beta, time_coeffs=self.time_coeffs, dirichlet_bcs=dirichlet_bcs, forcing_zones=forcing_zones, dt=self.dt, ) if self.need_gradient: # Reconstruct the gradient from the colour function DG0 field self.convection_scheme.initialize_gradient() # Notify listeners that the initial values are available sim.hooks.run_custom_hook('MultiPhaseModelUpdated') def get_colour_function(self, k): """ Return the colour function on timestep t^{n+k} """ if k == 0: if self.continuous_fields: c = self.continuous_c else: c = self.simulation.data['c'] elif k == -1: if self.continuous_fields: c = self.continuous_c_old else: c = self.simulation.data['cp'] elif k == -2: if self.continuous_fields: c = self.continuous_c_oldold else: c = self.simulation.data['cpp'] if self.force_bounded: c = dolfin.max_value(dolfin.min_value(c, Constant(1.0)), Constant(0.0)) if self.force_sharp: c = dolfin.conditional(dolfin.ge(c, 0.5), Constant(1.0), Constant(0.0)) return c def update_plot_fields(self): """ These fields are only needed to visualise the rho and nu fields in xdmf format for Paraview or similar """ if not self.plot_fields: return V = self.rho_for_plot.function_space() dolfin.project(self.get_density(0), V, function=self.rho_for_plot) dolfin.project(self.get_laminar_kinematic_viscosity(0), V, function=self.nu_for_plot) def update(self, timestep_number, t, dt): """ Update the VOF field by advecting it for a time dt using the given divergence free velocity field """ timer = dolfin.Timer('Ocellaris update VOF') sim = self.simulation # Get the functions c = sim.data['c'] cp = sim.data['cp'] cpp = sim.data['cpp'] # Stop early if the free surface is forced to stay still force_static = sim.input.get_value('multiphase_solver/force_static', FORCE_STATIC, 'bool') if force_static: c.assign(cp) cpp.assign(cp) timer.stop() # Stop timer before hook sim.hooks.run_custom_hook('MultiPhaseModelUpdated') self.is_first_timestep = False return if timestep_number != 1: # Update the previous values cpp.assign(cp) cp.assign(c) if self.degree == 0: self.vel_dgt0_projector.update() # Reconstruct the gradients if self.need_gradient: self.convection_scheme.gradient_reconstructor.reconstruct() # Update the convection blending factors is_static = isinstance(self.convection_scheme, StaticScheme) if not is_static: self.convection_scheme.update(dt / self.num_subcycles, self.u_conv) # Update global bounds in slope limiter if self.is_first_timestep: lo, hi = self.slope_limiter.set_global_bounds(lo=0.0, hi=1.0) if self.slope_limiter.has_global_bounds: sim.log.info( 'Setting global bounds [%r, %r] in BlendedAlgebraicVofModel' % (lo, hi)) # Solve the advection equations for the colour field if timestep_number == 1 or is_static: c.assign(cp) else: if self.solver is None: sim.log.info('Creating colour function solver', flush=True) self.solver = linear_solver_from_input( self.simulation, 'solver/c', default_parameters=SOLVER_OPTIONS) # Solve the advection equation A = self.eq.assemble_lhs() for _ in range(self.num_subcycles): b = self.eq.assemble_rhs() self.solver.inner_solve(A, c.vector(), b, 1, 0) self.slope_limiter.run() if self.num_subcycles > 1: self.cpp.assign(self.cp) self.cp.assign(c) # Optionally use a continuous predicted colour field if self.continuous_fields: Vcg = self.continuous_c.function_space() dolfin.project(c, Vcg, function=self.continuous_c) dolfin.project(cp, Vcg, function=self.continuous_c_old) dolfin.project(cpp, Vcg, function=self.continuous_c_oldold) # Report properties of the colour field sim.reporting.report_timestep_value('min(c)', c.vector().min()) sim.reporting.report_timestep_value('max(c)', c.vector().max()) # The next update should use the dt from this time step of the # main Navier-Stoke solver. The update just computed above uses # data from the previous Navier-Stokes solve with the previous dt self.dt.assign(dt / self.num_subcycles) if dt != sim.dt_prev: # Temporary switch to first order timestepping for the next # time step. This code is run before the Navier-Stokes solver # in each time step sim.log.info( 'VOF solver is first order this time step due to change in dt') self.time_coeffs.assign(Constant([1.0, -1.0, 0.0])) else: # Use second order backward time difference next time step self.time_coeffs.assign(Constant([3 / 2, -2.0, 1 / 2])) self.update_plot_fields() timer.stop() # Stop timer before hook sim.hooks.run_custom_hook('MultiPhaseModelUpdated') self.is_first_timestep = False
# Set final time # Initialize value at T[1] t = trange[1] vold = u_T_numpy(X, Y) if storeV: Vsol = np.ndarray([nt + 1, len(ydofs), len(xdofs)]) Vsol[0, :, :] = vold L_ = gamma * f * test * dx(mx) for i, t in enumerate(trange[1:]): print('Solve problem, time step t = {}'.format(np.round(t, 4))) # Assign current time to variable t_ t_.assign(t) # Compute Ytilde, i.e. y-position of process starting in x_i,y_j # after application of convection in y-direction Ytilde = Y + by(t, X, Y) * dt[i] Vtilde = Yinterp1(vold, Ytilde, ydofs, ydiff) # Set up problem Sfull = M - dt[i] * S # Apply boundary conditions bc_Vx.apply(Sfull) # Loop over all layers in y-direction for j in range(ny + 1):
class CavityProblemSetup(): def __init__(self, parameters, mesh_name, facet_name): """ Create the required function spaces, functions and boundary conditions for a channel flow problem """ self.mesh = Mesh() with XDMFFile(mesh_name) as infile: infile.read(self.mesh) mvc = MeshValueCollection("size_t", self.mesh, self.mesh.topology().dim() - 1) with XDMFFile(facet_name) as infile: infile.read(mvc, "name_to_read") mf = self.mf = cpp.mesh.MeshFunctionSizet(self.mesh, mvc) self.bc_dict = {"bottom": 1, "right": 2, "top": 3, "left": 4} T_init = Constant(parameters["initial temperature [°C]"]) self.t_amb = Constant(parameters["ambient temperature [°C]"]) self.t_feeder = Constant(parameters["temperature feeder [°C]"]) self.k_top = Constant(parameters["thermal conductivity top [W/(m K)]"]) self.k_lft = Constant( parameters["thermal conductivity left [W/(m K)]"]) self.k_btm = Constant( parameters["thermal conductivity bottom [W/(m K)]"]) self.k_rgt = Constant( parameters["thermal conductivity right [W/(m K)]"]) self.U_m = Constant(parameters["mean velocity lid [m/s]"]) g = parameters["gravity [m/s²]"] self.g = Constant((0.0, -g)) self.dt = Constant(parameters["dt [s]"]) self.D = Constant(parameters["Diffusivity [-]"]) self.V = V = VectorFunctionSpace(self.mesh, 'P', 2) self.Q = Q = FunctionSpace(self.mesh, 'P', 1) self.T = T = FunctionSpace(self.mesh, 'P', 1) self.ds_ = Measure("ds", domain=self.mesh, subdomain_data=mf) self.vu, self.vp, self.vt = (TestFunction(V), TestFunction(Q), TestFunction(T)) self.u_, self.p_, self.t_ = Function(V), Function(Q), Function(T) self.mu, self.rho = Function(T), Function(T) self.u_1, self.p_1, self.t_1, self.rho_1 = (Function(V), Function(Q), Function(T), Function(T)) self.u, self.p, self.t = (TrialFunction(V), TrialFunction(Q), TrialFunction(T)) # boundary conditions self.no_slip = Constant((0., 0)) self.topflow = Expression(("-x[0] * (x[0] - 1.0) * 6.0 * m", "0.0"), m=self.U_m, degree=2) bc0 = DirichletBC(V, self.topflow, mf, self.bc_dict["top"]) bc1 = DirichletBC(V, self.no_slip, mf, self.bc_dict["left"]) bc2 = DirichletBC(V, self.no_slip, mf, self.bc_dict["bottom"]) bc3 = DirichletBC(V, self.no_slip, mf, self.bc_dict["right"]) # bc4 = df.DirichletBC(Q, df.Constant(0), top) # bc3 = df.DirichletBC(T, df.Constant(800), top) self.bcu = [bc0, bc1, bc2, bc3] self.bcp = [DirichletBC(Q, Constant(0), mf, self.bc_dict["top"])] self.bcp = [] self.bct = [] # self.bct = [DirichletBC(T, Constant(self.t_feeder), mf, # self.bc_dict["top"])] self.robin_boundary_terms = ( self.k_btm * (self.t - self.t_amb) * self.vt * self.ds_(1) + self.k_rgt * (self.t - self.t_amb) * self.vt * self.ds_(2) # + self.k_top*(self.t - self.t_feeder)*self.vt*self.ds_(3) + self.k_lft * (self.t - self.t_amb) * self.vt * self.ds_(4)) print("k, T", self.k_btm.values(), self.t_feeder.values()) print("k, T", self.k_rgt.values(), self.t_amb.values()) # print("k, T", self.k_top.values(), self.t_amb.values()) print("k, T", self.k_lft.values(), self.t_amb.values()) # set initial values # TODO: find a better solution x, y = T.tabulate_dof_coordinates().T self.u_1.vector().vec().array[:] = 1e-6 # self.u_k.vector().vec().array[:] = 1e-6 self.p_.vector().vec( ).array[:] = -self.rho.vector().vec().array * g * y self.p_1.vector().vec( ).array[:] = -self.rho.vector().vec().array * g * y self.t_1.vector().vec().array = T_init self.t_.assign(self.t_1) return def stokes(self): P2 = VectorElement("CG", self.mesh.ufl_cell(), 2) P1 = FiniteElement("CG", self.mesh.ufl_cell(), 1) TH = P2 * P1 VQ = FunctionSpace(self.mesh, TH) mf = self.mf self.no_slip = Constant((0., 0)) self.topflow = Expression(("-x[0] * (x[0] - 1.0) * 6.0 * m", "0.0"), m=self.U_m, degree=2) bc0 = DirichletBC(VQ.sub(0), self.topflow, mf, self.bc_dict["top"]) bc1 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["left"]) bc2 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["bottom"]) bc3 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["right"]) # bc4 = DirichletBC(VQ.sub(1), Constant(0), mf, self.bc_dict["top"]) bcs = [bc0, bc1, bc2, bc3] vup = TestFunction(VQ) up = TrialFunction(VQ) # the solution will be in here: up_ = Function(VQ) u, p = split(up) # Trial vu, vp = split(vup) # Test u_, p_ = split(up_) # Function holding the solution F = self.mu*inner(grad(vu), grad(u))*dx - inner(div(vu), p)*dx \ - inner(vp, div(u))*dx + dot(self.g*self.rho, vu)*dx solve(lhs(F) == rhs(F), up_, bcs=bcs) self.u_.assign(project(u_, self.V)) self.p_.assign(project(p_, self.Q)) return def initial_condition_from_file(self, path_u, path_p): f_in = XDMFFile(path_u) f_in.read_checkpoint(self.u_, "f", 0) f_in = XDMFFile(path_p) f_in.read_checkpoint(self.p_, "f", 0) return def get_rho(self): return self.rho.vector().vec().array def set_rho(self, rho): self.rho.vector().vec().array[:] = rho def get_mu(self): return self.mu.vector().vec().array def set_mu(self, mu): self.mu.vector().vec().array[:] = mu def get_t(self): return self.t_.vector().vec().array def set_t(self, t): self.t_.vector().vec().array[:] = t def get_dt(self): return self.dt.values() def set_dt(self, dt): self.dt.assign(dt) def get_D(self): return self.D.values() def set_D(self, D): self.D.assign(D) def get_t_amb(self): return self.t_amb.values() def set_t_amb(self, t_amb): self.t_amb.assign(t_amb) def plot(self): cmap = mpl.cm.inferno cmap_r = mpl.cm.inferno_r u, p, t, m, r = self.u_, self.p_, self.t_, self.mu, self.rho mesh = self.mesh w0 = u.compute_vertex_values(mesh) w0.shape = (2, -1) magnitude = np.linalg.norm(w0, axis=0) x, y = np.split(mesh.coordinates(), 2, 1) u, v = np.split(w0, 2, 0) x, y, u, v = x.ravel(), y.ravel(), u.ravel(), v.ravel() tri = mesh.cells() pressure = p.compute_vertex_values(mesh) temperature = t.compute_vertex_values(mesh) viscosity = m.compute_vertex_values(mesh) density = r.compute_vertex_values(mesh) fig = plt.figure(figsize=(12, 8)) ax1 = plt.subplot(121) ax2 = plt.subplot(243, sharex=ax1, sharey=ax1) ax3 = plt.subplot(244, sharex=ax1, sharey=ax1) ax4 = plt.subplot(247, sharex=ax1, sharey=ax1) ax5 = plt.subplot(248, sharex=ax1, sharey=ax1) ax1.plot(x, y, "k.", ms=.5) not0 = magnitude > 1e-6 if np.sum(not0) > 0: ax1.quiver(x[not0], y[not0], u[not0], v[not0], magnitude[not0]) c2 = ax2.tricontourf(x, y, tri, pressure, levels=40, cmap=cmap) c3 = ax3.tricontourf(x, y, tri, temperature, levels=40, cmap=cmap) c4 = ax4.tricontourf( x, y, tri, viscosity, levels=40, # vmin=self.mu(800, .1), vmax=self.mu(600, .1), cmap=cmap_r) c5 = ax5.tricontourf( x, y, tri, density, levels=40, # vmin=self.rho(800.), vmax=self.rho(600.), cmap=cmap_r) plt.colorbar(c2, ax=ax2) plt.colorbar(c3, ax=ax3, ticks=[temperature.min(), temperature.max()]) plt.colorbar(c4, ax=ax4, ticks=[viscosity.min(), viscosity.max()]) plt.colorbar(c5, ax=ax5, ticks=[density.min(), density.max()]) ax1.set_aspect("equal") ax2.set_aspect("equal") ax3.set_aspect("equal") ax4.set_aspect("equal") ax5.set_aspect("equal") ax1.set_title("velocity\n{:.4f} ... {:.5f} m/s".format( magnitude.min(), magnitude.max())) ax2.set_title("pressure") ax3.set_title("temperature") ax4.set_title("viscosity") ax5.set_title("density") ax1.set_xlim([-.1, 1.1]) ax1.set_ylim([-.1, 1.1]) # plt.tight_layout() return fig, (ax1, ax2)
t1 = Timer("[P] Assign and output") # Needed for particle advection assign(Udiv, Uh.sub(0)) # Needed for constrained map assign(ubar0_a, Uhbar.sub(0)) assign(u0_a, ustar) assign(duh00, duh0) assign(duh0, project(Uh.sub(0) - ustar, W_2)) p.increment(Udiv.cpp_object(), ustar.cpp_object(), np.array([1, 2], dtype=np.uintp), theta_p, step) if step == 2: theta_L.assign(theta_next) # Probably can be combined into one file? xdmf_u.write(Uh.sub(0), t) xdmf_p.write(Uh.sub(1), t) del t1 timer.stop() # Compute errors u_exact.t = t p_exact.t = t u_error = sqrt(assemble(dot(Uh.sub(0) - u_exact, Uh.sub(0) - u_exact) * dx)) p_error = sqrt(assemble(dot(Uh.sub(1) - p_exact, Uh.sub(1) - p_exact) * dx)) udiv = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0)) * dx))
Uvector = 3 * as_backend_type(u_n.vector()).get_local() _3u_n.vector().set_local(Uvector) _3u_A, _3u_B, _3u_C, _3u_T = _3u_n.split() _u_D = _3u_C if Data_postprocessing: fA_out.write_checkpoint(_u_A, "A", t, XDMFFile.Encoding.HDF5, True) fB_out.write_checkpoint(_u_B, "B", t, XDMFFile.Encoding.HDF5, True) fC_out.write_checkpoint(_u_C, "C", t, XDMFFile.Encoding.HDF5, True) fD_out.write_checkpoint(_u_D, "D", t, XDMFFile.Encoding.HDF5, True) fT_out.write_checkpoint(_u_T, "T", t, XDMFFile.Encoding.HDF5, True) Twall_n = Twall ufl_integral = assemble(_u_T * ds_wall) Numer = (roW * Vw * Cpw) / dt * Twall_n + fw * Cpw * Tcool_in + hw * A * ufl_integral Twall_new = Numer / Denom print('Wall temperature {} K'.format(np.around(float(Twall_new), 4))) Twall.assign(Twall_new) u_n.assign(u) fA_out.close() fB_out.close() fC_out.close() fD_out.close() fT_out.close() End_St = dtm.datetime.now() # The end time of execution---------------------- Execution_time(Start_St, End_St, 'Reports', 'PhtAnh_PBR', True) # _______________END_______________ #