def __init__(self, optimization_algorithm): """Initializes the line search Parameters ---------- optimization_algorithm : cashocs._shape_optimization.shape_optimization_algorithm.ShapeOptimizationAlgorithm the optimization problem of interest """ self.optimization_algorithm = optimization_algorithm self.config = self.optimization_algorithm.config self.optimization_problem = self.optimization_algorithm.optimization_problem self.form_handler = self.optimization_problem.form_handler self.mesh_handler = self.optimization_problem.mesh_handler self.deformation = fenics.Function(self.form_handler.deformation_space) self.stepsize = self.config.getfloat('OptimizationRoutine', 'initial_stepsize', fallback=1.0) self.epsilon_armijo = self.config.getfloat('OptimizationRoutine', 'epsilon_armijo', fallback=1e-4) self.beta_armijo = self.config.getfloat('OptimizationRoutine', 'beta_armijo', fallback=2.0) self.armijo_stepsize_initial = self.stepsize self.cost_functional = self.optimization_problem.reduced_cost_functional self.gradient = self.optimization_algorithm.gradient self.algorithm = _optimization_algorithm_configuration(self.config) self.is_newton_like = (self.algorithm == 'lbfgs') self.is_newton = self.algorithm in ['newton'] self.is_steepest_descent = (self.algorithm == 'gradient_descent') if self.is_newton: self.stepsize = 1.0
def solve_pde(self, name='pde'): u = fe.Function(self.function_space) v = fe.TestFunction(self.function_space) u_old = fe.project(self.u_0, self.function_space) # Todo: Average right hand side if we choose it non-constant flux = self.dt * fe.dot( self.composed_diff_coef * (fe.grad(u) + self.drift_function(u)), fe.grad(v)) * fe.dx bilin_part = u * v * fe.dx + flux funtional_part = self.rhs * v * self.dt * fe.dx + u_old * v * fe.dx full_form = bilin_part - funtional_part num_steps = int(self.T / self.dt) + 1 bc = fe.DirichletBC(self.function_space, self.u_boundary, MembraneSimulator.full_boundary) for n in range(num_steps): print("Step %d" % n) self.time += self.dt fe.solve(full_form == 0, u, bc) fe.plot(u) plt.savefig('images/plt%d.pdf' % n) plt.show() # print(fe.errornorm(u_old, u)) u_old.assign(u) self.file << (u, self.time) plt.figure() # u=u+1E-9 f = fe.plot(u) # f = fe.plot(u,norm=colors.LogNorm(vmin=1E-9,vmax=2E-4)) plt.rc('text', usetex=True) plt.colorbar(f, format='%.0e') plt.title(r'Macroscopic density $u(x,t=1)$ for $\alpha=%.1f$' % MembraneSimulator.alpha) plt.xlabel(r'$x_1$') plt.ylabel(r'$x_2$') plt.savefig('%s.pdf' % name) plt.show()
def __call__(self, u_test, return_sol=False, return_permeability=False): # Pad with zeros u_test = np.pad(u_test, (0, len(self.indices) - len(u_test))) # Assembling diffusivity log_coeff = sum([ui * fi for ui, fi in zip(u_test, self.functions)], 0) if return_permeability: return log_coeff ccode_coeff = sym.ccode(sym.exp(log_coeff)) diff = fen.Expression(ccode_coeff, degree=2) # Define bilinear form in variational problem a_bil = diff * fen.dot(fen.grad(self.trial_f), fen.grad( self.test_f)) * fen.dx # Compute solution sol = fen.Function(self.f_space) fen.solve(a_bil == self.lin_func, sol, self.bound_cond) evaluations = [sol(xi, yi) for xi, yi in zip(self.x_obs, self.y_obs)] # print("Evaluating G...:", np.array(evaluations)) return sol if return_sol else np.array(evaluations)
def __call__(self, mesh, V=None, Vc=None): boundaries, boundarymarkers, domainmarkers, dx, ds, V, Vc = SetupUnitMeshHelper( mesh, V, Vc) self._ds_markers = boundarymarkers self._dx_markers = domainmarkers self._dx = dx self._ds = ds self._boundaries = boundaries self._subdomains = self._boundaries u = df.TrialFunction(V) v = df.TestFunction(V) alpha = df.Function(Vc, name='conductivity') alpha.vector()[:] = 1 def set_alpha(x): alpha.vector()[:] = x self._set_alpha = set_alpha a = alpha * df.inner(df.grad(u), df.grad(v)) * dx return a, set_alpha, alpha, V, Vc
def __init__(self, mesh: fe.Mesh, density: fe.Expression, constitutive_model: ConstitutiveModelBase, bf: fe.Expression = fe.Expression('0', degree=0)): super().__init__(mesh, density, constitutive_model, bf) W = fe.VectorFunctionSpace(mesh, "P", 1) # Unknowns, values at previous step and test functions self.w = fe.Function(W) self.u, self.u0 = self.w, fe.Function(W) self.v, self.v0 = fe.Function(W), fe.Function(W) self.a, self.a0 = fe.Function(W), fe.Function(W) # self.a0 = fe.Function(fe.FunctionSpace(mesh, element_v)) self.ut = fe.TestFunction(W) self.F = kin.def_grad(self.u) self.F0 = kin.def_grad(self.u0)
def __init__(self, mesh: fe.Mesh, constitutive_model: ConstitutiveModelBase, density: fe.Expression = fe.Expression('0', degree=0), bf: fe.Expression = fe.Expression('0', degree=0), user_output_fn: callable = None): W = fe.VectorFunctionSpace(mesh, "P", 1) super().__init__(mesh, constitutive_model, W, bf) self._density = density self.user_output_fn = user_output_fn # Unknowns, values at previous step and test functions self.w = fe.Function(W) self.u, self.u0 = self.w, fe.Function(W) self.v, self.v0 = fe.Function(W), fe.Function(W) self.a, self.a0 = fe.Function(W), fe.Function(W) # self.a0 = fe.Function(fe.FunctionSpace(mesh, element_v)) self.ut = fe.TestFunction(W) self.F = kin.def_grad(self.u) self.F0 = kin.def_grad(self.u0) self.output_fn_map = { Outputs.stress: self.write_stress, Outputs.strain: self.write_strain, Outputs.displacement: self.write_u } self.d_LHS = fe.inner(self.F * constitutive_model.stress(self.u), fe.grad(self.ut)) * fe.dx self.d_RHS = (fe.inner(fe.Constant((0., 0., 0.)), self.ut) * fe.dx)
def runModelButt(self): if len(markers) > 0: try: self.runButt.setEnabled(False) self.dr = float(self.sptlResLineEdit.text()) # dr = 150 self.pauseButt.setEnabled(True) interpolateData(True, self.dr,{}) ########################################### ### INTERPOLATE DATA SO EVEN INTERVAL ### ########################################### ''' Interpolating data at an even interval so the data points align with the invterval mesh. ''' self.thickness1dInterp = interp1d(thickness.distanceData, thickness.pathData) self.bed1dInterp = interp1d(bed.distanceData, bed.pathData) self.surface1dInterp = interp1d(surface.distanceData, surface.pathData) self.smb1dInterp = interp1d(smb.distanceData, smb.pathData) self.velocity1dInterp = interp1d(velocity.distanceData, velocity.pathData) self.t2m1dInterp = interp1d(t2m.distanceData, t2m.pathData) # N is the number of total data points including the last # Data points on interval [0, N*dr] inclusive on both ends self.N = int(np.floor(bed.distanceData[-1] / float(self.dr))) # length of path / resolution self.x = np.arange(0, (self.N + 1) * self.dr, self.dr) # start point, end point, number of segments. END POINT NOT INCLUDED! self.mesh = fc.IntervalMesh(self.N, 0, self.dr * self.N) # number of cells, start point, end point self.thicknessModelData = self.thickness1dInterp(self.x) self.bedModelData = self.bed1dInterp(self.x) self.surfaceModelData = self.surface1dInterp(self.x) self.smbModelData = self.smb1dInterp(self.x) self.velocityModelData = self.velocity1dInterp(self.x) self.t2mModelData = self.t2m1dInterp(self.x) self.THICKLIMIT = 10. # Ice is never less than this thick self.H = self.surfaceModelData - self.bedModelData self.surfaceModelData[self.H <= self.THICKLIMIT] = self.bedModelData[self.H <= self.THICKLIMIT] # FIXME the intervalMesh is consistantly 150 between each datapoint this not true for the data being sent self.hdf_name = '.data/latest_profile.h5' self.hfile = fc.HDF5File(self.mesh.mpi_comm(), self.hdf_name, "w") self.V = fc.FunctionSpace(self.mesh, "CG", 1) self.functThickness = fc.Function(self.V, name="Thickness") self.functBed = fc.Function(self.V, name="Bed") self.functSurface = fc.Function(self.V, name="Surface") self.functSMB = fc.Function(self.V, name='SMB') self.functVelocity = fc.Function(self.V, name='Velocity') self.functT2m = fc.Function(self.V, name='T2m') surface.pathPlotItem.setData(self.x, self.surfaceModelData) pg.QtGui.QApplication.processEvents() self.functThickness.vector()[:] = self.thicknessModelData self.functBed.vector()[:] = self.bedModelData self.functSurface.vector()[:] = self.surfaceModelData self.functSMB.vector()[:] = self.smbModelData self.functVelocity.vector()[:] = self.velocityModelData self.functT2m.vector()[:] = self.t2mModelData self.hfile.write(self.functThickness.vector(), "/thickness") self.hfile.write(self.functBed.vector(), "/bed") self.hfile.write(self.functSurface.vector(), "/surface") self.hfile.write(self.functSMB.vector(), "/smb") self.hfile.write(self.functVelocity.vector(), "/velocity") self.hfile.write(self.functT2m.vector(), "/t2m") self.hfile.write(self.mesh, "/mesh") self.hfile.close() self.runModel() except ValueError: print 'ERROR: Must have valid spatial resolution.'
def boundary(x, on_boundary): return on_boundary bc = fex.DirichletBC(V, u_D, boundary) # Define variational problem u = fex.TrialFunction(V) v = fex.TestFunction(V) f = fex.Constant(-6.0) a = fex.dot(fex.grad(u), fex.grad(v)) * fex.dx L = f * v * fex.dx # Compute solution u = fex.Function(V) fex.solve(a == L, u, bc) print(u) # Plot solution and mesh plt.subplot(2, 1, 1) fex.plot(u) #define the boundary conditions plt.subplot(2, 1, 2) fex.plot(mesh) plt.savefig('possion_fex2.png') #define the boundary conditions # Save solution to file in VTK format vtkfile = fex.File('poisson/solution.pvd') vtkfile << u # Compute error in L2 norm
def staggered_solve(self): self.U = fe.VectorFunctionSpace(self.mesh, 'CG', 1) self.W = fe.FunctionSpace(self.mesh, 'CG', 1) self.WW = fe.FunctionSpace(self.mesh, 'DG', 0) self.EE = fe.TensorFunctionSpace(self.mesh, 'DG', 0) self.MM = fe.VectorFunctionSpace(self.mesh, 'CG', 1) self.eta = fe.TestFunction(self.U) self.zeta = fe.TestFunction(self.W) q = fe.TestFunction(self.WW) del_x = fe.TrialFunction(self.U) del_d = fe.TrialFunction(self.W) p = fe.TrialFunction(self.WW) self.x_new = fe.Function(self.U, name="u") self.d_new = fe.Function(self.W, name="d") self.d_pre = fe.Function(self.W) self.x_pre = fe.Function(self.U) x_old = fe.Function(self.U) d_old = fe.Function(self.W) self.H_old = fe.Function(self.WW) self.map_plot = fe.Function(self.MM, name="m") e = fe.Function(self.EE, name="e") self.create_custom_xdmf_files() self.file_results = fe.XDMFFile('data/xdmf/{}/u.xdmf'.format( self.case_name)) self.file_results.parameters["functions_share_mesh"] = True vtkfile_e = fe.File('data/pvd/simulation/{}/e.pvd'.format( self.case_name)) vtkfile_u = fe.File('data/pvd/simulation/{}/u.pvd'.format( self.case_name)) vtkfile_d = fe.File('data/pvd/simulation/{}/d.pvd'.format( self.case_name)) for i, (disp, rp) in enumerate( zip(self.displacements, self.relaxation_parameters)): print('\n') print( '=================================================================================' ) print('>> Step {}, disp boundary condition = {} [mm]'.format( i, disp)) print( '=================================================================================' ) self.i = i self.update_weak_form_due_to_Model_C_bug() if self.update_weak_form: self.set_bcs_staggered() print("Update weak form...") self.build_weak_form_staggered() print("Taking derivatives of weak form...") J_u = fe.derivative(self.G_u, self.x_new, del_x) J_d = fe.derivative(self.G_d, self.d_new, del_d) print("Define nonlinear problems...") p_u = fe.NonlinearVariationalProblem(self.G_u, self.x_new, self.BC_u, J_u) p_d = fe.NonlinearVariationalProblem(self.G_d, self.d_new, self.BC_d, J_d) print("Define solvers...") solver_u = fe.NonlinearVariationalSolver(p_u) solver_d = fe.NonlinearVariationalSolver(p_d) self.update_weak_form = False print("Update history weak form") a = p * q * fe.dx L = history(self.H_old, self.update_history(), self.psi_cr) * q * fe.dx if self.map_flag: self.interpolate_map() # delta_x = self.x - self.x_hat # self.map_plot.assign(fe.project(delta_x, self.MM)) self.presLoad.t = disp newton_prm = solver_u.parameters['newton_solver'] newton_prm['maximum_iterations'] = 100 # newton_prm['absolute_tolerance'] = 1e-8 newton_prm['relaxation_parameter'] = rp newton_prm = solver_d.parameters['newton_solver'] newton_prm['maximum_iterations'] = 100 # newton_prm['absolute_tolerance'] = 1e-8 newton_prm['relaxation_parameter'] = rp vtkfile_e_staggered = fe.File( 'data/pvd/simulation/{}/step{}/e.pvd'.format( self.case_name, i)) vtkfile_u_staggered = fe.File( 'data/pvd/simulation/{}/step{}/u.pvd'.format( self.case_name, i)) vtkfile_d_staggered = fe.File( 'data/pvd/simulation/{}/step{}/d.pvd'.format( self.case_name, i)) iteration = 0 err = 1. while err > self.staggered_tol: iteration += 1 solver_d.solve() solver_u.solve() if self.solution_scheme == 'explicit': break # # Remarks(Tianju): self.x_new.vector() does not behave as expected: producing nan values # The following lines of codes cause issues # We use an error measure similar in https://doi.org/10.1007/s10704-019-00372-y # np_x_new = np.asarray(self.x_new.vector()) # np_d_new = np.asarray(self.d_new.vector()) # np_x_old = np.asarray(x_old.vector()) # np_d_old = np.asarray(d_old.vector()) # err_x = np.linalg.norm(np_x_new - np_x_old) / np.sqrt(len(np_x_new)) # err_d = np.linalg.norm(np_d_new - np_d_old) / np.sqrt(len(np_d_new)) # err = max(err_x, err_d) # # Remarks(Tianju): dolfin (2019.1.0) errornorm function has severe bugs not behave as expected # The bug seems to be fixed in later versions # The following sometimes produces nonzero results in dolfin (2019.1.0) # print(fe.errornorm(self.d_new, self.d_new, norm_type='l2')) err_x = fe.errornorm(self.x_new, x_old, norm_type='l2') err_d = fe.errornorm(self.d_new, d_old, norm_type='l2') err = max(err_x, err_d) x_old.assign(self.x_new) d_old.assign(self.d_new) e.assign( fe.project(strain(self.mfem_grad(self.x_new)), self.EE)) print( '---------------------------------------------------------------------------------' ) print( '>> iteration. {}, err_u = {:.5}, err_d = {:.5}, error = {:.5}' .format(iteration, err_x, err_d, err)) print( '---------------------------------------------------------------------------------' ) # vtkfile_e_staggered << e # vtkfile_u_staggered << self.x_new # vtkfile_d_staggered << self.d_new if err < self.staggered_tol or iteration >= self.staggered_maxiter: print( '=================================================================================' ) print('\n') break print("L2 projection to update the history function...") fe.solve(a == L, self.H_old, []) # self.d_pre.assign(self.d_new) # self.H_old.assign(fe.project(history(self.H_old, self.update_history(), self.psi_cr), self.WW)) if self.map_flag and not self.finish_flag: self.update_map() if self.compute_and_save_intermediate_results: print("Save files...") self.file_results.write(e, i) self.file_results.write(self.x_new, i) self.file_results.write(self.d_new, i) self.file_results.write(self.map_plot, i) vtkfile_e << e vtkfile_u << self.x_new vtkfile_d << self.d_new # Assume boundary is not affected by the map. # There's no need to use the mfem_grad wrapper so that fe.grad is used for speed-up print("Define forces...") sigma = cauchy_stress_plus(strain(fe.grad(self.x_new)), self.psi) sigma_minus = cauchy_stress_minus(strain(fe.grad(self.x_new)), self.psi_minus) sigma_plus = cauchy_stress_plus(strain(fe.grad(self.x_new)), self.psi_plus) sigma_degraded = g_d(self.d_new) * sigma_plus + sigma_minus print("Compute forces...") if self.case_name == 'pure_shear': f_full = float(fe.assemble(sigma[0, 1] * self.ds(1))) f_degraded = float( fe.assemble(sigma_degraded[0, 1] * self.ds(1))) else: f_full = float(fe.assemble(sigma[1, 1] * self.ds(1))) f_degraded = float( fe.assemble(sigma_degraded[1, 1] * self.ds(1))) print("Force full is {}".format(f_full)) print("Force degraded is {}".format(f_degraded)) self.delta_u_recorded.append(disp) self.force_full.append(f_full) self.force_degraded.append(f_degraded) # if force_upper < 0.5 and i > 10: # break if self.display_intermediate_results and i % 10 == 0: self.show_force_displacement() self.save_data_in_loop() if self.display_intermediate_results: plt.ioff() plt.show()
def demo64(self, permeability, obs_case=1): mesh = UnitSquareMesh(63, 63) ak_values = permeability flux_order = 3 s = scenarios.darcy_problem_1() DRT = fenics.FiniteElement("DRT", mesh.ufl_cell(), flux_order) # Lagrange CG = fenics.FiniteElement("CG", mesh.ufl_cell(), flux_order + 1) if s.integral_constraint: # From https://fenicsproject.org/qa/14184/how-to-solve-linear-system-with-constaint R = fenics.FiniteElement("R", mesh.ufl_cell(), 0) W = fenics.FunctionSpace(mesh, fenics.MixedElement([DRT, CG, R])) # Define trial and test functions (sigma, u, r) = fenics.TrialFunctions(W) (tau, v, r_) = fenics.TestFunctions(W) else: W = fenics.FunctionSpace(mesh, DRT * CG) # Define trial and test functions (sigma, u) = fenics.TrialFunctions(W) (tau, v) = fenics.TestFunctions(W) f = s.source_function g = s.g # Define property field function W_CG = fenics.FunctionSpace(mesh, "Lagrange", 1) if s.ak is None: ak = property_field.get_conductivity(W_CG, ak_values) else: ak = s.ak # Define variational form a = (fenics.dot(sigma, tau) + fenics.dot(ak * fenics.grad(u), tau) + fenics.dot(sigma, fenics.grad(v))) * fenics.dx L = -f * v * fenics.dx + g * v * fenics.ds # L = 0 if s.integral_constraint: # Lagrange multiplier? See above link. a += r_ * u * fenics.dx + v * r * fenics.dx # Define Dirichlet BC bc = fenics.DirichletBC(W.sub(1), s.dirichlet_bc, s.gamma_dirichlet) # Compute solution w = fenics.Function(W) fenics.solve(a == L, w, bc) # fenics.solve(a == L, w) if s.integral_constraint: (sigma, u, r) = w.split() else: (sigma, u) = w.split() x = u.compute_vertex_values(mesh) x2 = sigma.compute_vertex_values(mesh) p = x pre = p.reshape((64, 64)) vx = x2[:4096].reshape((64, 64)) vy = x2[4096:].reshape((64, 64)) if obs_case == 1: dd = np.zeros([8, 8]) pos = np.full((8 * 8, 2), 0) col = [4, 12, 20, 28, 36, 44, 52, 60] position = [4, 12, 20, 28, 36, 44, 52, 60] for i in range(8): for j in range(8): row = position pos[8 * i + j, :] = [col[i], row[j]] dd[i, j] = pre[col[i], row[j]] like = dd.reshape(8 * 8, ) return like, pre, vx, vy, ak_values, pos
b = fe.Expression(('0', '0'), degree=DEG) # forcing nu = fe.Constant(2e-6) rho = fe.Constant(1) RE = 0.01 lmx = 1 # mixing length dt = 0.1 # Re = 10 / 1e-4 = 1e5 V = fe.VectorElement("Lagrange", mesh.ufl_cell(), 2) P = fe.FiniteElement("Lagrange", mesh.ufl_cell(), 1) NU = fe.FiniteElement("Lagrange", mesh.ufl_cell(), 1) if MODEL: M = fe.MixedElement([V, P, NU]) else: M = fe.MixedElement([V, P]) W = fe.FunctionSpace(mesh, M) W0 = fe.Function(W) We = fe.Function(W) u0, p0 = fe.split(We) #u0 = fe.Function((W0[0], W0[1]), 'Velocity000023.vtu') #p0 = fe.Function(W0[2]) v, q = fe.TestFunctions(W) #u, p = fe.split(W0) u, p = (fe.as_vector((W0[0], W0[1])), W0[2]) #------------------------------------------------------- # Defining essential/Dirichlet boundary conditions # Step 1: Identify all boundary segments forming Gamma_d #------------------------------------------------------- # (-3., 2.5) # | # |
hessp=SR1(), tol=1e-7, constraints=volume_constraint, bounds=((0, 1.0),) * A.dim(), options={"verbose": 3, "gtol": 1e-7, "maxiter": 20}, ) q.assign(0.1) res = minimize( min_f, res.x, method="trust-constr", jac=True, hessp=SR1(), tol=1e-7, constraints=volume_constraint, bounds=((0, 1.0),) * A.dim(), options={"verbose": 3, "gtol": 1e-7, "maxiter": 100}, ) rho_opt_final = from_numpy(res.x, fenics.Function(A)) c = fenics.plot(rho_opt_final) plt.colorbar(c) plt.show() rho_opt_file = fenics.XDMFFile( fenics.MPI.comm_world, "output/control_solution_final.xdmf" ) rho_opt_file.write(rho_opt_final)
def __init__(self, lagrangian, bcs_list, states, controls, adjoints, config, riesz_scalar_products, control_constraints, ksp_options, adjoint_ksp_options, require_control_constraints): """Initializes the ControlFormHandler class. Parameters ---------- lagrangian : cashocs._forms.Lagrangian The lagrangian corresponding to the optimization problem. bcs_list : list[list[dolfin.fem.dirichletbc.DirichletBC]] The list of DirichletBCs for the state equation. states : list[dolfin.function.function.Function] The function that acts as the state variable. controls : list[dolfin.function.function.Function] The function that acts as the control variable. adjoints : list[dolfin.function.function.Function] The function that acts as the adjoint variable. config : configparser.ConfigParser The configparser object of the config file. riesz_scalar_products : list[ufl.form.Form] The UFL forms of the scalar products for the control variables. control_constraints : list[list[dolfin.function.function.Function]] The control constraints of the problem. ksp_options : list[list[list[str]]] The list of command line options for the KSP for the state systems. adjoint_ksp_options : list[list[list[str]]] The list of command line options for the KSP for the adjoint systems. require_control_constraints : list[bool] A list of boolean flags that indicates, whether the i-th control has actual control constraints present. """ FormHandler.__init__(self, lagrangian, bcs_list, states, adjoints, config, ksp_options, adjoint_ksp_options) # Initialize the attributes from the arguments self.controls = controls self.riesz_scalar_products = riesz_scalar_products self.control_constraints = control_constraints self.require_control_constraints = require_control_constraints self.control_dim = len(self.controls) self.control_spaces = [x.function_space() for x in self.controls] # Define the necessary functions self.states_prime = [fenics.Function(V) for V in self.state_spaces] self.adjoints_prime = [fenics.Function(V) for V in self.adjoint_spaces] self.test_directions = [ fenics.Function(V) for V in self.control_spaces ] self.trial_functions_control = [ fenics.TrialFunction(V) for V in self.control_spaces ] self.test_functions_control = [ fenics.TestFunction(V) for V in self.control_spaces ] self.temp = [fenics.Function(V) for V in self.control_spaces] # Compute the necessary equations self.__compute_gradient_equations() if self.opt_algo == 'newton' or \ (self.opt_algo == 'pdas' and self.inner_pdas == 'newton'): self.__compute_newton_forms() # Initialize the scalar products fenics_scalar_product_matrices = [ fenics.assemble(self.riesz_scalar_products[i], keep_diagonal=True) for i in range(self.control_dim) ] self.scalar_products_matrices = [ fenics.as_backend_type(fenics_scalar_product_matrices[i]).mat() for i in range(self.control_dim) ] copy_scalar_product_matrices = [ fenics_scalar_product_matrices[i].copy() for i in range(self.control_dim) ] [ copy_scalar_product_matrices[i].ident_zeros() for i in range(self.control_dim) ] self.riesz_projection_matrices = [ fenics.as_backend_type(copy_scalar_product_matrices[i]).mat() for i in range(self.control_dim) ] # Test for symmetry of the scalar products for i in range(self.control_dim): if not self.riesz_projection_matrices[i].isSymmetric(): if not self.riesz_projection_matrices[i].isSymmetric(1e-15): if not (self.riesz_projection_matrices[i] - self.riesz_projection_matrices[i].copy().transpose( )).norm() / self.riesz_projection_matrices[i].norm( ) < 1e-15: raise InputError( 'cashocs._forms.ControlFormHandler', 'riesz_scalar_products', 'Supplied scalar product form is not symmetric.')
def navierStokes(projectId, mesh, faceSets, boundarySets, config): log("Navier Stokes Analysis has started") # this is the default directory, when user request for download all files in this directory is being compressed and sent to the user resultDir = "./Results/" if len(config["steps"]) > 1: return "more than 1 step is not supported yet" # config is a dictionary containing all the user inputs for solver configurations t_init = 0.0 t_final = float(config['steps'][0]["finalTime"]) t_num = int(config['steps'][0]["iterationNo"]) dt = ((t_final - t_init) / t_num) t = t_init # # Viscosity coefficient. # nu = float(config['materials'][0]["viscosity"]) rho = float(config['materials'][0]["density"]) # # Declare Finite Element Spaces # do not use triangle directly P2 = fn.VectorElement("P", mesh.ufl_cell(), 2) P1 = fn.FiniteElement("P", mesh.ufl_cell(), 1) TH = fn.MixedElement([P2, P1]) V = fn.VectorFunctionSpace(mesh, "P", 2) Q = fn.FunctionSpace(mesh, "P", 1) W = fn.FunctionSpace(mesh, TH) # # Declare Finite Element Functions # (u, p) = fn.TrialFunctions(W) (v, q) = fn.TestFunctions(W) w = fn.Function(W) u0 = fn.Function(V) p0 = fn.Function(Q) # # Macros needed for weak formulation. # def contract(u, v): return fn.inner(fn.nabla_grad(u), fn.nabla_grad(v)) def b(u, v, w): return 0.5 * (fn.inner(fn.dot(u, fn.nabla_grad(v)), w) - fn.inner(fn.dot(u, fn.nabla_grad(w)), v)) # Define boundaries bcs = [] for BC in config['BCs']: if BC["boundaryType"] == "wall": for edge in json.loads(BC["edges"]): bcs.append( fn.DirichletBC(W.sub(0), fn.Constant((0.0, 0.0, 0.0)), boundarySets, int(edge), method='topological')) if BC["boundaryType"] == "inlet": vel = json.loads(BC['value']) for edge in json.loads(BC["edges"]): bcs.append( fn.DirichletBC(W.sub(0), fn.Expression( (str(vel[0]), str(vel[1]), str(vel[2])), degree=2), boundarySets, int(edge), method='topological')) if BC["boundaryType"] == "outlet": for edge in json.loads(BC["edges"]): bcs.append( fn.DirichletBC(W.sub(1), fn.Constant(float(BC['value'])), boundarySets, int(edge), method='topological')) f = fn.Constant((0.0, 0.0, 0.0)) # weak form NSE NSE = (1.0/dt)*fn.inner(u, v)*fn.dx + b(u0, u, v)*fn.dx + nu * \ contract(u, v)*fn.dx - fn.div(v)*p*fn.dx + q*fn.div(u)*fn.dx LNSE = fn.inner(f, v) * fn.dx + (1. / dt) * fn.inner(u0, v) * fn.dx velocity_file = fn.XDMFFile(resultDir + "/vel.xdmf") pressure_file = fn.XDMFFile(resultDir + "/pressure.xdmf") velocity_file.parameters["flush_output"] = True velocity_file.parameters["functions_share_mesh"] = True pressure_file.parameters["flush_output"] = True pressure_file.parameters["functions_share_mesh"] = True # # code for projecting a boundary condition into a file for visualization # # for bc in bcs: # bc.apply(w.vector()) # fn.File("para_plotting/bc.pvd") << w.sub(0) for jj in range(0, t_num): t = t + dt # print('t = ' + str(t)) A, b = fn.assemble_system(NSE, LNSE, bcs) fn.solve(A, w.vector(), b) # fn.solve(NSE==LNSE,w,bcs) fn.assign(u0, w.sub(0)) fn.assign(p0, w.sub(1)) # Save Solutions to Paraview File if (jj % 20 == 0): velocity_file.write(u0, t) pressure_file.write(p0, t) sendFile(projectId, resultDir + "vel.xdmf") sendFile(projectId, resultDir + "vel.h5") sendFile(projectId, resultDir + "pressure.xdmf") sendFile(projectId, resultDir + "pressure.h5") statusUpdate(projectId, "STARTED", {"progress": jj / t_num * 100})
def forward(lmin, pml, steps, Folder): """ Algorithm to solve the forward problem *Input arguments minl: Minimum lenght of element pml: Size of the absorbing layer in km steps: Number of timesteps Folder: Folder name for results *Output arguments c: Field of propagation speed in domain eta: Field of damping in domain histrec: Historical data receivers """ histrec = '' # Create and define function space V = fn.FunctionSpace(mesh, "CG", 1) w = fn.TrialFunction(V) v = fn.TestFunction(V) # Boundary conditions u0 = 0.0 bc = fn.DirichletBC(V, 0.0, fn.DomainBoundary()) # State variable and source space functions w = fn.Function(V, name="Veloc") w_ant1 = fn.Function(V) w_ant2 = fn.Function(V) q = fn.Function(V, name="Sourc") # Velocity mapping c_func = vel_c() c = fn.interpolate(c_func, V) velp_file = fn.File(Folder + "/Velp.pvd") velp_file << c # Damping mapping damping_func = damping(c.vector().get_local().min()) eta = fn.interpolate(damping_func, V) damp_file = fn.File(Folder + "/Damp.pvd") damp_file << eta # Current time we are solving for t = 0. # Number of timesteps solved ntimestep = int(0) # dt computation dt = critical_dt(lmin, c.vector().get_local().max(), steps) # Final time T = steps*dt print("Time step:", dt, "s") # "Bilinear term" def aterm(u, v, dt, c, eta): termgrad = dt**2*fn.inner(c, c)*fn.inner(fn.grad(u), fn.grad(v))*fn.dx termvare = (1.0 + dt*eta*fn.inner(c, c))*fn.inner(u, v)*fn.dx termboun = (dt**2*c*c)*fn.inner(fn.grad(u), n)*v*fn.ds return termgrad + termvare - termboun # Source term def lsourc(u_ant1, u_ant2, v, dt, c, q, eta): termua1 = (-2. + dt*eta*fn.inner(c, c))*fn.inner(u_ant1, v)*fn.dx termua2 = fn.inner(u_ant2, v)*fn.dx termsou = (dt**2*fn.inner(c, c))*fn.inner(q, v)*fn.dx return termua1 + termua2 - termsou # Output file names Exct = fn.File(Folder+"/Exct.pvd") Wave = fn.File(Folder+"/Wave.pvd") while True: # Update the time it is solving for print("Step: {0:1d} - Time: {1:1.4f}".format(ntimestep, t), "s") # Ricker source for time t ExcSource = RickerSource(t, tol=lmin/2) q.assign(fn.interpolate(ExcSource, V)) # Time integration loop if ntimestep < 1: g = fn.interpolate(fn.Expression('0.0', degree=2), V) w.assign(g) # assign initial guess for solver w_ant1.assign(g) # assign initial guess for solver w_ant2.assign(g) # assign initial guess for solver else: a = aterm(w, v, dt, c, eta) L = lsourc(w_ant1, w_ant2, v, dt, c, q, eta) #solve equation fn.solve(a + L == 0, w, bcs=bc, solver_parameters={"newton_solver": {"maximum_iterations": forward_max_it, "absolute_tolerance": forward_tol, "relative_tolerance": relativ_tol}}) # Cycling the variables w_ant2.assign(w_ant1) w_ant1.assign(w) #Output files # histrec += Receiver(t, posrec, pml, w) Exct << (q, t) Wave << (w, t) t += dt ntimestep += 1 if t >= T: break return c, eta, histrec
bcU = fn.DirichletBC(Hh.sub(0), u_g, bdry, 31) bcP = fn.DirichletBC(Hh.sub(2), p_g, bdry, 32) bcs = [bcU, bcP] # ******** Weak forms ********** # PLeft = 2*mu*fn.inner(strain(u),strain(v)) * fn.dx \ - fn.div(v) * phi * fn.dx \ + (c0/alpha + 1.0/lmbda)* p * q * fn.dx \ + kappa/(alpha*nu) * fn.dot(fn.grad(p),fn.grad(q)) * fn.dx \ - 1.0/lmbda * phi * q * fn.dx \ - fn.div(u) * psi * fn.dx \ + 1.0/lmbda * psi * p * fn.dx \ - 1.0/lmbda * phi * psi * fn.dx PRight = fn.dot(f, v) * fn.dx + fn.dot(h_g, v) * ds(32) Sol = fn.Function(Hh) # solve fn.solve(PLeft == PRight, Sol, bcs) u, phi, p = Sol.split() u.rename("u", "u") fileU << u p.rename("p", "p") fileP << p phi.rename("phi", "phi") filePHI << phi
def __init__(self, state_forms, bcs_list, cost_functional_form, states, controls, adjoints, config=None, riesz_scalar_products=None, control_constraints=None, initial_guess=None, ksp_options=None, adjoint_ksp_options=None, desired_weights=None): r"""This is used to generate all classes and functionalities. First ensures consistent input, afterwards, the solution algorithm is initialized. Parameters ---------- state_forms : ufl.form.Form or list[ufl.form.Form] The weak form of the state equation (user implemented). Can be either a single UFL form, or a (ordered) list of UFL forms. bcs_list : list[dolfin.fem.dirichletbc.DirichletBC] or list[list[dolfin.fem.dirichletbc.DirichletBC]] or dolfin.fem.dirichletbc.DirichletBC or None The list of DirichletBC objects describing Dirichlet (essential) boundary conditions. If this is ``None``, then no Dirichlet boundary conditions are imposed. cost_functional_form : ufl.form.Form or list[ufl.form.Form] UFL form of the cost functional. states : dolfin.function.function.Function or list[dolfin.function.function.Function] The state variable(s), can either be a :py:class:`fenics.Function`, or a list of these. controls : dolfin.function.function.Function or list[dolfin.function.function.Function] The control variable(s), can either be a :py:class:`fenics.Function`, or a list of these. adjoints : dolfin.function.function.Function or list[dolfin.function.function.Function] The adjoint variable(s), can either be a :py:class:`fenics.Function`, or a (ordered) list of these. config : configparser.ConfigParser or None The config file for the problem, generated via :py:func:`cashocs.create_config`. Alternatively, this can also be ``None``, in which case the default configurations are used, except for the optimization algorithm. This has then to be specified in the :py:meth:`solve <cashocs.OptimalControlProblem.solve>` method. The default is ``None``. riesz_scalar_products : None or ufl.form.Form or list[ufl.form.Form], optional The scalar products of the control space. Can either be None, a single UFL form, or a (ordered) list of UFL forms. If ``None``, the :math:`L^2(\Omega)` product is used. (default is ``None``). control_constraints : None or list[dolfin.function.function.Function] or list[float] or list[list[dolfin.function.function.Function]] or list[list[float]], optional Box constraints posed on the control, ``None`` means that there are none (default is ``None``). The (inner) lists should contain two elements of the form ``[u_a, u_b]``, where ``u_a`` is the lower, and ``u_b`` the upper bound. initial_guess : list[dolfin.function.function.Function], optional List of functions that act as initial guess for the state variables, should be valid input for :py:func:`fenics.assign`. Defaults to ``None``, which means a zero initial guess. ksp_options : list[list[str]] or list[list[list[str]]] or None, optional A list of strings corresponding to command line options for PETSc, used to solve the state systems. If this is ``None``, then the direct solver mumps is used (default is ``None``). adjoint_ksp_options : list[list[str]] or list[list[list[str]]] or None A list of strings corresponding to command line options for PETSc, used to solve the adjoint systems. If this is ``None``, then the same options as for the state systems are used (default is ``None``). Examples -------- Examples how to use this class can be found in the :ref:`tutorial <tutorial_index>`. """ OptimizationProblem.__init__(self, state_forms, bcs_list, cost_functional_form, states, adjoints, config, initial_guess, ksp_options, adjoint_ksp_options, desired_weights) ### Overloading, such that we do not have to use lists for a single state and a single control ### controls try: if type(controls) == list and len(controls) > 0: for i in range(len(controls)): if controls[i].__module__ == 'dolfin.function.function' and type(controls[i]).__name__ == 'Function': pass else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'controls', 'controls have to be fenics Functions.') self.controls = controls elif controls.__module__ == 'dolfin.function.function' and type(controls).__name__ == 'Function': self.controls = [controls] else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'controls', 'Type of controls is wrong.') except: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'controls', 'Type of controls is wrong.') self.control_dim = len(self.controls) ### riesz_scalar_products if riesz_scalar_products is None: dx = fenics.Measure('dx', self.controls[0].function_space().mesh()) self.riesz_scalar_products = [fenics.inner(fenics.TrialFunction(self.controls[i].function_space()), fenics.TestFunction(self.controls[i].function_space())) * dx for i in range(len(self.controls))] else: try: if type(riesz_scalar_products)==list and len(riesz_scalar_products) > 0: for i in range(len(riesz_scalar_products)): if riesz_scalar_products[i].__module__== 'ufl.form' and type(riesz_scalar_products[i]).__name__== 'Form': pass else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'riesz_scalar_products', 'riesz_scalar_products have to be ufl forms') self.riesz_scalar_products = riesz_scalar_products elif riesz_scalar_products.__module__== 'ufl.form' and type(riesz_scalar_products).__name__== 'Form': self.riesz_scalar_products = [riesz_scalar_products] else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'riesz_scalar_products', 'riesz_scalar_products have to be ufl forms') except: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'riesz_scalar_products', 'riesz_scalar_products have to be ufl forms') ### control_constraints if control_constraints is None: self.control_constraints = [] for control in self.controls: u_a = fenics.Function(control.function_space()) u_a.vector()[:] = float('-inf') u_b = fenics.Function(control.function_space()) u_b.vector()[:] = float('inf') self.control_constraints.append([u_a, u_b]) else: try: if type(control_constraints) == list and len(control_constraints) > 0: if type(control_constraints[0]) == list: for i in range(len(control_constraints)): if type(control_constraints[i]) == list and len(control_constraints[i]) == 2: for j in range(2): if type(control_constraints[i][j]) in [float, int]: pass elif control_constraints[i][j].__module__ == 'dolfin.function.function' and type(control_constraints[i][j]).__name__ == 'Function': pass else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'control_constraints has to be a list containing upper and lower bounds') pass else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'control_constraints has to be a list containing upper and lower bounds') self.control_constraints = control_constraints elif (type(control_constraints[0]) in [float, int] or (control_constraints[0].__module__ == 'dolfin.function.function' and type(control_constraints[0]).__name__=='Function')) \ and (type(control_constraints[1]) in [float, int] or (control_constraints[1].__module__ == 'dolfin.function.function' and type(control_constraints[1]).__name__=='Function')): self.control_constraints = [control_constraints] else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'control_constraints has to be a list containing upper and lower bounds') except: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'control_constraints has to be a list containing upper and lower bounds') # recast floats into functions for compatibility temp_constraints = self.control_constraints[:] self.control_constraints = [] for idx, pair in enumerate(temp_constraints): if type(pair[0]) in [float, int]: lower_bound = fenics.Function(self.controls[idx].function_space()) lower_bound.vector()[:] = pair[0] elif pair[0].__module__ == 'dolfin.function.function' and type(pair[0]).__name__ == 'Function': lower_bound = pair[0] else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'Wrong type for the control constraints') if type(pair[1]) in [float, int]: upper_bound = fenics.Function(self.controls[idx].function_space()) upper_bound.vector()[:] = pair[1] elif pair[1].__module__ == 'dolfin.function.function' and type(pair[1]).__name__ == 'Function': upper_bound = pair[1] else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'Wrong type for the control constraints') self.control_constraints.append([lower_bound, upper_bound]) ### Check whether the control constraints are feasible, and whether they are actually present self.require_control_constraints = [False for i in range(self.control_dim)] for idx, pair in enumerate(self.control_constraints): if not np.alltrue(pair[0].vector()[:] < pair[1].vector()[:]): raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'The lower bound must always be smaller than the upper bound for the control_constraints.') if np.max(pair[0].vector()[:]) == float('-inf') and np.min(pair[1].vector()[:]) == float('inf'): # no control constraint for this component pass else: self.require_control_constraints[idx] = True control_element = self.controls[idx].ufl_element() if control_element.family() == 'Mixed': for j in range(control_element.value_size()): sub_elem = control_element.extract_component(j)[1] if sub_elem.family() == 'Real' or (sub_elem.family() == 'Lagrange' and sub_elem.degree() == 1) \ or (sub_elem.family() == 'Discontinuous Lagrange' and sub_elem.degree() == 0): pass else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'controls', 'Control constraints are only implemented for linear Lagrange, constant Discontinuous Lagrange, and Real elements.') else: if control_element.family() == 'Real' or (control_element.family() == 'Lagrange' and control_element.degree() == 1) \ or (control_element.family() == 'Discontinuous Lagrange' and control_element.degree() == 0): pass else: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'controls', 'Control constraints are only implemented for linear Lagrange, constant Discontinuous Lagrange, and Real elements.') if not len(self.riesz_scalar_products) == self.control_dim: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'riesz_scalar_products', 'Length of controls does not match') if not len(self.control_constraints) == self.control_dim: raise InputError('cashocs._optimal_control.optimal_control_problem.OptimalControlProblem', 'control_constraints', 'Length of controls does not match') ### end overloading self.form_handler = ControlFormHandler(self.lagrangian, self.bcs_list, self.states, self.controls, self.adjoints, self.config, self.riesz_scalar_products, self.control_constraints, self.ksp_options, self.adjoint_ksp_options, self.require_control_constraints) self.state_spaces = self.form_handler.state_spaces self.control_spaces = self.form_handler.control_spaces self.adjoint_spaces = self.form_handler.adjoint_spaces self.projected_difference = [fenics.Function(V) for V in self.control_spaces] self.state_problem = StateProblem(self.form_handler, self.initial_guess) self.adjoint_problem = AdjointProblem(self.form_handler, self.state_problem) self.gradient_problem = GradientProblem(self.form_handler, self.state_problem, self.adjoint_problem) self.algorithm = _optimization_algorithm_configuration(self.config) self.reduced_cost_functional = ReducedCostFunctional(self.form_handler, self.state_problem) self.gradients = self.gradient_problem.gradients self.objective_value = 1.0
def __compute_shape_gradient_forms(self): """Calculates the necessary left-hand-sides for the shape gradient problem. Returns ------- None """ self.shape_bdry_def = json.loads( self.config.get('ShapeGradient', 'shape_bdry_def', fallback='[]')) if not type(self.shape_bdry_def) == list: raise ConfigError('ShapeGradient', 'shape_bdry_def', 'The input has to be a list.') # if not len(self.shape_bdry_def) > 0: # raise ConfigError('ShapeGradient', 'shape_bdry_def','The input must not be empty.') self.shape_bdry_fix = json.loads( self.config.get('ShapeGradient', 'shape_bdry_fix', fallback='[]')) if not type(self.shape_bdry_def) == list: raise ConfigError('ShapeGradient', 'shape_bdry_fix', 'The input has to be a list.') self.shape_bdry_fix_x = json.loads( self.config.get('ShapeGradient', 'shape_bdry_fix_x', fallback='[]')) if not type(self.shape_bdry_fix_x) == list: raise ConfigError('ShapeGradient', 'shape_bdry_fix_x', 'The input has to be a list.') self.shape_bdry_fix_y = json.loads( self.config.get('ShapeGradient', 'shape_bdry_fix_y', fallback='[]')) if not type(self.shape_bdry_fix_y) == list: raise ConfigError('ShapeGradient', 'shape_bdry_fix_y', 'The input has to be a list.') self.shape_bdry_fix_z = json.loads( self.config.get('ShapeGradient', 'shape_bdry_fix_z', fallback='[]')) if not type(self.shape_bdry_fix_z) == list: raise ConfigError('ShapeGradient', 'shape_bdry_fix_z', 'The input has to be a list.') self.bcs_shape = create_bcs_list( self.deformation_space, fenics.Constant([0] * self.deformation_space.ufl_element().value_size()), self.boundaries, self.shape_bdry_fix) self.bcs_shape += create_bcs_list(self.deformation_space.sub(0), fenics.Constant(0.0), self.boundaries, self.shape_bdry_fix_x) self.bcs_shape += create_bcs_list(self.deformation_space.sub(1), fenics.Constant(0.0), self.boundaries, self.shape_bdry_fix_y) if self.deformation_space.num_sub_spaces() == 3: self.bcs_shape += create_bcs_list(self.deformation_space.sub(2), fenics.Constant(0.0), self.boundaries, self.shape_bdry_fix_z) self.CG1 = fenics.FunctionSpace(self.mesh, 'CG', 1) self.DG0 = fenics.FunctionSpace(self.mesh, 'DG', 0) if self.shape_scalar_product is None: # Use the default linear elasticity approach self.mu_lame = fenics.Function(self.CG1) self.lambda_lame = self.config.getfloat('ShapeGradient', 'lambda_lame', fallback=0.0) self.damping_factor = self.config.getfloat('ShapeGradient', 'damping_factor', fallback=0.0) if self.config.getboolean('ShapeGradient', 'inhomogeneous', fallback=False): self.volumes = fenics.project(fenics.CellVolume(self.mesh), self.DG0) vol_max = np.max(np.abs(self.volumes.vector()[:])) self.volumes.vector()[:] /= vol_max else: self.volumes = fenics.Constant(1.0) def eps(u): return fenics.Constant(0.5) * (fenics.grad(u) + fenics.grad(u).T) trial = fenics.TrialFunction(self.deformation_space) test = fenics.TestFunction(self.deformation_space) self.riesz_scalar_product = fenics.Constant(2)*self.mu_lame/self.volumes*fenics.inner(eps(trial), eps(test))*self.dx \ + fenics.Constant(self.lambda_lame)/self.volumes*fenics.div(trial)*fenics.div(test)*self.dx \ + fenics.Constant(self.damping_factor)/self.volumes*fenics.inner(trial, test)*self.dx else: # Use the scalar product supplied by the user self.riesz_scalar_product = self.shape_scalar_product
def __init__(self, optimization_problem): """Parent class for the optimization methods implemented in cashocs.optimization.methods Parameters ---------- optimization_problem : cashocs.ShapeOptimizationProblem the optimization problem """ self.line_search_broken = False self.has_curvature_info = False self.optimization_problem = optimization_problem self.form_handler = self.optimization_problem.form_handler self.state_problem = self.optimization_problem.state_problem self.config = self.state_problem.config self.adjoint_problem = self.optimization_problem.adjoint_problem self.shape_gradient_problem = self.optimization_problem.shape_gradient_problem self.gradient = self.shape_gradient_problem.gradient self.cost_functional = self.optimization_problem.reduced_cost_functional self.search_direction = fenics.Function( self.form_handler.deformation_space) if self.config.getboolean('Mesh', 'remesh', fallback=False): self.iteration = self.optimization_problem.temp_dict[ 'OptimizationRoutine'].get('iteration_counter', 0) else: self.iteration = 0 self.objective_value = 1.0 self.gradient_norm_initial = 1.0 self.relative_norm = 1.0 self.stepsize = 1.0 self.converged = False self.converged_reason = 0 self.output_dict = dict() try: self.output_dict[ 'cost_function_value'] = self.optimization_problem.temp_dict[ 'output_dict']['cost_function_value'] self.output_dict[ 'gradient_norm'] = self.optimization_problem.temp_dict[ 'output_dict']['gradient_norm'] self.output_dict['stepsize'] = self.optimization_problem.temp_dict[ 'output_dict']['stepsize'] self.output_dict[ 'MeshQuality'] = self.optimization_problem.temp_dict[ 'output_dict']['MeshQuality'] except (TypeError, KeyError): self.output_dict['cost_function_value'] = [] self.output_dict['gradient_norm'] = [] self.output_dict['stepsize'] = [] self.output_dict['MeshQuality'] = [] self.verbose = self.config.getboolean('Output', 'verbose', fallback=True) self.save_results = self.config.getboolean('Output', 'save_results', fallback=True) self.rtol = self.config.getfloat('OptimizationRoutine', 'rtol', fallback=1e-3) self.atol = self.config.getfloat('OptimizationRoutine', 'atol', fallback=0.0) self.maximum_iterations = self.config.getint('OptimizationRoutine', 'maximum_iterations', fallback=100) self.soft_exit = self.config.getboolean('OptimizationRoutine', 'soft_exit', fallback=False) self.save_pvd = self.config.getboolean('Output', 'save_pvd', fallback=False) self.result_dir = self.config.get('Output', 'result_dir', fallback='./') if self.save_pvd: self.state_pvd_list = [] for i in range(self.form_handler.state_dim): if self.form_handler.state_spaces[i].num_sub_spaces() > 0: self.state_pvd_list.append([]) for j in range(self.form_handler.state_spaces[i]. num_sub_spaces()): if self.optimization_problem.mesh_handler.do_remesh: self.state_pvd_list[i].append( fenics. File(self.result_dir + '/pvd/remesh_' + format( self.optimization_problem.temp_dict.get( 'remesh_counter', 0), 'd') + '_state_' + str(i) + '_' + str(j) + '.pvd')) else: self.state_pvd_list[i].append( fenics.File(self.result_dir + '/pvd/state_' + str(i) + '_' + str(j) + '.pvd')) else: if self.optimization_problem.mesh_handler.do_remesh: self.state_pvd_list.append( fenics.File(self.result_dir + '/pvd/remesh_' + format( self.optimization_problem.temp_dict .get('remesh_counter', 0), 'd') + '_state_' + str(i) + '.pvd')) else: self.state_pvd_list.append( fenics.File(self.result_dir + '/pvd/state_' + str(i) + '.pvd'))
mu = 1 # kinematic viscosity rho = 1 # density # Create mesh and define function spaces SEPARATELY for pressure and velocity spaces. mesh = fs.UnitSquareMesh(16, 16) V = fs.VectorFunctionSpace(mesh, 'P', 2) # velocity space, a vector space Q = fs.FunctionSpace(mesh, 'P', 1) # pressure space, a scalar space # Define trial and test functions u = fs.TrialFunction(V) # in velocity space v = fs.TestFunction(V) p = fs.TrialFunction(Q) # in pressure space q = fs.TestFunction(Q) # Define functions for solutions at previous and current time steps u_n = fs.Function(V) # u^(n) u_ = fs.Function(V) # u^(n+1) p_n = fs.Function(Q) # p^(n) p_ = fs.Function(Q) # p^(n+1) # Define boundaries inflow = 'near(x[0], 0)' outflow = 'near(x[0], 1)' walls = 'near(x[1], 0) || near (x[1], 1)' # Define boundary bonditions bcu_noslip = fs.DirichletBC(V, fs.Constant((0,0)), walls) bcp_inflow = fs.DirichletBC(Q, fs.Constant(8), inflow) bcp_outflow = fs.DirichletBC(Q, fs.Constant(0), outflow) bcu = [bcu_noslip] bcp = [bcp_inflow, bcp_outflow]
def demo16(self, permeability, obs_case=1): """This demo program solves the mixed formulation of Poisson's equation: sigma + grad(u) = 0 in Omega div(sigma) = f in Omega du/dn = g on Gamma_N u = u_D on Gamma_D The corresponding weak (variational problem) <sigma, tau> + <grad(u), tau> = 0 for all tau - <sigma, grad(v)> = <f, v> + <g, v> for all v is solved using DRT (Discontinuous Raviart-Thomas) elements of degree k for (sigma, tau) and CG (Lagrange) elements of degree k + 1 for (u, v) for k >= 1. """ mesh = UnitSquareMesh(15, 15) ak_values = permeability flux_order = 3 s = scenarios.darcy_problem_1() DRT = fenics.FiniteElement("DRT", mesh.ufl_cell(), flux_order) # Lagrange CG = fenics.FiniteElement("CG", mesh.ufl_cell(), flux_order + 1) if s.integral_constraint: # From https://fenicsproject.org/qa/14184/how-to-solve-linear-system-with-constaint R = fenics.FiniteElement("R", mesh.ufl_cell(), 0) W = fenics.FunctionSpace(mesh, fenics.MixedElement([DRT, CG, R])) # Define trial and test functions (sigma, u, r) = fenics.TrialFunctions(W) (tau, v, r_) = fenics.TestFunctions(W) else: W = fenics.FunctionSpace(mesh, DRT * CG) # Define trial and test functions (sigma, u) = fenics.TrialFunctions(W) (tau, v) = fenics.TestFunctions(W) f = s.source_function g = s.g # Define property field function W_CG = fenics.FunctionSpace(mesh, "Lagrange", 1) if s.ak is None: ak = property_field.get_conductivity(W_CG, ak_values) else: ak = s.ak # Define variational form a = (fenics.dot(sigma, tau) + fenics.dot(ak * fenics.grad(u), tau) + fenics.dot(sigma, fenics.grad(v))) * fenics.dx L = -f * v * fenics.dx + g * v * fenics.ds # L = 0 if s.integral_constraint: # Lagrange multiplier? See above link. a += r_ * u * fenics.dx + v * r * fenics.dx # Define Dirichlet BC bc = fenics.DirichletBC(W.sub(1), s.dirichlet_bc, s.gamma_dirichlet) # Compute solution w = fenics.Function(W) fenics.solve(a == L, w, bc) # fenics.solve(a == L, w) if s.integral_constraint: (sigma, u, r) = w.split() else: (sigma, u) = w.split() x = u.compute_vertex_values(mesh) x2 = sigma.compute_vertex_values(mesh) p = x pre = p.reshape((16, 16)) vx = x2[:256].reshape((16, 16)) vy = x2[256:].reshape((16, 16)) if obs_case == 1: dd = np.zeros([8, 8]) pos = np.full((8 * 8, 2), 0) col = [1, 3, 5, 7, 9, 11, 13, 15] position = [1, 3, 5, 7, 9, 11, 13, 15] for i in range(8): for j in range(8): row = position pos[8 * i + j, :] = [col[i], row[j]] dd[i, j] = pre[col[i], row[j]] like = dd.reshape(8 * 8, ) return like, pre, vx, vy, ak_values, pos
def solve_cell_problems(self, method='regularized', plot=False): """ Solve the cell problems for the given PDE by changing the geometry to exclude the zone in the middle :return: """ class PeriodicBoundary(fe.SubDomain): # Left boundary is "target domain" G def inside(self, x, on_boundary): par = MembraneSimulator.w / MembraneSimulator.length tol = 1E-4 return on_boundary and x[1] >= -tol and x[1] <= tol # Map right boundary (H) to left boundary (G) def map(self, x, y): y[1] = x[1] + 2 * self.eta / MembraneSimulator.length y[0] = x[0] mesh_size = 50 # Domain if method == 'circle': self.obstacle_radius = self.eta / MembraneSimulator.length / 2 box_begin_point = fe.Point(-self.w / MembraneSimulator.length, 0) box_end_point = fe.Point(self.w / MembraneSimulator.length, 2 * self.eta / MembraneSimulator.length) box = mshr.Rectangle(box_begin_point, box_end_point) cell = box - mshr.Circle( fe.Point(0, self.eta / MembraneSimulator.length), self.obstacle_radius, mesh_size) self.cell_mesh = mshr.generate_mesh(cell, mesh_size) diff_coef = fe.Constant( ((0, 0), (0, self.D[1, 1]))) # limit for regularisation below. # elif method == 'diff_coef': # print("Haha this is going to crash. Also it is horrible in accuracy") # self.cell_mesh = fe.RectangleMesh(fe.Point(-self.w / MembraneSimulator.length, 0), # fe.Point(self.w / MembraneSimulator.length, # 2 * self.eta / MembraneSimulator.length), mesh_size, mesh_size) # diff_coef = fe.Expression( # (('0', '0'), ('0', 'val * ((x[0] - c_x)*(x[0] - c_x) + (x[1] - c_y)*(x[1] - c_y) > r*r)')), # val=(4 * self.ref_T * MembraneSimulator.d2 / MembraneSimulator.length ** 2), c_x=0, # c_y=(self.eta / MembraneSimulator.length), # r=self.obstacle_radius, degree=2, domain=self.cell_mesh) elif method == 'regularized': box_begin_point = fe.Point(-self.w / MembraneSimulator.length, 0) box_end_point = fe.Point(self.w / MembraneSimulator.length, 2 * self.eta / MembraneSimulator.length) box = mshr.Rectangle(box_begin_point, box_end_point) obstacle_begin_point = fe.Point( -self.w / MembraneSimulator.length * self.obs_length, self.eta / MembraneSimulator.length * (1 - self.obs_height)) obstacle_end_point = fe.Point( self.w / MembraneSimulator.length * self.obs_length, self.eta / MembraneSimulator.length * (1 + self.obs_height)) obstacle = mshr.Rectangle(obstacle_begin_point, obstacle_end_point) cell = box - obstacle self.cell_mesh = mshr.generate_mesh(cell, mesh_size) diff_coef = fe.Constant(((self.obs_ratio * self.D[0, 0], 0), (0, self.D[1, 1]))) # defect matrix. else: raise ValueError("%s not a valid method to solve cell problem" % method) self.cell_fs = fe.FunctionSpace(self.cell_mesh, 'P', 2) self.cell_solutions = [ fe.Function(self.cell_fs), fe.Function(self.cell_fs) ] w = fe.TrialFunction(self.cell_fs) phi = fe.TestFunction(self.cell_fs) scaled_unit_vectors = [ fe.Constant((1. / np.sqrt(self.obs_ratio), 0.)), fe.Constant((0., 1.)) ] for i in range(2): weak_form = fe.dot( diff_coef * (fe.grad(w) + scaled_unit_vectors[i]), fe.grad(phi)) * fe.dx print("Solving cell problem") bc = fe.DirichletBC(self.cell_fs, fe.Constant(0), MembraneSimulator.cell_boundary) if i == 0: # Periodicity is applied automatically bc = None fe.solve( fe.lhs(weak_form) == fe.rhs(weak_form), self.cell_solutions[i], bc) if plot: plt.rc('text', usetex=True) f = fe.plot(self.cell_solutions[i]) plt.colorbar(f) plt.title(r'Solution to cell problem $w_%d$' % (i + 1)) plt.xlabel(r'$Y_1$') plt.ylabel(r'$Y_2$') print("Cell solution") print(np.min(self.cell_solutions[i].vector().get_local()), np.max(self.cell_solutions[i].vector().get_local())) plt.show()
def _load_fenics_function(path): V = fn.FunctionSpace(mesh, element_type, element_degree) return fn.Function(V, path)
MODEL = False # flag to use SA model b = fe.Expression(('0', '0'), degree=DEG) # forcing nu = fe.Constant(1e-2) rho = fe.Constant(1) RE = 50 lmx = 1 # mixing length :) # Re = 10 / 1e-4 = 1e5 V = fe.VectorElement("Lagrange", mesh.ufl_cell(), 2) P = fe.FiniteElement("Lagrange", mesh.ufl_cell(), 1) NU = fe.FiniteElement("Lagrange", mesh.ufl_cell(), 1) if MODEL: M = fe.MixedElement([V, P, NU]) else: M = fe.MixedElement([V, P]) W = fe.FunctionSpace(mesh, M) W0 = fe.Function(W) if MODEL: (v, q, nu_test) = fe.TestFunctions(W) (u, p, nu_trial) = fe.split(W0) else: ( v, q, ) = fe.TestFunctions(W) ( u, p, ) = fe.split(W0) nu_trial = fe.Constant(5) # artificial viscosity!!! fv1 = fe.Constant(1)
Mixed = fn.MixedElement(Elem) V = fn.FunctionSpace(mesh, Mixed) # %% # define potentials and concentrations u_GND = fn.Expression('0', degree=2) #Ground u_DD = fn.Expression('0.5', degree=2) #pontential c_avg = fn.Expression('0.0001', degree=2) #average concentration # set boundary conditions bcs = [] bcs += [fn.DirichletBC(V.sub(0), u_DD, mf, 3)] bcs += [fn.DirichletBC(V.sub(0), u_GND, mf, 1)] # define problem UC = fn.Function(V) uc = fn.split(UC) # trial function potential concentration lagrange multi u, c, lam = uc[0], uc[1:M + 1], uc[M + 1:] VW = fn.TestFunctions( V) # test function potential concentration lagrange multi v, w, mu = VW[0], VW[1:M + 1], VW[M + 1:] #lets try rot r = fn.Expression('x[0]', degree=0) # changing concentrations charges Rho = 0 for i in range(M): if i % 2: Rho += -c[i]
# Volumetric Load q = -10.0 / t b = fn.Constant((0.0, q)) def Left_boundary(x, on_boundary): return on_boundary and abs(x[0]) < fn.DOLFIN_EPS u_L = fn.Constant((0.0, 0.0)) bcs = [fn.DirichletBC(V, u_L, Left_boundary)] # Forward problem solution @build_jax_solve_eval((fn.Function(C), )) def forward(x): u = fn.TrialFunction(V) w = fn.TestFunction(V) sigma = lmbda * tr(sym(grad(u))) * Identity(2) + 2 * G * sym( grad(u)) # Stress R = simp(x) * inner(sigma, grad(w)) * dx - dot(b, w) * dx a, L = ufl.lhs(R), ufl.rhs(R) u = fn.Function(V) F = L - ufl.action(a, u) fn.solve(a == L, u, bcs) return u, F, bcs @build_jax_assemble_eval((fn.Function(V), fn.Function(C))) def eval_cost(u, x):
boundaries = fe.MeshFunction("size_t", mesh, "mesh/beam_facet_region.xml") # Redefine the integration measures dxp = fe.Measure('dx', domain=mesh, subdomain_data=subdomains) dsp = fe.Measure('ds', domain=mesh, subdomain_data=boundaries) ##################### FINITE ELEMENT SPACES ################################## # Finite element spaces W = fe.FunctionSpace(mesh, 'P', 1) V = fe.VectorFunctionSpace(mesh, 'P', 1) Z = fe.TensorFunctionSpace(mesh, 'P', 1) # Finite element functions du = fe.TrialFunction(V) v = fe.TestFunction(V) u = fe.Function(V) ######################### PROBLEM PARAMS ###################################### # Material properties materials = { 1: [210e9, 0.33], } # Load multipliers p = 500000. q = p * 100. ######################## BOUNDARY CONDITIONS ################################# # Define the boundary conditions boundary_conditions = { 2: fe.Constant((0., 0., 0.)),
return on_boundary and fen.near(x[1], edge, tol) def boundary_B(x, on_boundary): return on_boundary and fen.near(x[1], -edge, tol) bc_L = fen.DirichletBC(V, phi_L, boundary_L) bc_R = fen.DirichletBC(V, phi_R, boundary_R) bc_H = fen.DirichletBC(V, phi_H, boundary_H) bc_B = fen.DirichletBC(V, phi_B, boundary_B) bc = [bc_L, bc_R, bc_H, bc_B] # -------------Define variational problem------------ phi = fen.Function(V) v = fen.TestFunction(V) pi = np.pi rho_sun = fen.Expression( 'pow(pow(x[0],2)+pow(x[1],2),0.5)<=rad_sun ? 3*m_sun/(4*pi*pow(rad_sun,3)): 0', degree=2, rad_sun=rad_sun, m_sun=m_sun, pi=pi) J = fen.Expression('pow(x[0]*x[0] + x[1]*x[1],0.5)', degree=2) Func = (-J * phi.dx(0) * v.dx(0) - J * phi.dx(1) * v.dx(1) - J * 4 * np.pi * rho_sun * v) * fen.dx
# Define Boundaries left = fe.CompiledSubDomain("near(x[0], side) && on_boundary", side=0.0) right = fe.CompiledSubDomain("near(x[0], side) && on_boundary", side=1.0) # Define Dirichlet boundary (x = 0 or x = 1) u_left = fe.Expression(("0.0", "0.0", "0.0"), element=element_3) u_right = fe.Expression(("0.0", "0.0", "0.0"), element=element_3) p_left = fe.Constant(0.) # Define acting force b = fe.Constant((0.0, 0.0, 0.0)) # Body force per unit volume t_bar = fe.Constant((0.0, 0.0, 0.0)) # Traction force on the boundary # Define test and trial functions w = fe.Function(V) # most recently computed solution (u, p) = fe.split(w) (v, q) = fe.TestFunctions(V) dw = fe.TrialFunction(V) # Kinematics d = u.geometric_dimension() I = fe.Identity(d) # Identity tensor F = fe.variable(I + grad(u)) # Deformation gradient C = fe.variable(F.T * F) # Right Cauchy-Green tensor J = fe.det(C) DE = lambda v: 0.5 * (F.T * grad(v) + grad(v).T * F) a_0 = fe.as_vector([[1.0], [0.], [0.]])
def __init__(self, form_handler, gradient_problem): """Initializes self. Parameters ---------- form_handler : cashocs._forms.ControlFormHandler The FormHandler object for the optimization problem. gradient_problem : cashocs._pde_problems.GradientProblem The GradientProblem object (this is needed for the computation of the Hessian). """ self.form_handler = form_handler self.gradient_problem = gradient_problem self.config = self.form_handler.config self.gradients = self.gradient_problem.gradients self.inner_newton = self.config.get('AlgoTNM', 'inner_newton', fallback='cr') self.max_it_inner_newton = self.config.getint('AlgoTNM', 'max_it_inner_newton', fallback=50) # TODO: Add absolute tolerance, too self.inner_newton_tolerance = self.config.getfloat( 'AlgoTNM', 'inner_newton_tolerance', fallback=1e-15) self.test_directions = self.form_handler.test_directions self.residual = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.delta_control = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.state_dim = self.form_handler.state_dim self.control_dim = self.form_handler.control_dim self.temp1 = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.temp2 = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.p = [fenics.Function(V) for V in self.form_handler.control_spaces] self.p_prev = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.p_pprev = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.s = [fenics.Function(V) for V in self.form_handler.control_spaces] self.s_prev = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.s_pprev = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.q = [fenics.Function(V) for V in self.form_handler.control_spaces] self.q_prev = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.hessian_actions = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.inactive_part = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.active_part = [ fenics.Function(V) for V in self.form_handler.control_spaces ] self.controls = self.form_handler.controls self.rtol = self.config.getfloat('StateSystem', 'picard_rtol', fallback=1e-10) self.atol = self.config.getfloat('StateSystem', 'picard_atol', fallback=1e-12) self.maxiter = self.config.getint('StateSystem', 'picard_iter', fallback=50) self.picard_verbose = self.config.getboolean('StateSystem', 'picard_verbose', fallback=False) self.no_sensitivity_solves = 0 self.state_ksps = [ PETSc.KSP().create() for i in range(self.form_handler.state_dim) ] _setup_petsc_options(self.state_ksps, self.form_handler.state_ksp_options) self.adjoint_ksps = [ PETSc.KSP().create() for i in range(self.form_handler.state_dim) ] _setup_petsc_options(self.adjoint_ksps, self.form_handler.adjoint_ksp_options) # Initialize the PETSc Krylov solver for the Riesz projection problems self.ksps = [PETSc.KSP().create() for i in range(self.control_dim)] option = [['ksp_type', 'cg'], ['pc_type', 'hypre'], ['pc_hypre_type', 'boomeramg'], ['pc_hypre_boomeramg_strong_threshold', 0.7], ['ksp_rtol', 1e-16], ['ksp_atol', 1e-50], ['ksp_max_it', 100]] self.riesz_ksp_options = [] for i in range(self.control_dim): self.riesz_ksp_options.append(option) _setup_petsc_options(self.ksps, self.riesz_ksp_options) for i, ksp in enumerate(self.ksps): ksp.setOperators(self.form_handler.riesz_projection_matrices[i])