def SetupUnitMeshHelper(mesh, V=None, Vc=None): if V is None: V = df.FunctionSpace(mesh, 'CG', 1) if Vc is None: Vc = df.FunctionSpace(mesh, 'DG', 0) boundaries = dict() boundaries['left'] = df.CompiledSubDomain("near(x[0], 0.0) && on_boundary") boundaries['bottom'] = df.CompiledSubDomain( "near(x[1], 0.0) && on_boundary") boundaries['top'] = df.CompiledSubDomain("near(x[1], 1.0) && on_boundary") boundaries['right'] = df.CompiledSubDomain( "near(x[0], 1.0) && on_boundary") boundarymarkers = df.MeshFunction('size_t', mesh, mesh.topology().dim() - 1, 0) boundarymarkers.set_all(0) domainmarkers = df.MeshFunction('size_t', mesh, mesh.topology().dim(), 0) boundaries['left'].mark(boundarymarkers, 1) boundaries['bottom'].mark(boundarymarkers, 2) boundaries['right'].mark(boundarymarkers, 3) boundaries['top'].mark(boundarymarkers, 4) ds = df.Measure('ds', domain=mesh, subdomain_data=boundarymarkers) dx = df.Measure('dx', domain=mesh, subdomain_data=domainmarkers) return boundaries, boundarymarkers, domainmarkers, dx, ds, V, Vc
def calTrueSol(para): nx, ny = para['mesh_N'][0], para['mesh_N'][1] mesh = fe.UnitSquareMesh(nx, ny) Vu = fe.FunctionSpace(mesh, 'P', para['P']) Vc = fe.FunctionSpace(mesh, 'P', para['P']) al = fe.Constant(para['alpha']) f = fe.Expression(para['f'], degree=5) q1 = fe.interpolate(fe.Expression(para['q1'], degree=5), Vc) q2 = fe.interpolate(fe.Expression(para['q2'], degree=5), Vc) q3 = fe.interpolate(fe.Expression(para['q3'], degree=5), Vc) theta = fe.interpolate(fe.Expression(para['q4'], degree=5), Vc) class BoundaryX0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 0.0) class BoundaryX1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 1.0) class BoundaryY0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 0.0) class BoundaryY1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 1.0) boundaries = fe.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) boundaries.set_all(0) bc0, bc1, bc2, bc3 = BoundaryX0(), BoundaryX1(), BoundaryY0(), BoundaryY1() bc0.mark(boundaries, 1) bc1.mark(boundaries, 2) bc2.mark(boundaries, 3) bc3.mark(boundaries, 4) domains = fe.MeshFunction("size_t", mesh, mesh.topology().dim()) domains.set_all(0) bcD = fe.DirichletBC(Vu, theta, boundaries, 4) dx = fe.Measure('dx', domain=mesh, subdomain_data=domains) ds = fe.Measure('ds', domain=mesh, subdomain_data=boundaries) u_trial, u_test = fe.TrialFunction(Vu), fe.TestFunction(Vu) u = fe.Function(Vu) left = fe.inner(al * fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * dx right = f * u_test * dx + (q1 * u_test * ds(1) + q2 * u_test * ds(2) + q3 * u_test * ds(3)) left_m, right_m = fe.assemble_system(left, right, bcD) fe.solve(left_m, u.vector(), right_m) return u
def get_measures(self): """ Create the measurements from the generated subdomains and boundaries objects. The defined measurements are: - dx: Area measure. - ds: External boundaries measure. - dS: Internal boundaries measure. Returns ------- None. """ self.dx = fn.Measure('dx')(subdomain_data=self.subdomains) self.ds = fn.Measure('ds')(subdomain_data=self.boundaries) self.dS = fn.Measure('dS')(subdomain_data=self.boundaries)
def set_boundaries(self): self.boundaries = fe.MeshFunction("size_t", self.mesh, self.mesh.topology().dim() - 1) self.boundaries.set_all(0) self.ds = fe.Measure("ds")(subdomain_data=self.boundaries) self.I = fe.Identity(self.mesh.topology().dim()) self.normal = fe.FacetNormal(self.mesh)
def readCellExpression(self, group_value_dict, value_type="scalar", overlap=lambda x: x[0], *args, **kwargs): """ Reads cell expression and returns it. """ value_type_dictionary = { "scalar": ScalarCellExpressionFromXDMF, "vector2d": Vector2DCellExpressionFromXDMF, "vector3d": Vector3DCellExpressionFromXDMF } self.readMesh() xdmffile = fenics.XDMFFile(self.xdmffilename) cf = value_type_dictionary[value_type.lower()](group_value_dict, overlap=overlap, *args, **kwargs) cf.init() for (key, value) in cf.group_value_dict.items(): cf.markers[key] = fenics.MeshFunction("size_t", self.mesh, self.mesh.topology().dim()) xdmffile.read(cf.markers[key], key) cf.dx[key] = fenics.Measure("dx", domain=self.mesh, subdomain_data=cf.markers[key]) xdmffile.close() return cf
def _make_variational_problem(V): """ Formulate the variational problem a(u, v) = L(v). Parameters ---------- V: FEniCS.FunctionSpace Returns ------- a, L: FEniCS.Expression Variational forms. """ # Define trial and test functions u = F.TrialFunction(V) v = F.TestFunction(V) # Collect Neumann conditions ds = F.Measure("ds", domain=mesh, subdomain_data=boundary_markers) integrals_N = [] for i in boundary_conditions: if isinstance(boundary_conditions[i], dict): if "Neumann" in boundary_conditions[i]: if boundary_conditions[i]["Neumann"] != 0: g = boundary_conditions[i]["Neumann"] integrals_N.append(g[0] * v * ds(i)) # Define variational problem a = F.inner(u, v) * F.dx + (DT**2) * (C**2) * F.inner( F.grad(u), F.grad(v)) * F.dx L = ((DT**2) * f[0] + 2 * u_nm1 - u_nm2) * v * F.dx + (DT**2) * (C**2) * sum(integrals_N) return a, L
def get_measures(self): """ Get measures of the domain given the required data. The defined measurements are: - dx: Area measure. - ds: External boundaries measure. - dS: Internal boundaries measure. Returns: """ self.dx = fn.Measure('dx')( subdomain_data=self.subdomains) # Area measure. self.ds = fn.Measure('ds')( subdomain_data=self.boundaries) # External boundaries measures. self.dS = fn.Measure('dS')( subdomain_data=self.boundaries ) # Internal boundaries measures (interface boundary).
def useSternLayerCellBC(self): """ Interfaces at left hand side and right hand side, species-wise number conservation within interval.""" self.boundary_conditions = [] # Introduce a Lagrange multiplier per species anderson # rebuild discretization scheme (function spaces) self.constraints = 0 self.K = self.M self.discretize() # Potential Dirichlet BC self.u0 = self.delta_u_scaled / 2. self.u1 = -self.delta_u_scaled / 2. boundary_markers = fn.MeshFunction('size_t', self.mesh, self.mesh.topology().dim() - 1) bx = [ Boundary(x0=self.x0_scaled, tol=self.bctol), Boundary(x0=self.x1_scaled, tol=self.bctol) ] # Boundary.mark crashes the kernel if Boundary is internal class for i, b in enumerate(bx): b.mark(boundary_markers, i) boundary_conditions = { 0: { 'Robin': (1. / self.lambda_S_scaled, self.u0) }, 1: { 'Robin': (1. / self.lambda_S_scaled, self.u1) }, } ds = fn.Measure('ds', domain=self.mesh, subdomain_data=boundary_markers) integrals_R = [] for i in boundary_conditions: if 'Robin' in boundary_conditions[i]: r, s = boundary_conditions[i]['Robin'] integrals_R.append(r * (self.u - s) * self.v * ds(i)) self.constraints += sum(integrals_R) # Number conservation constraints N0 = self.L_scaled * self.c_scaled # total amount of species in cell for k in range(self.M): self.logger.info('{:>{lwidth}s} N0 = {:<8.4g}'.format( 'Ion species {:02d} number conservation constraint'.format(k), N0[k], lwidth=self.label_width)) self.applyNumberConservationConstraint(k, self.c_scaled[k])
def eva(self): # construct solutions corresponding to the basis functions class BoundaryX0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 0.0) class BoundaryX1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 1.0) class BoundaryY0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 0.0) class BoundaryY1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 1.0) boundaries = fe.MeshFunction('size_t', self.mesh, self.mesh.topology().dim() - 1) boundaries.set_all(0) bc0, bc1, bc2, bc3 = BoundaryX0(), BoundaryX1(), BoundaryY0( ), BoundaryY1() bc0.mark(boundaries, 1) bc1.mark(boundaries, 2) bc2.mark(boundaries, 3) bc3.mark(boundaries, 4) domains = fe.MeshFunction("size_t", self.mesh, self.mesh.topology().dim()) domains.set_all(0) dx = fe.Measure('dx', domain=self.mesh, subdomain_data=domains) ds = fe.Measure('ds', domain=self.mesh, subdomain_data=boundaries) u_trial, u_test = fe.TrialFunction(self.Vu), fe.TestFunction(self.Vu) left = fe.inner(fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * dx right = self.f * u_test * dx + (self.q1 * u_test * ds(1) + self.q2 * u_test * ds(2) + self.q3 * u_test * ds(3)) bcD = fe.DirichletBC(self.Vu, self.theta, boundaries, 4) left_m, right_m = fe.assemble_system(left, right, bcD) fe.solve(left_m, self.u.vector(), right_m)
def BCsDefinition(Dimensions, Mesh, V, u_0, u_1, LoadCase, BCsType=False): # Define geometric spaces class LowerSide(fe.SubDomain): def inside(self, x, on_boundary): tol = 1E-14 return on_boundary and fe.near(x[2], -Dimensions[2] / 2, tol) class UpperSide(fe.SubDomain): def inside(self, x, on_boundary): tol = 1E-14 return on_boundary and fe.near(x[2], Dimensions[2] / 2, tol) # Define integration over subdpmains Domains_Facets = fe.MeshFunction('size_t', Mesh, Mesh.geometric_dimension() - 1) ds = fe.Measure('ds', domain=Mesh, subdomain_data=Domains_Facets) # Mark all domain facets with 0 Domains_Facets.set_all(0) # Mark bottom facets with 1 bottom = LowerSide() bottom.mark(Domains_Facets, 1) # Mark upper facets with 2 upper = UpperSide() upper.mark(Domains_Facets, 2) # Apply boundary conditions if BCsType == 'Ideal': if LoadCase == 'SimpleShear': bcl = fe.DirichletBC(V, u_0, Domains_Facets, 1) bcu = fe.DirichletBC(V, u_1, Domains_Facets, 2) else: bcl = fe.DirichletBC(V.sub(2), u_0, Domains_Facets, 1) bcu = fe.DirichletBC(V.sub(2), u_1, Domains_Facets, 2) else: bcl = fe.DirichletBC(V, u_0, Domains_Facets, 1) bcu = fe.DirichletBC(V, u_1, Domains_Facets, 2) # Set of boundary conditions BoundaryConditions = [bcl, bcu] return [BoundaryConditions, ds]
def load_2d_muscle_geo(filename='../geo/muscle_2d.xml', L0=1e-2): mesh = fe.Mesh(filename) coords = mesh.coordinates() coords *= L0 mesh.bounding_box_tree().build(mesh) # Define Boundaries bottom = fe.CompiledSubDomain("near(x[1], side, 0.01) && on_boundary", side=-20.0 * L0) top = fe.CompiledSubDomain("near(x[1], side, 0.01) && on_boundary", side=20.0 * L0) # Initialize mesh function for boundary domains boundaries = fe.MeshFunction('size_t', mesh, 2) boundaries.set_all(0) bottom.mark(boundaries, 1) top.mark(boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries dx = fe.Measure('dx', domain=mesh) ds = fe.Measure('ds', domain=mesh, subdomain_data=boundaries) return mesh, dx, ds, {"top": top, "bottom": bottom}
def readFacetFunction(self, group_value_dict, *args, **kwargs): """ Reads facet function and returns it. """ self.readMesh() xdmffile = fenics.XDMFFile(self.xdmffilename) ff = FacetFunctionFromXDMF(group_value_dict, *args, **kwargs) ff.init() for (key, value) in ff.group_value_dict.items(): ff.markers[key] = fenics.MeshFunction("size_t", self.mesh, self.mesh.topology().dim() - 1) xdmffile.read(ff.markers[key], key) ff.marked[key] = value.get("marked", 1) ff.ds[key] = fenics.Measure("ds", domain=self.mesh, subdomain_data=ff.markers[key]) ff.bcs[key] = value xdmffile.close() return ff
def run(self) -> None: mesh = self.mesh_creator.get_mesh() self.spaces.initialize(mesh=mesh) self.boundary_markers.mark_boundaries(mesh=mesh) bc = self.bc_creator.apply( vector_space=self.spaces.vector_space, boundary_markers=self.boundary_markers.value) ds = fenics.Measure('ds', domain=mesh, subdomain_data=self.boundary_markers.value) self.boundary_excitation.set_ds(ds=ds) self.fields.initialize(spaces=self.spaces) fem_solver = get_fem_solver(fem_solver=self.fem_solver_type, problem=self.problem, fields=self.fields, boundary_conditions=bc) self.time_step_builder.set( alpha_params=self.alpha_params, time_params=self.time_params, fem_solver=fem_solver, boundary_excitation=self.boundary_excitation, field_updates=self.field_updates, fields=self.fields, mesh=mesh, spaces=self.spaces) time_step = self.time_step_builder.build() mins = [] maxs = [] for (i, t) in enumerate(self.time_params.linear_time_space[1:]): # for i in range(3): print("Time: ", t) time_step.run(i) # v = fenics.elem_div(self.problem.constitutive_relation.get_new_value(self.fields.u_new), fenics.sym(fenics.grad(self.fields.u_new))) # x = fenics.project(v, self.spaces.tensor_space).vector()[:] # mins.append(min(x)) # maxs.append(max(x)) # # print('min: {}, max: {}, median, {}'.format(min(x), max(x), np.nanmedian(np.asarray(x)))) # print(x) # print() # print(fenics.project(self.problem.constitutive_relation.get_new_value(self.fields.u_new), self.spaces.tensor_space).vector()[:]) # print(fenics.project(fenics.sym(fenics.grad(self.fields.u_new)), self.spaces.tensor_space).vector()[:]) if time_step.halt: break time_step.close() print('total: min: {}, max: {}'.format(min(mins), max(maxs)))
def wrapper2D(par, meshName, N_PN, boundaryFilePrefix, solutionFolder): #-------- load mesh -------- mesh = fe.Mesh(meshName + '.xml') boundaryMarkers = fe.MeshFunction('size_t', mesh, meshName + '_facet_region.xml') ds = fe.Measure('ds', domain=mesh, subdomain_data=boundaryMarkers) u = solvePN2nd(par, N_PN, mesh, boundaryFilePrefix, ds) #fe.plot(u[0]) # first moment: u0 = int_{4pi} I * b0 dOmega, b0 = sqrt(1 / 4 / pi) # radiative energy: phi = int_{4pi} I dOmega radiativeEnergy = np.sqrt(4 * np.pi) * u[0].compute_vertex_values() createFolder(solutionFolder) sio.savemat('%sradiativeEnergy_P%d2nd_%s.mat'%(solutionFolder, N_PN, meshName.split('/')[-1]), {'radiativeEnergy': radiativeEnergy, 'points': mesh.coordinates(), 'connectivityList': mesh.cells()}) return u
def readXDMFFile(self, xdmffilename, group_value_dict): xdmffile = fenics.XDMFFile(xdmffilename) self.group_value_dict = group_value_dict self.mesh = fenics.Mesh() xdmffile.read(self.mesh) self.markers = {} self.marked = {} self.ds = {} self.bcs = {} for (key, value) in self.group_value_dict.iteritems(): # Fenics interface here: create facet function of type size_t (positive int) for every group # TODO: examine whether size_t is appropriate or this class could be generalized self.markers[key] = fenics.FacetFunction("size_t", self.mesh) xdmffile.read(self.markers[key], key) self.marked[key] = value.get("marked", 1) self.ds[key] = fenics.Measure("ds", domain=self.mesh, subdomain_data=self.markers[key]) self.bcs[key] = value xdmffile.close()
def avg_condition_number(mesh): """Computes average mesh quality based on the condition number of the reference mapping. This quality criterion uses the condition number (in the Frobenius norm) of the (linear) mapping from the elements of the mesh to the reference element. Computes the average of the condition number over all elements. Parameters ---------- mesh : dolfin.cpp.mesh.Mesh The mesh, whose quality shall be computed. Returns ------- float The average mesh quality based on the condition number. """ DG0 = fenics.FunctionSpace(mesh, 'DG', 0) jac = Jacobian(mesh) inv = JacobianInverse(mesh) options = [ ['ksp_type', 'preonly'], ['pc_type', 'jacobi'], ['pc_jacobi_type', 'diagonal'], ['ksp_rtol', 1e-16], ['ksp_atol', 1e-20], ['ksp_max_it', 1000] ] ksp = PETSc.KSP().create() _setup_petsc_options([ksp], [options]) dx = fenics.Measure('dx', mesh) a = fenics.TrialFunction(DG0)*fenics.TestFunction(DG0)*dx L = fenics.sqrt(fenics.inner(jac, jac))*fenics.sqrt(fenics.inner(inv, inv))*fenics.TestFunction(DG0)*dx cond = fenics.Function(DG0) A, b = _assemble_petsc_system(a, L) _solve_linear_problem(ksp, A, b, cond.vector().vec(), options) cond.vector().apply('') return np.average(np.sqrt(mesh.geometric_dimension()) / cond.vector()[:])
def defineBoundaryMarkers1D(mesh, zMin, zMax): """For implementation details, see https://fenicsproject.org/olddocs/dolfin/1.3.0/python/demo/documented/subdomains-poisson/python/documentation.html https://fenicsproject.discourse.group/t/natural-boundary-conditions-without-facetfunction/228/3 """ boundaries = fe.MeshFunction("size_t", mesh, mesh.topology().dim() - 1) class Left(fe.SubDomain): def inside(self, x, on_boundary): return fe.near(x[0], zMin) class Right(fe.SubDomain): def inside(self, x, on_boundary): return fe.near(x[0], zMax) left = Left() right = Right() left.mark(boundaries, 1) right.mark(boundaries, 2) ds = fe.Measure("ds", domain=mesh, subdomain_data=boundaries) return ds
def readXDMFfile(self, xdmffilename, group_value_dict): """ Initialization of CellExpressionXDMF by reading an XDMF file. @param: xdmffilename: path to xdmf file @param: group_value_dict: {"groupname":function(x)} function(x) is a function which is evaluated at the marked positions of the cells """ xdmffile = fenics.XDMFFile(xdmffilename) self.group_value_dict = group_value_dict self.mesh = fenics.Mesh() xdmffile.read(self.mesh) self.markers = {} self.dx = {} for (key, value) in self.group_value_dict.iteritems(): # Fenics interface here: create cell function of type int for every group # TODO: examine whether int is appropriate or this class could be generalized self.markers[key] = fenics.CellFunction("size_t", self.mesh) xdmffile.read(self.markers[key], key) self.dx[key] = fenics.Measure("dx", domain=self.mesh, subdomain_data=self.markers[key]) xdmffile.close()
def _build_function_space(self): class Exterior(fa.SubDomain): def inside(self, x, on_boundary): return on_boundary self.exterior = Exterior() self.V = fa.FunctionSpace(self.mesh, 'P', 1) self.sub_domains = fa.MeshFunction("size_t", self.mesh, self.mesh.topology().dim() - 1) self.sub_domains.set_all(0) self.normal = fa.FacetNormal(self.mesh) self.ds = fa.Measure("ds")(subdomain_data=self.sub_domains) # self.source = fa.Expression(("cos(pi*x[0])*cos(pi*x[1])"), degree=3) self.source = fa.Expression(("x[0]*x[0] + x[1]*x[1]"), degree=3) self.source = fa.interpolate(self.source, self.V) # self.source = fa.Constant(1.) self.bcs = [] boundary_fn = fa.Constant(0.) boundary_bc = fa.DirichletBC(self.V, boundary_fn, self.exterior) self.bcs = self.bcs + [boundary_bc]
def _assembly(V): """ Assemble the matrices used in the linear system Au = b. Alternative representation of the variational form. Pre-calculate to speed up. """ # Define trial and test functions u = F.TrialFunction(V) v = F.TestFunction(V) # Assemble a_M = F.inner(u, v) * F.dx a_K = F.inner(F.grad(u), F.grad(v)) * F.dx M = F.assemble(a_M) K = F.assemble(a_K) A = M + (dt**2) * (c**2) * K ds = F.Measure("ds", domain=mesh, subdomain_data=boundary_markers) M_ = F.assemble(u * v * ds(1)) return M, K, A, M_
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 strain(v): return fn.sym(fn.grad(v)) # boundary conditions bdry = fn.MeshFunction("size_t", mesh, 1) bdry.set_all(0) FooT = fn.CompiledSubDomain( "(x[0] >= -0.2) && (x[0] <= 0.2) && near(x[1], 0.75) && on_boundary") GammaU = fn.CompiledSubDomain( "( near(x[0], -0.5) || near(x[1], 0.0) ) && on_boundary") GammaU.mark(bdry, 31) FooT.mark(bdry, 32) ds = fn.Measure("ds", subdomain_data=bdry) 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
def __init__(self, lagrangian, bcs_list, states, adjoints, config, ksp_options, adjoint_ksp_options): """Initializes the form handler. Parameters ---------- lagrangian : cashocs._forms.Lagrangian The lagrangian of 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. adjoints : list[dolfin.function.function.Function] The function that acts as the adjoint variable. config : configparser.ConfigParser The configparser object of the config file. 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. """ # Initialize the attributes from the arguments self.lagrangian = lagrangian self.bcs_list = bcs_list self.states = states self.adjoints = adjoints self.config = config self.state_ksp_options = ksp_options self.adjoint_ksp_options = adjoint_ksp_options # Further initializations self.cost_functional_form = self.lagrangian.cost_functional_form self.state_forms = self.lagrangian.state_forms self.state_dim = len(self.states) self.state_spaces = [x.function_space() for x in self.states] self.adjoint_spaces = [x.function_space() for x in self.adjoints] # Test if state_spaces coincide with adjoint_spaces if self.state_spaces == self.adjoint_spaces: self.state_adjoint_equal_spaces = True else: self.state_adjoint_equal_spaces = False self.mesh = self.state_spaces[0].mesh() self.dx = fenics.Measure('dx', self.mesh) self.trial_functions_state = [ fenics.TrialFunction(V) for V in self.state_spaces ] self.test_functions_state = [ fenics.TestFunction(V) for V in self.state_spaces ] self.trial_functions_adjoint = [ fenics.TrialFunction(V) for V in self.adjoint_spaces ] self.test_functions_adjoint = [ fenics.TestFunction(V) for V in self.adjoint_spaces ] self.state_is_linear = self.config.getboolean('StateSystem', 'is_linear', fallback=False) self.state_is_picard = self.config.getboolean('StateSystem', 'picard_iteration', fallback=False) self.opt_algo = _optimization_algorithm_configuration(config) if self.opt_algo == 'pdas': self.inner_pdas = self.config.get('AlgoPDAS', 'inner_pdas') self.__compute_state_equations() self.__compute_adjoint_equations()
def __init__(self, form_handler): """Initializes the regularization Parameters ---------- form_handler : cashocs._forms.ShapeFormHandler the corresponding shape form handler object """ self.form_handler = form_handler self.config = self.form_handler.config self.dx = fenics.Measure('dx', self.form_handler.mesh) self.ds = fenics.Measure('ds', self.form_handler.mesh) self.spatial_coordinate = fenics.SpatialCoordinate( self.form_handler.mesh) self.measure_hole = self.config.getboolean('Regularization', 'measure_hole', fallback=False) if self.measure_hole: self.x_start = self.config.getfloat('Regularization', 'x_start', fallback=0.0) self.x_end = self.config.getfloat('Regularization', 'x_end', fallback=1.0) if not self.x_end >= self.x_start: raise ConfigError('Regularization', 'x_end', 'x_end must not be smaller than x_start.') self.delta_x = self.x_end - self.x_start self.y_start = self.config.getfloat('Regularization', 'y_start', fallback=0.0) self.y_end = self.config.getfloat('Regularization', 'y_end', fallback=1.0) if not self.y_end >= self.y_start: raise ConfigError('Regularization', 'y_end', 'y_end must not be smaller than y_start.') self.delta_y = self.y_end - self.y_start self.z_start = self.config.getfloat('Regularization', 'z_start', fallback=0.0) self.z_end = self.config.getfloat('Regularization', 'z_end', fallback=1.0) if not self.z_end >= self.z_start: raise ConfigError('Regularization', 'z_end', 'z_end must not be smaller than z_start.') self.delta_z = self.z_end - self.z_start if self.form_handler.mesh.geometric_dimension() == 2: self.delta_z = 1.0 self.mu_volume = self.config.getfloat('Regularization', 'factor_volume', fallback=0.0) self.target_volume = self.config.getfloat('Regularization', 'target_volume', fallback=0.0) if self.config.getboolean('Regularization', 'use_initial_volume', fallback=False): if not self.measure_hole: self.target_volume = fenics.assemble(Constant(1) * self.dx) else: self.target_volume = self.delta_x * self.delta_y * self.delta_z - fenics.assemble( Constant(1.0) * self.dx) self.mu_surface = self.config.getfloat('Regularization', 'factor_surface', fallback=0.0) self.target_surface = self.config.getfloat('Regularization', 'target_surface', fallback=0.0) if self.config.getboolean('Regularization', 'use_initial_surface', fallback=False): self.target_surface = fenics.assemble(Constant(1) * self.ds) self.mu_barycenter = self.config.getfloat('Regularization', 'factor_barycenter', fallback=0.0) self.target_barycenter_list = json.loads( self.config.get('Regularization', 'target_barycenter', fallback='[0,0,0]')) if not type(self.target_barycenter_list) == list: raise ConfigError('Regularization', 'target_barycenter', 'This has to be a list.') if self.form_handler.mesh.geometric_dimension() == 2 and len( self.target_barycenter_list) == 2: self.target_barycenter_list.append(0.0) if self.config.getboolean('Regularization', 'use_initial_barycenter', fallback=False): self.target_barycenter_list = [0.0, 0.0, 0.0] if not self.measure_hole: volume = fenics.assemble(Constant(1) * self.dx) self.target_barycenter_list[0] = fenics.assemble( self.spatial_coordinate[0] * self.dx) / volume self.target_barycenter_list[1] = fenics.assemble( self.spatial_coordinate[1] * self.dx) / volume if self.form_handler.mesh.geometric_dimension() == 3: self.target_barycenter_list[2] = fenics.assemble( self.spatial_coordinate[2] * self.dx) / volume else: self.target_barycenter_list[2] = 0.0 else: volume = self.delta_x * self.delta_y * self.delta_z - fenics.assemble( Constant(1) * self.dx) self.target_barycenter_list[0] = ( 0.5 * (pow(self.x_end, 2) - pow(self.x_start, 2)) * self.delta_y * self.delta_z - fenics.assemble( self.spatial_coordinate[0] * self.dx)) / volume self.target_barycenter_list[1] = ( 0.5 * (pow(self.y_end, 2) - pow(self.y_start, 2)) * self.delta_x * self.delta_z - fenics.assemble( self.spatial_coordinate[1] * self.dx)) / volume if self.form_handler.mesh.geometric_dimension() == 3: self.target_barycenter_list[2] = ( 0.5 * (pow(self.z_end, 2) - pow(self.z_start, 2)) * self.delta_x * self.delta_y - fenics.assemble( self.spatial_coordinate[2] * self.dx)) / volume else: self.target_barycenter_list[2] = 0.0 if not (self.mu_volume >= 0.0 and self.mu_surface >= 0.0 and self.mu_barycenter >= 0.0): raise ConfigError( 'Regularization', 'mu_volume, mu_surface, or mu_barycenter', 'All regularization constants have to be nonnegative.') if self.mu_volume > 0.0 or self.mu_surface > 0.0 or self.mu_barycenter > 0.0: self.has_regularization = True else: self.has_regularization = False # self.relative_scaling = self.config.getboolean('Regularization', 'relative_scaling') # if self.relative_scaling and self.has_regularization: # self.scale_weights() self.current_volume = fenics.Expression('val', degree=0, val=1.0) self.current_surface = fenics.Expression('val', degree=0, val=1.0) self.current_barycenter_x = fenics.Expression('val', degree=0, val=0.0) self.current_barycenter_y = fenics.Expression('val', degree=0, val=0.0) self.current_barycenter_z = fenics.Expression('val', degree=0, val=0.0)
def regular_box_mesh(n=10, S_x=0.0, S_y=0.0, S_z=None, E_x=1.0, E_y=1.0, E_z=None): r"""Creates a mesh corresponding to a rectangle or cube. This function creates a uniform mesh of either a rectangle or a cube, with specified start (``S_``) and end points (``E_``). The resulting mesh uses ``n`` elements along the shortest direction and accordingly many along the longer ones. The resulting domain is .. math:: \begin{alignedat}{2} &[S_x, E_x] \times [S_y, E_y] \quad &&\text{ in } 2D, \\ &[S_x, E_x] \times [S_y, E_y] \times [S_z, E_z] \quad &&\text{ in } 3D. \end{alignedat} The boundary markers are ordered as follows: - 1 corresponds to :math:`x=S_x`. - 2 corresponds to :math:`x=E_x`. - 3 corresponds to :math:`y=S_y`. - 4 corresponds to :math:`y=E_y`. - 5 corresponds to :math:`z=S_z` (only in 3D). - 6 corresponds to :math:`z=E_z` (only in 3D). Parameters ---------- n : int Number of elements in the shortest coordinate direction. S_x : float Start of the x-interval. S_y : float Start of the y-interval. S_z : float or None, optional Start of the z-interval, mesh is 2D if this is ``None`` (default is ``None``). E_x : float End of the x-interval. E_y : float End of the y-interval. E_z : float or None, optional End of the z-interval, mesh is 2D if this is ``None`` (default is ``None``). Returns ------- mesh : dolfin.cpp.mesh.Mesh The computational mesh. subdomains : dolfin.cpp.mesh.MeshFunctionSizet A MeshFunction object containing the subdomains. boundaries : dolfin.cpp.mesh.MeshFunctionSizet A MeshFunction object containing the boundaries. dx : ufl.measure.Measure The volume measure of the mesh corresponding to subdomains. ds : ufl.measure.Measure The surface measure of the mesh corresponding to boundaries. dS : ufl.measure.Measure The interior facet measure of the mesh corresponding to boundaries. """ n = int(n) if not n > 0: raise InputError('cashocs.geometry.regular_box_mesh', 'n', 'This needs to be positive.') if not S_x < E_x: raise InputError( 'cashocs.geometry.regular_box_mesh', 'S_x', 'Incorrect input for the x-coordinate. S_x has to be smaller than E_x.' ) if not S_y < E_y: raise InputError( 'cashocs.geometry.regular_box_mesh', 'S_y', 'Incorrect input for the y-coordinate. S_y has to be smaller than E_y.' ) if not ((S_z is None and E_z is None) or (S_z < E_z)): raise InputError( 'cashocs.geometry.regular_box_mesh', 'S_z', 'Incorrect input for the z-coordinate. S_z has to be smaller than E_z, or only one of them is specified.' ) if S_z is None: lx = E_x - S_x ly = E_y - S_y sizes = [lx, ly] dim = 2 else: lx = E_x - S_x ly = E_y - S_y lz = E_z - S_z sizes = [lx, ly, lz] dim = 3 size_min = np.min(sizes) num_points = [int(np.round(length / size_min * n)) for length in sizes] if S_z is None: mesh = fenics.RectangleMesh(fenics.Point(S_x, S_y), fenics.Point(E_x, E_y), num_points[0], num_points[1]) else: mesh = fenics.BoxMesh(fenics.Point(S_x, S_y, S_z), fenics.Point(E_x, E_y, E_z), num_points[0], num_points[1], num_points[2]) subdomains = fenics.MeshFunction('size_t', mesh, dim=dim) boundaries = fenics.MeshFunction('size_t', mesh, dim=dim - 1) x_min = fenics.CompiledSubDomain('on_boundary && near(x[0], sx, tol)', tol=fenics.DOLFIN_EPS, sx=S_x) x_max = fenics.CompiledSubDomain('on_boundary && near(x[0], ex, tol)', tol=fenics.DOLFIN_EPS, ex=E_x) x_min.mark(boundaries, 1) x_max.mark(boundaries, 2) y_min = fenics.CompiledSubDomain('on_boundary && near(x[1], sy, tol)', tol=fenics.DOLFIN_EPS, sy=S_y) y_max = fenics.CompiledSubDomain('on_boundary && near(x[1], ey, tol)', tol=fenics.DOLFIN_EPS, ey=E_y) y_min.mark(boundaries, 3) y_max.mark(boundaries, 4) if S_z is not None: z_min = fenics.CompiledSubDomain('on_boundary && near(x[2], sz, tol)', tol=fenics.DOLFIN_EPS, sz=S_z) z_max = fenics.CompiledSubDomain('on_boundary && near(x[2], ez, tol)', tol=fenics.DOLFIN_EPS, ez=E_z) z_min.mark(boundaries, 5) z_max.mark(boundaries, 6) dx = fenics.Measure('dx', mesh, subdomain_data=subdomains) ds = fenics.Measure('ds', mesh, subdomain_data=boundaries) dS = fenics.Measure('dS', mesh) return mesh, subdomains, boundaries, dx, ds, dS
############################### IMPORT MESH ################################## #cprint("\nMESH PRE-PROCESSING", 'blue', attrs=['bold']) # Import mesh and groups #cprint("Creating gmsh mesh...", 'green') subprocess.check_output("gmsh ./gmsh/beam.geo -3", shell=True) #cprint("Converting mesh to DOLFIN format...", 'green') subprocess.check_output('dolfin-convert ./gmsh/beam.msh mesh/beam.xml', shell=True) #cprint("Importing mesh in FEniCS...", 'green') mesh = fe.Mesh('mesh/beam.xml') #cprint("Generating boundaries and subdomains...", 'green') subdomains = fe.MeshFunction("size_t", mesh, "mesh/beam_physical_region.xml") 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
def regular_mesh(n=10, L_x=1.0, L_y=1.0, L_z=None): r"""Creates a mesh corresponding to a rectangle or cube. This function creates a uniform mesh of either a rectangle or a cube, starting at the origin and having length specified in ``L_x``, ``L_y``, and ``L_z``. The resulting mesh uses ``n`` elements along the shortest direction and accordingly many along the longer ones. The resulting domain is .. math:: \begin{alignedat}{2} &[0, L_x] \times [0, L_y] \quad &&\text{ in } 2D, \\ &[0, L_x] \times [0, L_y] \times [0, L_z] \quad &&\text{ in } 3D. \end{alignedat} The boundary markers are ordered as follows: - 1 corresponds to :math:`x=0`. - 2 corresponds to :math:`x=L_x`. - 3 corresponds to :math:`y=0`. - 4 corresponds to :math:`y=L_y`. - 5 corresponds to :math:`z=0` (only in 3D). - 6 corresponds to :math:`z=L_z` (only in 3D). Parameters ---------- n : int Number of elements in the shortest coordinate direction. L_x : float Length in x-direction. L_y : float Length in y-direction. L_z : float or None, optional Length in z-direction, if this is ``None``, then the geometry will be two-dimensional (default is ``None``). Returns ------- mesh : dolfin.cpp.mesh.Mesh The computational mesh. subdomains : dolfin.cpp.mesh.MeshFunctionSizet A :py:class:`fenics.MeshFunction` object containing the subdomains. boundaries : dolfin.cpp.mesh.MeshFunctionSizet A MeshFunction object containing the boundaries. dx : ufl.measure.Measure The volume measure of the mesh corresponding to subdomains. ds : ufl.measure.Measure The surface measure of the mesh corresponding to boundaries. dS : ufl.measure.Measure The interior facet measure of the mesh corresponding to boundaries. """ if not n > 0: raise InputError('cashocs.geometry.regular_mesh', 'n', 'This needs to be positive.') if not L_x > 0.0: raise InputError('cashocs.geometry.regular_mesh', 'L_x', 'L_x needs to be positive') if not L_y > 0.0: raise InputError('cashocs.geometry.regular_mesh', 'L_y', 'L_y needs to be positive') if not (L_z is None or L_z > 0.0): raise InputError('cashocs.geometry.regular_mesh', 'L_z', 'L_z needs to be positive or None (for 2D mesh)') n = int(n) if L_z is None: sizes = [L_x, L_y] dim = 2 else: sizes = [L_x, L_y, L_z] dim = 3 size_min = np.min(sizes) num_points = [int(np.round(length / size_min * n)) for length in sizes] if L_z is None: mesh = fenics.RectangleMesh(fenics.Point(0, 0), fenics.Point(sizes), num_points[0], num_points[1]) else: mesh = fenics.BoxMesh(fenics.Point(0, 0, 0), fenics.Point(sizes), num_points[0], num_points[1], num_points[2]) subdomains = fenics.MeshFunction('size_t', mesh, dim=dim) boundaries = fenics.MeshFunction('size_t', mesh, dim=dim - 1) x_min = fenics.CompiledSubDomain('on_boundary && near(x[0], 0, tol)', tol=fenics.DOLFIN_EPS) x_max = fenics.CompiledSubDomain('on_boundary && near(x[0], length, tol)', tol=fenics.DOLFIN_EPS, length=sizes[0]) x_min.mark(boundaries, 1) x_max.mark(boundaries, 2) y_min = fenics.CompiledSubDomain('on_boundary && near(x[1], 0, tol)', tol=fenics.DOLFIN_EPS) y_max = fenics.CompiledSubDomain('on_boundary && near(x[1], length, tol)', tol=fenics.DOLFIN_EPS, length=sizes[1]) y_min.mark(boundaries, 3) y_max.mark(boundaries, 4) if L_z is not None: z_min = fenics.CompiledSubDomain('on_boundary && near(x[2], 0, tol)', tol=fenics.DOLFIN_EPS) z_max = fenics.CompiledSubDomain( 'on_boundary && near(x[2], length, tol)', tol=fenics.DOLFIN_EPS, length=sizes[2]) z_min.mark(boundaries, 5) z_max.mark(boundaries, 6) dx = fenics.Measure('dx', mesh, subdomain_data=subdomains) ds = fenics.Measure('ds', mesh, subdomain_data=boundaries) dS = fenics.Measure('dS', mesh) return mesh, subdomains, boundaries, dx, ds, dS
def compute_static_deformation(self): assert self.mesh is not None # now we define subdomains on the mesh bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary') top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary') # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7') # Initialize mesh function for interior domains self.domains = fe.MeshFunction('size_t', self.mesh, 3) self.domains.set_all(0) # middle.mark(self.domains, 1) # Initialize mesh function for boundary domains self.boundaries = fe.MeshFunction('size_t', self.mesh, 2) self.boundaries.set_all(0) bottom.mark(self.boundaries, 1) top.mark(self.boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries self.dx = fe.Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.ds = fe.Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) # define function spaces V = fe.VectorFunctionSpace(self.mesh, "Lagrange", 1) # now we define subdomains on the mesh bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary') top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary') # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7') d = self.mesh.geometry().dim() # Initialize mesh function for interior domains self.domains = fe.MeshFunction('size_t', self.mesh, d) self.domains.set_all(0) # middle.mark(self.domains, 1) # Initialize mesh function for boundary domains self.boundaries = fe.MeshFunction('size_t', self.mesh, d - 1) self.boundaries.set_all(0) bottom.mark(self.boundaries, 1) top.mark(self.boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries self.dx = fe.Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.ds = fe.Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) c_zero = fe.Constant((0, 0, 0)) # define boundary conditions bc_bottom = fe.DirichletBC(V, c_zero, bottom) bc_top = fe.DirichletBC(V, c_zero, top) bcs = [bc_bottom] # , bc_top] # define functions du = TrialFunction(V) v = TestFunction(V) u = Function(V) B = fe.Constant((0., 2.0, 0.)) T = fe.Constant((0.0, 0.0, 0.0)) d = u.geometric_dimension() I = fe.Identity(d) F = I + grad(u) C = F.T * F I_1 = tr(C) J = det(F) E, mu = 10., 0.3 mu, lmbda = fe.Constant(E / (2 * (1 + mu))), fe.Constant( E * mu / ((1 + mu) * (1 - 2 * mu))) # stored energy (comp. neo-hookean model) psi = (mu / 2.) * (I_1 - 3) - mu * fe.ln(J) + (lmbda / 2.) * (fe.ln(J))**2 dx = self.dx ds = self.ds Pi = psi * fe.dx - dot(B, u) * fe.dx - dot(T, u) * fe.ds F = fe.derivative(Pi, u, v) J = fe.derivative(F, u, du) fe.solve(F == 0, u, bcs, J=J) # save results self.u = u # write to disk output = fe.File("/tmp/static.pvd") output << u
def import_mesh(arg): """Imports a mesh file for use with CASHOCS / FEniCS. This function imports a mesh file that was generated by GMSH and converted to .xdmf with the command line function :ref:`cashocs-convert <cashocs_convert>`. If there are Physical quantities specified in the GMSH file, these are imported to the subdomains and boundaries output of this function and can also be directly accessed via the measures, e.g., with ``dx(1)``, ``ds(1)``, etc. Parameters ---------- arg : str or configparser.ConfigParser This is either a string, in which case it corresponds to the location of the mesh file in .xdmf file format, or a config file that has this path stored in its settings, under the section Mesh, as parameter ``mesh_file``. Returns ------- mesh : dolfin.cpp.mesh.Mesh The imported (computational) mesh. subdomains : dolfin.cpp.mesh.MeshFunctionSizet A :py:class:`fenics.MeshFunction` object containing the subdomains, i.e., the Physical regions marked in the GMSH file. boundaries : dolfin.cpp.mesh.MeshFunctionSizet A MeshFunction object containing the boundaries, i.e., the Physical regions marked in the GMSH file. Can, e.g., be used to set up boundary conditions. dx : ufl.measure.Measure The volume measure of the mesh corresponding to the subdomains (i.e. GMSH Physical region indices). ds : ufl.measure.Measure The surface measure of the mesh corresponding to the boundaries (i.e. GMSH Physical region indices). dS : ufl.measure.Measure The interior facet measure of the mesh corresponding to boundaries (i.e. GMSH Physical region indices). """ start_time = time.time() print('Importing mesh to FEniCS') # Check for the file format if type(arg) == str: mesh_file = arg mesh_attribute = 'str' elif type(arg) == configparser.ConfigParser: mesh_attribute = 'config' ### overloading for remeshing if not arg.getboolean('Mesh', 'remesh', fallback=False): mesh_file = arg.get('Mesh', 'mesh_file') else: if not ('_cashocs_remesh_flag' in sys.argv): mesh_file = arg.get('Mesh', 'mesh_file') else: temp_dir = sys.argv[-1] with open(temp_dir + '/temp_dict.json', 'r') as file: temp_dict = json.load(file) mesh_file = temp_dict['mesh_file'] else: raise InputError( 'cashocs.geometry.import_mesh', 'arg', 'Not a valid argument for import_mesh. Has to be either a path to a mesh file (str) or a config.' ) if mesh_file[-5:] == '.xdmf': file_string = mesh_file[:-5] else: raise InputError( 'cashocs.geometry.import_mesh', 'arg', 'Not a suitable mesh file format. Has to end in .xdmf.') mesh = fenics.Mesh() xdmf_file = fenics.XDMFFile(mesh.mpi_comm(), mesh_file) xdmf_file.read(mesh) xdmf_file.close() subdomains_mvc = fenics.MeshValueCollection('size_t', mesh, mesh.geometric_dimension()) boundaries_mvc = fenics.MeshValueCollection('size_t', mesh, mesh.geometric_dimension() - 1) if os.path.isfile(file_string + '_subdomains.xdmf'): xdmf_subdomains = fenics.XDMFFile(mesh.mpi_comm(), file_string + '_subdomains.xdmf') xdmf_subdomains.read(subdomains_mvc, 'subdomains') xdmf_subdomains.close() if os.path.isfile(file_string + '_boundaries.xdmf'): xdmf_boundaries = fenics.XDMFFile(mesh.mpi_comm(), file_string + '_boundaries.xdmf') xdmf_boundaries.read(boundaries_mvc, 'boundaries') xdmf_boundaries.close() subdomains = fenics.MeshFunction('size_t', mesh, subdomains_mvc) boundaries = fenics.MeshFunction('size_t', mesh, boundaries_mvc) dx = fenics.Measure('dx', domain=mesh, subdomain_data=subdomains) ds = fenics.Measure('ds', domain=mesh, subdomain_data=boundaries) dS = fenics.Measure('dS', domain=mesh, subdomain_data=boundaries) end_time = time.time() print('Done Importing Mesh. Elapsed Time: ' + format(end_time - start_time, '.3e') + ' s') print('') # Add an attribute to the mesh to show with what procedure it was generated mesh._cashocs_generator = mesh_attribute return mesh, subdomains, boundaries, dx, ds, dS
# section of boundary that is free free_boundary = fn.CompiledSubDomain( "(near(x[1], mesh_height) || near(x[0], mesh_width/2)) && on_boundary", mesh_height=mesh_height, mesh_width=mesh_width) # section of boundary that is a rigid wall wall_boundary = fn.CompiledSubDomain( "(near(x[1], 0.0) || near(x[0], -mesh_width/2)) && on_boundary", mesh_width=mesh_width) # mark boundaries free_boundary.mark(mesh_boundary, 31) wall_boundary.mark(mesh_boundary, 32) # ds, for integrating ds = fn.Measure("ds", subdomain_data=mesh_boundary) # boundary conditions bcU = fn.DirichletBC(Hh.sub(0), u_g, mesh_boundary, 32) bcP = fn.DirichletBC(Hh.sub(2), p_g, mesh_boundary, 31) boundary_conditions = [bcU, bcP] # initial conditions - poroelasticity u_old = fn.interpolate(fn.Constant((0.0, 0.0)), Vhf) phi_old = fn.interpolate(fn.Constant(0.0), Zhf) p_old = fn.interpolate(fn.Constant(0.0), Qhf) # initial conditions - reaction-diffusion E_old = fn.interpolate(fn.Constant(0.0),Mhf) n_old = fn.interpolate(fn.Constant(0.0),Mhf)