def create_function_marker(PHI, W, xlimits, ylimits): x, y, z = fd.SpatialCoordinate(PHI.ufl_domain()) x_func, y_func, z_func = ( fd.Function(PHI), fd.Function(PHI), fd.Function(PHI), ) with fda.stop_annotating(): x_func.interpolate(x) y_func.interpolate(y) z_func.interpolate(z) domain = "{[i, j]: 0 <= i < f.dofs and 0<= j <= 3}" instruction = f""" f[i, j] = 1.0 if (x[i, 0] < {xlimits[1]} and x[i, 0] > {xlimits[0]}) and (y[i, 0] < {ylimits[0]} or y[i, 0] > {ylimits[1]}) and z[i, 0] < 1e-7 else 0.0 """ I_BC = fd.Function(W) fd.par_loop( (domain, instruction), dx, { "f": (I_BC, fd.RW), "x": (x_func, fd.READ), "y": (y_func, fd.READ), "z": (z_func, fd.READ), }, is_loopy_kernel=True, ) return I_BC
def test_line_search(): mesh = fd.UnitSquareMesh(50, 50) # Shape derivative S = fd.VectorFunctionSpace(mesh, "CG", 1) s = fd.Function(S, name="deform") mesh.coordinates.assign(mesh.coordinates + s) # Level set PHI = fd.FunctionSpace(mesh, "CG", 1) x, y = fd.SpatialCoordinate(mesh) with fda.stop_annotating(): phi = fd.interpolate(-(x - 0.5), PHI) phi.rename("original") solver_parameters = { "ts_atol": 1e-4, "ts_rtol": 1e-4, "ts_dt": 1e-2, "ts_exact_final_time": "matchstep", "ts_monitor": None, } ## Search direction with fda.stop_annotating(): delta_x = fd.interpolate(fd.as_vector([-100 * x, 0.0]), S) delta_x.rename("velocity") # Cost function J = fd.assemble(hs(-phi) * dx) # Reduced Functional c = fda.Control(s) Jhat = LevelSetFunctional(J, c, phi) # InfDim Problem beta_param = 0.08 reg_solver = RegularizationSolver(S, mesh, beta=beta_param, gamma=1e5, dx=dx) solver_parameters = {"hj_solver": solver_parameters} problem = InfDimProblem(Jhat, reg_solver, solver_parameters=solver_parameters) new_phi = fd.Function(PHI, name="new_ls") orig_phi = fd.Function(PHI) with fda.stop_annotating(): orig_phi.assign(phi) problem.delta_x.assign(delta_x) AJ, AC = 1.0, 1.0 C = np.array([]) merit = merit_eval_new(AJ, J, AC, C) rtol = 1e-4 new_phi, newJ, newG, newH = line_search( problem, orig_phi, new_phi, merit_eval_new, merit, AJ, AC, dt=1.0, tol_merit=rtol, maxtrials=20, ) assert_allclose(newJ, J, rtol=rtol)
def heat_exchanger_optimization(mu=0.03, n_iters=1000): output_dir = "2D/" path = os.path.abspath(__file__) dir_path = os.path.dirname(path) mesh = fd.Mesh(f"{dir_path}/2D_mesh.msh") # Perturb the mesh coordinates. Necessary to calculate shape derivatives S = fd.VectorFunctionSpace(mesh, "CG", 1) s = fd.Function(S, name="deform") mesh.coordinates.assign(mesh.coordinates + s) # Initial level set function x, y = fd.SpatialCoordinate(mesh) PHI = fd.FunctionSpace(mesh, "CG", 1) phi_expr = sin(y * pi / 0.2) * cos(x * pi / 0.2) - fd.Constant(0.8) # Avoid recording the operation interpolate into the tape. # Otherwise, the shape derivatives will not be correct with fda.stop_annotating(): phi = fd.interpolate(phi_expr, PHI) phi.rename("LevelSet") fd.File(output_dir + "phi_initial.pvd").write(phi) # Physics mu = fd.Constant(mu) # viscosity alphamin = 1e-12 alphamax = 2.5 / (2e-4) parameters = { "mat_type": "aij", "ksp_type": "preonly", "ksp_converged_reason": None, "pc_type": "lu", "pc_factor_mat_solver_type": "mumps", } stokes_parameters = parameters temperature_parameters = parameters u_inflow = 2e-3 tin1 = fd.Constant(10.0) tin2 = fd.Constant(100.0) P2 = fd.VectorElement("CG", mesh.ufl_cell(), 2) P1 = fd.FiniteElement("CG", mesh.ufl_cell(), 1) TH = P2 * P1 W = fd.FunctionSpace(mesh, TH) U = fd.TrialFunction(W) u, p = fd.split(U) V = fd.TestFunction(W) v, q = fd.split(V) epsilon = fd.Constant(10000.0) def hs(phi, epsilon): return fd.Constant(alphamax) * fd.Constant(1.0) / ( fd.Constant(1.0) + exp(-epsilon * phi)) + fd.Constant(alphamin) def stokes(phi, BLOCK_INLET_MOUTH, BLOCK_OUTLET_MOUTH): a_fluid = mu * inner(grad(u), grad(v)) - div(v) * p - q * div(u) darcy_term = inner(u, v) return (a_fluid * dx + hs(phi, epsilon) * darcy_term * dx(0) + alphamax * darcy_term * (dx(BLOCK_INLET_MOUTH) + dx(BLOCK_OUTLET_MOUTH))) # Dirichlet boundary conditions inflow1 = fd.as_vector([ u_inflow * sin( ((y - (line_sep - (dist_center + inlet_width))) * pi) / inlet_width), 0.0, ]) inflow2 = fd.as_vector([ u_inflow * sin(((y - (line_sep + dist_center)) * pi) / inlet_width), 0.0, ]) noslip = fd.Constant((0.0, 0.0)) # Stokes 1 bcs1_1 = fd.DirichletBC(W.sub(0), noslip, WALLS) bcs1_2 = fd.DirichletBC(W.sub(0), inflow1, INLET1) bcs1_3 = fd.DirichletBC(W.sub(1), fd.Constant(0.0), OUTLET1) bcs1_4 = fd.DirichletBC(W.sub(0), noslip, INLET2) bcs1_5 = fd.DirichletBC(W.sub(0), noslip, OUTLET2) bcs1 = [bcs1_1, bcs1_2, bcs1_3, bcs1_4, bcs1_5] # Stokes 2 bcs2_1 = fd.DirichletBC(W.sub(0), noslip, WALLS) bcs2_2 = fd.DirichletBC(W.sub(0), inflow2, INLET2) bcs2_3 = fd.DirichletBC(W.sub(1), fd.Constant(0.0), OUTLET2) bcs2_4 = fd.DirichletBC(W.sub(0), noslip, INLET1) bcs2_5 = fd.DirichletBC(W.sub(0), noslip, OUTLET1) bcs2 = [bcs2_1, bcs2_2, bcs2_3, bcs2_4, bcs2_5] # Forward problems U1, U2 = fd.Function(W), fd.Function(W) L = inner(fd.Constant((0.0, 0.0, 0.0)), V) * dx problem = fd.LinearVariationalProblem(stokes(-phi, INMOUTH2, OUTMOUTH2), L, U1, bcs=bcs1) solver_stokes1 = fd.LinearVariationalSolver( problem, solver_parameters=stokes_parameters, options_prefix="stokes_1") solver_stokes1.solve() problem = fd.LinearVariationalProblem(stokes(phi, INMOUTH1, OUTMOUTH1), L, U2, bcs=bcs2) solver_stokes2 = fd.LinearVariationalSolver( problem, solver_parameters=stokes_parameters, options_prefix="stokes_2") solver_stokes2.solve() # Convection difussion equation ks = fd.Constant(1e0) cp_value = 5.0e5 cp = fd.Constant(cp_value) T = fd.FunctionSpace(mesh, "DG", 1) t = fd.Function(T, name="Temperature") w = fd.TestFunction(T) # Mesh-related functions n = fd.FacetNormal(mesh) h = fd.CellDiameter(mesh) u1, p1 = fd.split(U1) u2, p2 = fd.split(U2) def upwind(u): return (dot(u, n) + abs(dot(u, n))) / 2.0 u1n = upwind(u1) u2n = upwind(u2) # Penalty term alpha = fd.Constant(500.0) # Bilinear form a_int = dot(grad(w), ks * grad(t) - cp * (u1 + u2) * t) * dx a_fac = (fd.Constant(-1.0) * ks * dot(avg(grad(w)), jump(t, n)) * dS + fd.Constant(-1.0) * ks * dot(jump(w, n), avg(grad(t))) * dS + ks("+") * (alpha("+") / avg(h)) * dot(jump(w, n), jump(t, n)) * dS) a_vel = (dot( jump(w), cp * (u1n("+") + u2n("+")) * t("+") - cp * (u1n("-") + u2n("-")) * t("-"), ) * dS + dot(w, cp * (u1n + u2n) * t) * ds) a_bnd = (dot(w, cp * dot(u1 + u2, n) * t) * (ds(INLET1) + ds(INLET2)) + w * t * (ds(INLET1) + ds(INLET2)) - w * tin1 * ds(INLET1) - w * tin2 * ds(INLET2) + alpha / h * ks * w * t * (ds(INLET1) + ds(INLET2)) - ks * dot(grad(w), t * n) * (ds(INLET1) + ds(INLET2)) - ks * dot(grad(t), w * n) * (ds(INLET1) + ds(INLET2))) aT = a_int + a_fac + a_vel + a_bnd LT_bnd = (alpha / h * ks * tin1 * w * ds(INLET1) + alpha / h * ks * tin2 * w * ds(INLET2) - tin1 * ks * dot(grad(w), n) * ds(INLET1) - tin2 * ks * dot(grad(w), n) * ds(INLET2)) problem = fd.LinearVariationalProblem(derivative(aT, t), LT_bnd, t) solver_temp = fd.LinearVariationalSolver( problem, solver_parameters=temperature_parameters, options_prefix="temperature", ) solver_temp.solve() # fd.solve(eT == 0, t, solver_parameters=temperature_parameters) # Cost function: Flux at the cold outlet scale_factor = 4e-4 Jform = fd.assemble( fd.Constant(-scale_factor * cp_value) * inner(t * u1, n) * ds(OUTLET1)) # Constraints: Pressure drop on each fluid power_drop = 1e-2 Power1 = fd.assemble(p1 / power_drop * ds(INLET1)) Power2 = fd.assemble(p2 / power_drop * ds(INLET2)) phi_pvd = fd.File("phi_evolution.pvd") def deriv_cb(phi): with stop_annotating(): phi_pvd.write(phi[0]) c = fda.Control(s) # Reduced Functionals Jhat = LevelSetFunctional(Jform, c, phi, derivative_cb_pre=deriv_cb) P1hat = LevelSetFunctional(Power1, c, phi) P1control = fda.Control(Power1) P2hat = LevelSetFunctional(Power2, c, phi) P2control = fda.Control(Power2) Jhat_v = Jhat(phi) print("Initial cost function value {:.5f}".format(Jhat_v), flush=True) print("Power drop 1 {:.5f}".format(Power1), flush=True) print("Power drop 2 {:.5f}".format(Power2), flush=True) beta_param = 0.08 # Regularize the shape derivatives only in the domain marked with 0 reg_solver = RegularizationSolver(S, mesh, beta=beta_param, gamma=1e5, dx=dx, design_domain=0) tol = 1e-5 dt = 0.05 params = { "alphaC": 1.0, "debug": 5, "alphaJ": 1.0, "dt": dt, "K": 1e-3, "maxit": n_iters, "maxtrials": 5, "itnormalisation": 10, "tol_merit": 5e-3, # new merit can be within 0.5% of the previous merit # "normalize_tol" : -1, "tol": tol, } solver_parameters = { "reinit_solver": { "h_factor": 2.0, } } # Optimization problem problem = InfDimProblem( Jhat, reg_solver, ineqconstraints=[ Constraint(P1hat, 1.0, P1control), Constraint(P2hat, 1.0, P2control), ], solver_parameters=solver_parameters, ) results = nlspace_solve(problem, params) return results
} def update_forcings(t): with timed_stage('update forcings'): print_output("Updating tidal field at t={}".format(t)) elev = prepare.myboundary.set_tidal_field( Function(bathymetry2d.function_space()), t, dt) tidal_elev.project(elev) v = prepare.myboundary.set_velocity_field( Function(VectorFunctionSpace(mesh2d, "CG", 1)), t, dt) tidal_v.project(v) print_output("Done updating tidal field") # run as normal (this run will be annotated by firedrake_adjoint) #solver_obj.load_state(670,outputdir='./outputs/redata_5min_normaldepth') solver_obj.assign_initial_conditions(uv=as_vector((1e-7, 0.0)), elev=Constant(0.0)) #place detectors code with stop_annotating(): locations, names = prepare.detectors.get_detectors(mesh2d) cb = DetectorsCallback(solver_obj, locations, ['elev_2d', 'uv_2d'], name='detectors', detector_names=names) solver_obj.add_callback(cb, 'timestep') solver_obj.iterate(update_forcings=update_forcings)
def gradient_test_acoustic(model, mesh, V, comm, vp_exact, vp_guess, mask=None): #{{{ import firedrake_adjoint as fire_adj with fire_adj.stop_annotating(): if comm.comm.rank == 0: print('######## Starting gradient test ########', flush=True) sources = spyro.Sources(model, mesh, V, comm) receivers = spyro.Receivers(model, mesh, V, comm) wavelet = spyro.full_ricker_wavelet( model["timeaxis"]["dt"], model["timeaxis"]["tf"], model["acquisition"]["frequency"], ) point_cloud = receivers.set_point_cloud(comm) # simulate the exact model if comm.comm.rank == 0: print('######## Running the exact model ########', flush=True) p_exact_recv = forward(model, mesh, comm, vp_exact, sources, wavelet, point_cloud) # simulate the guess model if comm.comm.rank == 0: print('######## Running the guess model ########', flush=True) p_guess_recv, Jm = forward(model, mesh, comm, vp_guess, sources, wavelet, point_cloud, fwi=True, true_rec=p_exact_recv) if comm.comm.rank == 0: print("\n Cost functional at fixed point : " + str(Jm) + " \n ", flush=True) # compute the gradient of the control (to be verified) if comm.comm.rank == 0: print( '######## Computing the gradient by automatic differentiation ########', flush=True) control = fire_adj.Control(vp_guess) dJ = fire_adj.compute_gradient(Jm, control) if mask: dJ *= mask # File("gradient.pvd").write(dJ) #steps = [1e-3, 1e-4, 1e-5, 1e-6, 1e-7] # step length #steps = [1e-4, 1e-5, 1e-6, 1e-7] # step length steps = [1e-5, 1e-6, 1e-7, 1e-8] # step length with fire_adj.stop_annotating(): delta_m = Function(V) # model direction (random) delta_m.assign(dJ) Jhat = fire_adj.ReducedFunctional(Jm, control) derivative = enlisting.Enlist(Jhat.derivative()) hs = enlisting.Enlist(delta_m) projnorm = sum(hi._ad_dot(di) for hi, di in zip(hs, derivative)) # this deepcopy is important otherwise pertubations accumulate vp_original = vp_guess.copy(deepcopy=True) if comm.comm.rank == 0: print( '######## Computing the gradient by finite diferences ########', flush=True) errors = [] for step in steps: # range(3): # steps.append(step) # perturb the model and calculate the functional (again) # J(m + delta_m*h) vp_guess = vp_original + step * delta_m p_guess_recv, Jp = forward(model, mesh, comm, vp_guess, sources, wavelet, point_cloud, fwi=True, true_rec=p_exact_recv) fd_grad = (Jp - Jm) / step if comm.comm.rank == 0: print("\n Cost functional for step " + str(step) + " : " + str(Jp) + ", fd approx.: " + str(fd_grad) + ", grad'*dir : " + str(projnorm) + " \n ", flush=True) errors.append(100 * ((fd_grad - projnorm) / projnorm)) fire_adj.get_working_tape().clear_tape() # all errors less than 1 % errors = np.array(errors) assert (np.abs(errors) < 5.0).all()
def compliance(): parser = argparse.ArgumentParser(description="Compliance problem with MMA") parser.add_argument( "--nref", action="store", dest="nref", type=int, help="Number of mesh refinements", default=2, ) parser.add_argument( "--uniform", action="store", dest="uniform", type=int, help="Use uniform mesh", default=0, ) parser.add_argument( "--inner_product", action="store", dest="inner_product", type=str, help="Inner product, euclidean or L2", default="L2", ) parser.add_argument( "--output_dir", action="store", dest="output_dir", type=str, help="Directory for all the output", default="./", ) args = parser.parse_args() nref = args.nref inner_product = args.inner_product output_dir = args.output_dir assert inner_product == "L2" or inner_product == "euclidean" mesh = fd.Mesh("./beam_uniform.msh") #mh = fd.MeshHierarchy(mesh, 2) #mesh = mh[-1] if nref > 0: mh = fd.MeshHierarchy(mesh, nref) mesh = mh[-1] elif nref < 0: raise RuntimeError("Non valid mesh argument") V = fd.VectorFunctionSpace(mesh, "CG", 1) u, v = fd.TrialFunction(V), fd.TestFunction(V) # Elasticity parameters E, nu = 1e0, 0.3 mu, lmbda = fd.Constant(E / (2 * (1 + nu))), fd.Constant( E * nu / ((1 + nu) * (1 - 2 * nu)) ) # Helmholtz solver RHO = fd.FunctionSpace(mesh, "CG", 1) rho = fd.interpolate(fd.Constant(0.1), RHO) af, b = fd.TrialFunction(RHO), fd.TestFunction(RHO) #filter_radius = fd.Constant(0.2) #x, y = fd.SpatialCoordinate(mesh) #x_ = fd.interpolate(x, RHO) #y_ = fd.interpolate(y, RHO) #aH = filter_radius * inner(grad(af), grad(b)) * dx + af * b * dx #LH = rho * b * dx rhof = fd.Function(RHO) solver_params = { "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps", "mat_mumps_icntl_14": 200, "mat_mumps_icntl_24": 1, } #fd.solve(aH == LH, rhof, solver_parameters=solver_params) rhof.assign(rho) rhofControl = fda.Control(rhof) eps = fd.Constant(1e-5) p = fd.Constant(3.0) def simp(rho): return eps + (fd.Constant(1.0) - eps) * rho ** p def epsilon(v): return sym(nabla_grad(v)) def sigma(v): return 2.0 * mu * epsilon(v) + lmbda * tr(epsilon(v)) * Identity(2) DIRICHLET = 3 NEUMANN = 4 a = inner(simp(rhof) * sigma(u), epsilon(v)) * dx load = fd.Constant((0.0, -1.0)) L = inner(load, v) * ds(NEUMANN) u_sol = fd.Function(V) bcs = fd.DirichletBC(V, fd.Constant((0.0, 0.0)), DIRICHLET) fd.solve(a == L, u_sol, bcs=bcs, solver_parameters=solver_params) c = fda.Control(rho) J = fd.assemble(fd.Constant(1e-4) * inner(u_sol, load) * ds(NEUMANN)) Vol = fd.assemble(rhof * dx) VolControl = fda.Control(Vol) with fda.stop_annotating(): Vlimit = fd.assemble(fd.Constant(1.0) * dx(domain=mesh)) * 0.5 rho_viz_f = fd.Function(RHO, name="rho") plot_file = f"{output_dir}/design_{inner_product}.pvd" controls_f = fd.File(plot_file) def deriv_cb(j, dj, rho): with fda.stop_annotating(): rho_viz_f.assign(rhofControl.tape_value()) controls_f.write(rho_viz_f) Jhat = fda.ReducedFunctional(J, c, derivative_cb_post=deriv_cb) Volhat = fda.ReducedFunctional(Vol, c) class VolumeConstraint(fda.InequalityConstraint): def __init__(self, Vhat, Vlimit, VolControl): self.Vhat = Vhat self.Vlimit = float(Vlimit) self.VolControl = VolControl def function(self, m): # Compute the integral of the control over the domain integral = self.VolControl.tape_value() with fda.stop_annotating(): value = -integral / self.Vlimit + 1.0 return [value] def jacobian(self, m): with fda.stop_annotating(): gradients = self.Vhat.derivative() with gradients.dat.vec as v: v.scale(-1.0 / self.Vlimit) return [gradients] def output_workspace(self): return [0.0] def length(self): """Return the number of components in the constraint vector (here, one).""" return 1 lb = 1e-5 ub = 1.0 problem = fda.MinimizationProblem( Jhat, bounds=(lb, ub), constraints=[VolumeConstraint(Volhat, Vlimit, VolControl)], ) parameters_mma = { "move": 0.2, "maximum_iterations": 200, "m": 1, "IP": 0, "tol": 1e-6, "accepted_tol": 1e-4, "norm": inner_product, #"norm": "euclidean", "gcmma": False, } solver = MMASolver(problem, parameters=parameters_mma) rho_opt = solver.solve() with open(f"{output_dir}/finished_{inner_product}.txt", "w") as f: f.write("Done")
def jacobian(self, m): with fda.stop_annotating(): gradients = self.Vhat.derivative() with gradients.dat.vec as v: v.scale(-1.0 / self.Vlimit) return [gradients]
def function(self, m): # Compute the integral of the control over the domain integral = self.VolControl.tape_value() with fda.stop_annotating(): value = -integral / self.Vlimit + 1.0 return [value]
def deriv_cb(j, dj, rho): with fda.stop_annotating(): rho_viz_f.assign(rhofControl.tape_value()) controls_f.write(rho_viz_f)
def compliance_optimization(n_iters=200): output_dir = "cantilever/" path = os.path.abspath(__file__) dir_path = os.path.dirname(path) m = fd.Mesh(f"{dir_path}/mesh_cantilever.msh") mesh = fd.MeshHierarchy(m, 0)[-1] # Perturb the mesh coordinates. Necessary to calculate shape derivatives S = fd.VectorFunctionSpace(mesh, "CG", 1) s = fd.Function(S, name="deform") mesh.coordinates.assign(mesh.coordinates + s) # Initial level set function x, y = fd.SpatialCoordinate(mesh) PHI = fd.FunctionSpace(mesh, "CG", 1) lx = 2.0 ly = 1.0 phi_expr = ( -cos(6.0 / lx * pi * x) * cos(4.0 * pi * y) - 0.6 + max_value(200.0 * (0.01 - x ** 2 - (y - ly / 2) ** 2), 0.0) + max_value(100.0 * (x + y - lx - ly + 0.1), 0.0) + max_value(100.0 * (x - y - lx + 0.1), 0.0) ) # Avoid recording the operation interpolate into the tape. # Otherwise, the shape derivatives will not be correct with fda.stop_annotating(): phi = fd.interpolate(phi_expr, PHI) phi.rename("LevelSet") fd.File(output_dir + "phi_initial.pvd").write(phi) # Physics. Elasticity rho_min = 1e-5 beta = fd.Constant(200.0) def hs(phi, beta): return fd.Constant(1.0) / ( fd.Constant(1.0) + exp(-beta * phi) ) + fd.Constant(rho_min) H1_elem = fd.VectorElement("CG", mesh.ufl_cell(), 1) W = fd.FunctionSpace(mesh, H1_elem) u = fd.TrialFunction(W) v = fd.TestFunction(W) # Elasticity parameters E, nu = 1.0, 0.3 mu, lmbda = fd.Constant(E / (2 * (1 + nu))), fd.Constant( E * nu / ((1 + nu) * (1 - 2 * nu)) ) def epsilon(u): return sym(nabla_grad(u)) def sigma(v): return 2.0 * mu * epsilon(v) + lmbda * tr(epsilon(v)) * Identity(2) a = inner(hs(-phi, beta) * sigma(u), nabla_grad(v)) * dx t = fd.Constant((0.0, -75.0)) L = inner(t, v) * ds(2) bc = fd.DirichletBC(W, fd.Constant((0.0, 0.0)), 1) parameters = { "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "ksp_converged_reason": None, "pc_factor_mat_solver_type": "mumps", } u_sol = fd.Function(W) F = fd.action(a, u_sol) - L problem = fd.NonlinearVariationalProblem(F, u_sol, bcs=bc) solver = fd.NonlinearVariationalSolver( problem, solver_parameters=parameters ) solver.solve() # fd.solve( # a == L, u_sol, bcs=[bc], solver_parameters=parameters # ) # , nullspace=nullspace) with fda.stop_annotating(): fd.File("u_sol.pvd").write(u_sol) # Cost function: Compliance J = fd.assemble( fd.Constant(1e-2) * inner(hs(-phi, beta) * sigma(u_sol), epsilon(u_sol)) * dx ) # Constraint: Volume with fda.stop_annotating(): total_volume = fd.assemble(fd.Constant(1.0) * dx(domain=mesh)) VolPen = fd.assemble(hs(-phi, beta) * dx) # Needed to track the value of the volume VolControl = fda.Control(VolPen) Vval = total_volume / 2.0 phi_pvd = fd.File("phi_evolution.pvd", target_continuity=fd.H1) def deriv_cb(phi): with fda.stop_annotating(): phi_pvd.write(phi[0]) c = fda.Control(s) Jhat = LevelSetFunctional(J, c, phi, derivative_cb_pre=deriv_cb) Vhat = LevelSetFunctional(VolPen, c, phi) beta_param = 0.1 # Boundary conditions for the shape derivatives. # They must be zero at the boundary conditions. bcs_vel = fd.DirichletBC(S, fd.Constant((0.0, 0.0)), (1, 2)) # Regularize the shape derivatives reg_solver = RegularizationSolver( S, mesh, beta=beta_param, gamma=1.0e5, dx=dx, bcs=bcs_vel, output_dir=None, ) # Hamilton-Jacobi equation to advect the level set dt = 0.05 tol = 1e-5 # Optimization problem vol_constraint = Constraint(Vhat, Vval, VolControl) problem = InfDimProblem(Jhat, reg_solver, ineqconstraints=vol_constraint) parameters = { "ksp_type": "preonly", "pc_type": "lu", "mat_type": "aij", "ksp_converged_reason": None, "pc_factor_mat_solver_type": "mumps", } params = { "alphaC": 3.0, "K": 0.1, "debug": 5, "alphaJ": 1.0, "dt": dt, "maxtrials": 10, "maxit": n_iters, "itnormalisation": 50, "tol": tol, } results = nlspace_solve(problem, params) return results
def deriv_cb(phi): with fda.stop_annotating(): phi_pvd.write(phi[0])
def compliance_bridge(): parser = argparse.ArgumentParser(description="Heat exchanger") parser.add_argument( "--n_iters", dest="n_iters", type=int, action="store", default=1000, help="Number of optimization iterations", ) parser.add_argument( "--output_dir", dest="output_dir", type=str, action="store", default="./", help="Output directory", ) opts = parser.parse_args() output_dir = opts.output_dir # Elasticity parameters E, nu = 1.0, 0.3 rho_min = fd.Constant(1e-4) # Min Vol fraction eps = fd.Constant(100.0) # Heaviside parameter mu, lmbda = fd.Constant(E / (2 * (1 + nu))), fd.Constant( E * nu / ((1 + nu) * (1 - 2 * nu))) mesh = fd.RectangleMesh(20, 40, 0.5, 1, quadrilateral=True) mh = fd.MeshHierarchy(mesh, 1) m = fd.ExtrudedMeshHierarchy(mh, height=1, base_layer=40) mesh = m[-1] S = fd.VectorFunctionSpace(mesh, "CG", 1) s = fd.Function(S, name="deform") mesh.coordinates.assign(mesh.coordinates + s) x, y, z = fd.SpatialCoordinate(mesh) PHI = fd.FunctionSpace(mesh, "CG", 1) lx = 1.0 ly = 2.0 lz = ly phi_expr = (-cos(4.0 / lx * pi * x) * cos(4.0 * pi / ly * y) * cos(4.0 / lz * pi * z) - 0.6) with fda.stop_annotating(): phi = fd.interpolate(-phi_expr, PHI) phi.rename("LevelSet") H1 = fd.VectorElement("CG", mesh.ufl_cell(), 1) W = fd.FunctionSpace(mesh, H1) print(f"DOFS: {W.dim()}") modes = [fd.Function(W) for _ in range(6)] modes[0].interpolate(fd.Constant([1, 0, 0])) modes[1].interpolate(fd.Constant([0, 1, 0])) modes[2].interpolate(fd.Constant([0, 0, 1])) modes[3].interpolate(fd.as_vector([0, z, -y])) modes[4].interpolate(fd.as_vector([-z, 0, x])) modes[5].interpolate(fd.as_vector([y, -x, 0])) nullmodes = fd.VectorSpaceBasis(modes) # Make sure they're orthonormal. nullmodes.orthonormalize() u = fd.TrialFunction(W) v = fd.TestFunction(W) def epsilon(u): return sym(nabla_grad(u)) def sigma(v): return 2.0 * mu * epsilon(v) + lmbda * tr(epsilon(v)) * Identity(3) # Variational forms a = inner(hs(phi, eps, min_value=rho_min) * sigma(u), nabla_grad(v)) * dx(degree=2) t = fd.Constant((0.0, 0.0, -1.0e-1)) L = inner(t, v) * ds_t # Dirichlet BCs ylimits = (0.2, 1.8) xlimits = (0.4, 0.6) I_BC = create_function_marker(PHI, W, xlimits, ylimits) bc1 = MyBC(W, 0, I_BC) bc2 = fd.DirichletBC(W.sub(0), fd.Constant(0.0), 2) bc3 = fd.DirichletBC(W.sub(1), fd.Constant(0.0), 4) u_sol = fd.Function(W) fd.solve( a == L, u_sol, bcs=[bc1, bc2, bc3], solver_parameters=gamg_parameters, near_nullspace=nullmodes, ) # Cost function Jform = fd.assemble( inner(hs(phi, eps, min_value=rho_min) * sigma(u_sol), epsilon(u_sol)) * dx(degree=2)) # Constraint VolPen = fd.assemble(hs(phi, eps, min_value=rho_min) * dx(degree=2)) total_vol = fd.assemble(fd.Constant(1.0) * dx(domain=mesh), annotate=False) VolControl = fda.Control(VolPen) Vval = 0.15 * total_vol # Plotting global_counter1 = itertools.count() phi_pvd = fd.File(f"{output_dir}/level_set_evolution.pvd") def deriv_cb(phi): iter = next(global_counter1) if iter % 10 == 0: phi_pvd.write(phi[0]) c = fda.Control(s) Jhat = LevelSetFunctional(Jform, c, phi, derivative_cb_pre=deriv_cb) Vhat = LevelSetFunctional(VolPen, c, phi) # Regularization solver. Zero on the BCs boundaries beta_param = 0.005 bcs_vel_1 = MyBC(S, 0, I_BC) bcs_vel_2 = fd.DirichletBC(S, fd.Constant((0.0, 0.0, 0.0)), "top") bcs_vel = [bcs_vel_1, bcs_vel_2] reg_solver = RegularizationSolver( S, mesh, beta=beta_param, gamma=1.0e4, dx=dx, bcs=bcs_vel, output_dir=None, solver_parameters=gamg_parameters, ) dt = 0.05 tol = 1e-5 params = { "alphaC": 1.0, "K": 0.0001, "debug": 5, "maxit": opts.n_iters, "alphaJ": 2.0, "dt": dt, "maxtrials": 500, "tol_merit": 5e-2, # new merit can be within 0.5% of the previous merit "itnormalisation": 50, "tol": tol, } hj_solver_parameters["ts_dt"] = dt / 50.0 solver_parameters = { "hj_solver": hj_solver_parameters, "reinit_solver": reinit_solver_parameters, } vol_constraint = Constraint(Vhat, Vval, VolControl) problem = InfDimProblem( Jhat, reg_solver, ineqconstraints=vol_constraint, solver_parameters=solver_parameters, ) _ = nlspace_solve(problem, params)