def __init__(self, x0, y0, z0, R, n): class SphereSurface(SubDomain): def inside(self, x, on_boundary): return on_boundary class X_Symmetric(SubDomain): def inside(self, x, on_boundary): return near(x[0], x0) class Y_Symmetric(SubDomain): def inside(self, x, on_boundary): return near(x[1], y0) class Z_Symmetric(SubDomain): def inside(self, x, on_boundary): return near(x[2], z0) self.geometry = Sphere(Point(x0, y0, z0), R, segments=n) - Box(Point(x0 + R, y0, z0 - R), Point(x0 - R, y0 - R, z0 + R)) - Box(Point(x0 - R, y0 + R, z0), Point(x0 + R, y0, z0 - R)) - Box(Point(x0, y0, z0), Point(x0 - R, y0 + R, z0 + R)) self.mesh = generate_mesh(self.geometry, n) self.domains = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()) self.domains.set_all(0) self.dx = Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.boundaries = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()-1) self.boundaries.set_all(0) self.sphereSurface = SphereSurface() self.sphereSurface.mark(self.boundaries, 1) self.x_symmetric = X_Symmetric() self.x_symmetric.mark(self.boundaries, 2) self.y_symmetric = Y_Symmetric() self.y_symmetric.mark(self.boundaries, 3) self.z_symmetric = Z_Symmetric() self.z_symmetric.mark(self.boundaries, 4) self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) self.dS = Measure('dS', domain=self.mesh, subdomain_data=self.boundaries)
def dP(self, domain = "all"): """ Convenience wrapper for integral-point measure. If the mesh does not contain any cell domains, the measure for the whole mesh is returned. *Arguments* domain (:class:`string` / :class:`int`) name or ID of domain *Returns* :class:`dolfin:Measure` the measure """ if not self.mesh_has_domains(): return Measure('dP', self.mesh) if not self._dP.has_key(domain): v = TestFunction(self.FunctionSpace()) values = assemble(v*self.dx(domain)).array() # TODO improve this? markers = ((np.sign(np.ceil(values) - 0.5) + 1.0) / 2.0).astype(np.uint64) vertex_domains = MeshFunction('size_t', self.mesh, 0) vertex_domains.array()[:] = markers self._dP[domain] = Measure('dP', self.mesh)[vertex_domains](1) return self._dP[domain]
def mesh_generator(n): mesh = UnitSquareMesh(n, n, "left/right") dim = mesh.topology().dim() domains = MeshFunction("size_t", mesh, dim) domains.set_all(0) dx = Measure("dx", subdomain_data=domains) boundaries = MeshFunction("size_t", mesh, dim - 1) boundaries.set_all(0) ds = Measure("ds", subdomain_data=boundaries) return mesh, dx, ds
def create_mesh(self, parameters): from dolfin import Point, XDMFFile import hashlib d = { 'rad': parameters['geometry']['rad'], 'h': parameters['geometry']['meshsize'] } # fname = 'coinforall' # fname = 'coin' fname = 'coinforall_small' meshfile = "meshes/%s-%s.xml" % (fname, self.signature) if os.path.isfile(meshfile): print("Meshfile %s exists" % meshfile) else: print("Create meshfile, meshsize {}".format( parameters['geometry']['meshsize'])) nel = int(parameters['geometry']['rad'] / parameters['geometry']['meshsize']) # geom = mshr.Circle(Point(0., 0.), parameters['geometry']['rad']) # mesh = mshr.generate_mesh(geom, nel) mesh_template = open('scripts/coin_template.geo') src = Template(mesh_template.read()) geofile = src.substitute(d) if MPI.rank(MPI.comm_world) == 0: with open("scripts/coin-%s" % self.signature + ".geo", 'w') as f: f.write(geofile) form_compiler_parameters = { "representation": "uflacs", "quadrature_degree": 2, "optimize": True, "cpp_optimize": True, } mesh = Mesh("meshes/{}.xml".format(fname)) self.domains = MeshFunction( 'size_t', mesh, 'meshes/{}_physical_region.xml'.format(fname)) self.ds = Measure("exterior_facet", domain=mesh) self.dS = Measure("interior_facet", domain=mesh) self.dx = Measure("dx", metadata=form_compiler_parameters, subdomain_data=self.domains) # self.dx = Measure("dx", subdomain_data=self.domains) plt.colorbar(plot(self.domains)) plt.savefig('domains.pdf') return mesh
def recompute_dJ(self): """ Create gradient expression for deformation algorithm """ # FIXME: probably only works with one obstacle # Recalculate barycenter and volume of obstacle self.geometric_quantities() self.integrand_list = [] dJ = 0 solver.dJ_form = [] for i in range(1, self.N): # Integrand of gradient x = SpatialCoordinate(self.multimesh.part(i)) u_i = self.u.part(i) dJ_stokes = -inner(grad(u_i), grad(u_i)) dJ_vol = -Constant(2 * self.vfac) * (self.Vol - self.Vol0) dJ_bar = Constant(2 * self.bfac) / self.Vol * ( (self.bx - x[0]) * self.bxoff + (self.by - x[1]) * self.byoff) integrand = dJ_stokes + dJ_vol + dJ_bar dDeform = Measure("ds", subdomain_data=self.mfs[i]) from femorph import VolumeNormal n = VolumeNormal(self.multimesh.part(i)) s = TestFunction(self.S[i]) self.integrand_list.append(n * integrand) dJ = inner(s, n) * integrand * dDeform(self.move_dict[i]["Deform"]) self.dJ_form.append(dJ)
def update_multimesh(self, step): move_norm = [] hmins = [] move_max = [] for i in range(1, self.N): s_move = self.deformation[i - 1].copy(True) s_move.vector()[:] *= step # Approximate geodesic distance dDeform = Measure("ds", subdomain_data=self.mfs[i]) n_i = FacetNormal(self.multimesh.part(i)) geo_dist_i = inner(s_move, s_move)*\ dDeform(self.move_dict[i]["Deform"]) move_norm.append(assemble(geo_dist_i)) # move_max.append(project(sqrt(s_move[0]**2 + s_move[1]**2), # FunctionSpace(self.multimesh.part(i),"CG",1) # ).vector().max()) # hmins.append(self.multimesh.part(i).hmin()) ALE.move(self.multimesh.part(i), s_move) # Compute L2 norm of movement self.move_norm = sqrt(sum(move_norm)) # self.move_max = max(move_max) # print(hmins, move_max) self.multimesh.build() for key in self.cover_points.keys(): self.multimesh.auto_cover(key, self.cover_points[key])
def _csd_normalization_factor(self, csd): old_a = csd.a csd.a = 1 try: return 1.0 / assemble(csd * Measure("dx", self._mesh)) finally: csd.a = old_a
def initial_conditions(self): "Return initial conditions for v and s as a dolfin.GenericFunction." n = self.num_states() # (Maximal) Number of states in MultiCellModel VS = VectorFunctionSpace(self.mesh(), "DG", 0, n+1) vs = Function(VS) markers = self.markers() u = TrialFunction(VS) v = TestFunction(VS) dy = Measure("dx", domain=self.mesh(), subdomain_data=markers) # Define projection into multiverse a = inner(u, v)*dy() Ls = list() for (k, model) in enumerate(self.models()): ic = model.initial_conditions() # Extract initial conditions n_k = model.num_states() # Extract number of local states i_k = self.keys()[k] # Extract domain index of cell model k L_k = sum(ic[j]*v[j]*dy(i_k) for j in range(n_k)) Ls.append(L_k) L = sum(Ls) solve(a == L, vs) return vs
def assign_initial_conditions(self, function): function_space = function.function_space() markers = self.markers() u = TrialFunction(function_space) v = TestFunction(function_space) dy = Measure("dx", domain=self.mesh(), subdomain_data=markers) # Define projection into multiverse a = inner(u, v) * dy() Ls = list() for k, model in enumerate(self.models()): ic = model.initial_conditions() # Extract initial conditions n_k = model.num_states() # Extract number of local states i_k = self.keys()[k] # Extract domain index of cell model k L_k = sum(ic[j] * v[j] * dy(i_k) for j in range(n_k + 1)) # include v and s Ls.append(L_k) L = sum(Ls) # solve(a == L, function) # really inaccurate params = df.KrylovSolver.default_parameters() params["absolute_tolerance"] = 1e-14 params["relative_tolerance"] = 1e-14 params["nonzero_initial_guess"] = True solver = df.KrylovSolver() solver.update_parameters(params) A, b = df.assemble_system(a, L) solver.set_operator(A) solver.solve(function.vector(), b)
def __init__(self, V, subdomains, expression_type, basis_generation): self.V = V # Parametrized function to be interpolated mock_problem = MockProblem(V) f = ParametrizedExpression( mock_problem, "exp( - 2*pow(x[0]-mu[0], 2) - 2*pow(x[1]-mu[1], 2) )", mu=(0., 0.), element=V.ufl_element()) # Subdomain measure dx = Measure("dx")(subdomain_data=subdomains)(1) # folder_prefix = os.path.join("test_eim_approximation_04_tempdir", expression_type, basis_generation) assert expression_type in ("Vector", "Matrix") if expression_type == "Vector": v = TestFunction(V) form = f * v * dx # Call Parent constructor EIMApproximation.__init__(self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) elif expression_type == "Matrix": u = TrialFunction(V) v = TestFunction(V) form = f * u * v * dx # Call Parent constructor EIMApproximation.__init__(self, mock_problem, ParametrizedTensorFactory(form), folder_prefix, basis_generation) else: # impossible to arrive here anyway thanks to the assert raise AssertionError("Invalid expression_type")
def __init__(self, x0, x1, y0, y1, z0, z1, n, unstructured=False): class Left(SubDomain): def inside(self, x, on_boundary): return near(x[0], x0) class Right(SubDomain): def inside(self, x, on_boundary): return near(x[0], x1) class Back(SubDomain): def inside(self, x, on_boundary): return near(x[1], y0) class Front(SubDomain): def inside(self, x, on_boundary): return near(x[1], y1) class Bottom(SubDomain): def inside(self, x, on_boundary): return near(x[2], z0) class Top(SubDomain): def inside(self, x, on_boundary): return near(x[2], z1) if unstructured: self.geometry = Box(Point(x0, y0, z0), Point(x1, y1, z1)) self.mesh = generate_mesh(self.geometry, n) else: nx = int(round(n**(1./3.)*(x1 - x0))) ny = int(round(n**(1./3.)*(y1 - y0))) nz = int(round(n**(1./3.)*(z1 - z0))) self.mesh = BoxMesh(Point(x0, y0, z0), Point(x1, y1, z1), nx, ny, nz) self.domains = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()) self.domains.set_all(0) self.dx = Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.boundaries = MeshFunction("size_t", self.mesh, self.mesh.topology().dim()-1) self.boundaries.set_all(0) self.left = Left() self.left.mark(self.boundaries, 1) self.right = Right() self.right.mark(self.boundaries, 2) self.front = Front() self.front.mark(self.boundaries, 3) self.back = Back() self.back.mark(self.boundaries, 4) self.bottom = Bottom() self.bottom.mark(self.boundaries, 5) self.top = Top() self.top.mark(self.boundaries, 6) self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) self.dS = Measure('dS', domain=self.mesh, subdomain_data=self.boundaries)
def calculate_volumes(self): dx = Measure('dx', domain=self.mesh1) a = Constant(1.0) * dx V1 = assemble(a) dx = Measure('dx', domain=self.mesh2) a = Constant(1.0) * dx V2 = assemble(a) dx = Measure('dx', domain=self.overlap_mesh) a = Constant(1.0) * dx VO = assemble(a) dx = Measure('dx', domain=self.mesh) a = Constant(1.0) * dx V = assemble(a) return V, V1, V2, VO
def calculate_areas(self): dx = Measure('dx', domain=self.mesh1) a = Constant(1.0) * dx A1 = assemble(a) dx = Measure('dx', domain=self.mesh2) a = Constant(1.0) * dx A2 = assemble(a) dx = Measure('dx', domain=self.overlap_mesh) a = Constant(1.0) * dx AO = assemble(a) dx = Measure('dx', domain=self.mesh) a = Constant(1.0) * dx A = assemble(a) return A, A1, A2, AO
def initialize(self, coupling_subdomain, mesh, read_field, write_field, u_n, dimension=2, t=0, n=0, coupling_marker=0): """Initializes remaining attributes. Called once, from the solver. :param read_field: function applied on the read field :param write_field: function applied on the write field """ print("Begin initializating the fenics adapter...") self._fenics_dimensions = dimension self.set_coupling_mesh(mesh, coupling_subdomain) self.set_read_field(read_field) self.set_write_field(write_field) self._precice_tau = self._interface.initialize() self._function_type = self.function_type(write_field) print('is action required') if self._interface.is_action_required( precice.action_write_initial_data()): self.write_block_data() self._interface.initialize_data() print('read available') if self._interface.is_read_data_available(): self.read_block_data() # if self.function_type(read_field) is FunctionType.SCALAR: # self._interface.read_block_scalar_data(self._read_data_id, self._n_vertices, self._vertex_ids, self._read_data) # elif self.function_type(read_field) is FunctionType.VECTOR: # self._interface.read_block_vector_data(self._read_data_id, self._n_vertices, self._vertex_ids, self._read_data.ravel()) # else: # raise Exception("Rank of function space is neither 0 nor 1") if self._interface.is_action_required( precice.action_write_iteration_checkpoint()): self._u_cp = u_n.copy(deepcopy=True) self._t_cp = t self._n_cp = n self._interface.fulfilled_action( precice.action_write_iteration_checkpoint()) #create an integration domain for the coupled boundary self.dss = Measure('ds', domain=mesh, subdomain_data=coupling_marker) print("initialization successful") return self._precice_tau
def main_slice_fem(mesh, subdomains, boundaries, src_pos, snk_pos): sigma_ROI = Constant(params.sigma_roi) sigma_SLICE = Constant(params.sigma_slice) sigma_SALINE = Constant(params.sigma_saline) sigma_AIR = Constant(0.) V = FunctionSpace(mesh, "CG", 2) v = TestFunction(V) u = TrialFunction(V) phi = Function(V) dx = Measure("dx")(subdomain_data=subdomains) ds = Measure("ds")(subdomain_data=boundaries) a = inner(sigma_ROI * grad(u), grad(v))*dx(params.roivol) + \ inner(sigma_SLICE * grad(u), grad(v))*dx(params.slicevol) + \ inner(sigma_SALINE * grad(u), grad(v))*dx(params.salinevol) L = Constant(0) * v * dx A = assemble(a) b = assemble(L) x_pos, y_pos, z_pos = src_pos point = Point(x_pos, y_pos, z_pos) delta = PointSource(V, point, 1.) delta.apply(b) x_pos, y_pos, z_pos = snk_pos point1 = Point(x_pos, y_pos, z_pos) delta1 = PointSource(V, point1, -1.) delta1.apply(b) solver = KrylovSolver("cg", "ilu") solver.parameters["maximum_iterations"] = 1000 solver.parameters["absolute_tolerance"] = 1E-8 solver.parameters["monitor_convergence"] = True info(solver.parameters, True) # set_log_level(PROGRESS) does not work in fenics 2018.1.0 solver.solve(A, phi.vector(), b) ele_pos_list = params.ele_coords vals = extract_pots(phi, ele_pos_list) # np.save(os.path.join('results', save_as), vals) return vals
def rhs_with_markerwise_field(g, mesh, v): if g is None: dz = dx rhs = 0.0 # Do make constant elif isinstance(g, Markerwise): markers = g.markers() dz = Measure("dx", domain=mesh, subdomain_data=markers) rhs = sum([g*v*dz(i) for (i, g) in zip(g.keys(), g.values())]) else: dz = dx rhs = g*v*dz() return dz, rhs
def CladdingR_solver(FC_mesh, FC_facets, FC_fs, FC_info, D_post, R_path): FC_fi, FC_fo = FC_fs h, Tfc_inner, Tb, FC_Tave = FC_info # Reading mesh data stored in .xdmf files. mesh = Mesh() with XDMFFile(FC_mesh) as infile: infile.read(mesh) mvc = MeshValueCollection("size_t", mesh, 1) with XDMFFile(FC_facets) as infile: infile.read(mvc, "name_to_read") mf = cpp.mesh.MeshFunctionSizet(mesh, mvc) #File("Circle_facet.pvd").write(mf) # Mesh data print('CladdingRod_mesh data\n', 'Number of cells: ', mesh.num_cells(), '\n Number of nodes: ', mesh.num_vertices()) # Define variational problem V = FunctionSpace(mesh, 'P', 1) u = Function(V) v = TestFunction(V) # Define boundary conditions base on pygmsh mesh mark bc = DirichletBC(V, Constant(Tfc_inner), mf, FC_fi) ds = Measure("ds", domain=mesh, subdomain_data=mf, subdomain_id=FC_fo) # Variational formulation # Klbda_ZrO2 = 18/1000 # W/(m K) --> Nuclear reactor original source # Klbda_ZrO2 = Constant(K_ZrO2(FC_Tave)) F = K_ZrO2(u) * dot(grad(u), grad(v)) * dx + h * (u - Tb) * v * ds # Compute solution du = TrialFunction(V) Gain = derivative(F, u, du) solve(F==0, u, bc, J=Gain, \ solver_parameters={"newton_solver": {"linear_solver": "lu", "relative_tolerance": 1e-9}}, \ form_compiler_parameters={"cpp_optimize": True, "representation": "uflacs", "quadrature_degree" : 2} ) # mumps # Save solution if D_post: fU_out = XDMFFile(os.path.join(R_path, 'FuelCladding', 'u.xdmf')) fU_out.write_checkpoint(u, "T", 0, XDMFFile.Encoding.HDF5, False) fU_out.close()
def _init_measure(measure="default", cell_domains=None, facet_domains=None, indicator=None): assert cell_domains is None or facet_domains is None, "You can't specify both cell_domains or facet_domains" if cell_domains is not None: assert isinstance(cell_domains, (MeshFunctionSizet, MeshFunctionInt)) if facet_domains is not None: assert isinstance(facet_domains, (MeshFunctionSizet, MeshFunctionInt)) if (cell_domains and indicator is not None): if LooseVersion(dolfin_version()) > LooseVersion("1.6.0"): dI = Measure("cell")(subdomain_data=cell_domains)(indicator) else: dI = Measure("cell")[cell_domains](indicator) elif (facet_domains and indicator is not None): if LooseVersion(dolfin_version()) > LooseVersion("1.6.0"): dI = Measure("exterior_facet")( subdomain_data=facet_domains)(indicator) else: dI = Measure("exterior_facet")[facet_domains](indicator) elif measure == "default": if indicator is not None: cbc_warning( "Indicator specified, but no domains. Will dompute average over entire domain." ) dI = dx() elif isinstance(measure, Measure): dI = measure else: raise TypeError( "Unable to create a domain measure from provided domains or measure." ) return dI
def assemble_lui_stiffness(self, g, f, mesh, robin_boundary): V = FunctionSpace(mesh, "Lagrange", self.p) u = TrialFunction(V) v = TestFunction(V) n = FacetNormal(mesh) robin = MeshFunction('size_t', mesh, mesh.topology().dim() - 1) robin_boundary.mark(robin, 1) ds = Measure('ds', subdomain_data=robin) a = inner(grad(u), grad(v)) * dx b = (1 - g) * (inner(grad(u), n)) * v * ds(1) c = f * u * v * ds(1) k = lhs(a + b - c) K = PETScMatrix() assemble(k, tensor=K) return K, V
def test_stationary_solve(show=False): problem = problems.Crucible() boundaries = problem.wp_boundaries average_temp = 1551.0 material = problem.subdomain_materials[problem.wpi] rho = material.density(average_temp) cp = material.specific_heat_capacity kappa = material.thermal_conductivity my_ds = Measure("ds")(subdomain_data=boundaries) convection = None heat = maelstrom.heat.Heat( problem.Q, kappa, rho, cp, convection, source=Constant(0.0), dirichlet_bcs=problem.theta_bcs_d, neumann_bcs=problem.theta_bcs_n, robin_bcs=problem.theta_bcs_r, my_dx=dx, my_ds=my_ds, ) theta_reference = heat.solve_stationary() theta_reference.rename("theta", "temperature") if show: # with XDMFFile('temperature.xdmf') as f: # f.parameters['flush_output'] = True # f.parameters['rewrite_function_mesh'] = False # f.write(theta_reference) tri = plot(theta_reference) plt.colorbar(tri) plt.show() assert abs(maelstrom.helpers.average(theta_reference) - 1551.0) < 1.0e-1 return theta_reference
def generate_H1_deformation(self): self.deformation = [] for i in range(1, self.N): S_i = VectorFunctionSpace(self.multimesh.part(i), "CG", 1) u_i, v_i = TrialFunction(S_i), TestFunction(S_i) d_free = Measure("ds", domain=self.multimesh.part(i), subdomain_data=self.mfs[i], subdomain_id=self.move_dict[i]["Deform"]) plot(-self.integrand_list[i - 1]) plt.show() a_i = inner(u_i, v_i) * dx + 0.01 * inner(grad(u_i), grad(v_i)) * dx n_i = FacetNormal(self.multimesh.part(i)) l_i = inner(v_i, -self.integrand_list[i - 1]) * d_free s_i = Function(S_i) solve(a_i == l_i, s_i) plot(s_i) plt.show() self.deformation.append(s_i)
def big_error_norms(self, u, overlap_subdomain): V = FunctionSpace(self.mesh, "Lagrange", self.p) uu = Function(V) uu.vector()[:] = u.vector() # uu.vector()[:] = u.vector() overlap_marker = MeshFunction('size_t', self.mesh, self.mesh.topology().dim()) overlap_subdomain.mark(overlap_marker, 1) dxo = Measure('dx', subdomain_data=overlap_marker) error = (uu**2) * dxo semi_error = inner(grad(uu), grad(uu)) * dxo L2 = assemble(error) H1 = L2 + assemble(semi_error) SH = H1 - L2 return L2, H1, SH
def __init__(self, w_sim, h_sim, w_wg, h_wg, res): # Create mesh with two domains, waveguide + cladding self.res = res domain = Rectangle(Point(-w_sim / 2, -h_sim / 2), Point(w_sim / 2, h_sim / 2)) domain.set_subdomain( 1, Rectangle(Point(-w_sim / 2, -h_sim / 2), Point(w_sim / 2, h_sim / 2))) domain.set_subdomain( 2, Rectangle(Point(-w_wg / 2, -h_wg / 2), Point(w_wg / 2, h_wg / 2))) self.mesh = generate_mesh(domain, self.res) self.mesh.init() # Initialize mesh function for interior domains self.waveguide = Waveguide(w_wg, h_wg) self.domains = MeshFunction("size_t", self.mesh, 2) self.domains.set_all(0) self.waveguide.mark(self.domains, 1) # Define new measures associated with the interior domains self.dx = Measure("dx")(subdomain_data=self.domains)
def recompute_dJ(self): """ Create gradient expression for deformation algorithm """ # Recalculate barycenter and volume of obstacle self.compute_volume_bary() # Integrand of gradient x = SpatialCoordinate(mesh) dJ_stokes = -inner(grad(self.u), grad(self.u)) dJ_vol = - Constant(2*self.vfac)*(self.Vol-self.Vol0) dJ_bar = Constant(2*self.bfac)/self.Vol*((self.bx-x[0])*self.bx_off + (self.by-x[1])*self.by_off) self.integrand = dJ_stokes + dJ_vol + dJ_bar dDeform = Measure("ds", subdomain_data=self.mf) from femorph import VolumeNormal n = VolumeNormal(mesh) s = TestFunction(self.S) dJ = 0 # Sum up over all moving boundaries for marker in self.move_dict["Deform"]: dJ += inner(s,n)*self.integrand*dDeform(marker) self.dJ_form = dJ
def create_integration_subdomains(self): self._dx = Measure("dx")(subdomain_data=self._subdomains) self._ds = Measure("ds")(subdomain_data=self._boundaries)
def __init__(self): GMSH_EPS = 1.0e-15 # https://fenicsproject.org/qa/12891/initialize-mesh-from-vertices-connectivities-at-once points, cells, point_data, cell_data, _ = meshes.crucible_with_coils.generate( ) # Convert the cell data to 'uint' so we can pick a size_t MeshFunction # below as usual. for k0 in cell_data: for k1 in cell_data[k0]: cell_data[k0][k1] = numpy.array(cell_data[k0][k1], dtype=numpy.dtype("uint")) with TemporaryDirectory() as temp_dir: tmp_filename = os.path.join(temp_dir, "test.xml") meshio.write_points_cells( tmp_filename, points, cells, cell_data=cell_data, file_format="dolfin-xml", ) self.mesh = Mesh(tmp_filename) self.subdomains = MeshFunction( "size_t", self.mesh, os.path.join(temp_dir, "test_gmsh:physical.xml")) self.subdomain_materials = { 1: my_materials.porcelain, 2: materials.argon, 3: materials.gallium_arsenide_solid, 4: materials.gallium_arsenide_liquid, 27: materials.air, } # coils for k in range(5, 27): self.subdomain_materials[k] = my_materials.ek90 # Define the subdomains which together form a single coil. self.coil_domains = [ [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23], [24, 25, 26], ] self.wpi = 4 self.submesh_workpiece = SubMesh(self.mesh, self.subdomains, self.wpi) # http://fenicsproject.org/qa/2026/submesh-workaround-for-parallel-computation # submesh_parallel_bug_fixed = False # if submesh_parallel_bug_fixed: # submesh_workpiece = SubMesh(self.mesh, self.subdomains, self.wpi) # else: # # To get the mesh in parallel, we need to read it in from a file. # # Writing out can only happen in serial mode, though. :/ # base = os.path.join(current_path, # '../../meshes/2d/crucible-with-coils-submesh' # ) # filename = base + '.xml' # if not os.path.isfile(filename): # warnings.warn( # 'Submesh file \'{}\' does not exist. Creating... '.format( # filename # )) # if MPI.size(mpi_comm_world()) > 1: # raise RuntimeError( # 'Can only write submesh in serial mode.' # ) # submesh_workpiece = \ # SubMesh(self.mesh, self.subdomains, self.wpi) # output_stream = File(filename) # output_stream << submesh_workpiece # # Read the mesh # submesh_workpiece = Mesh(filename) coords = self.submesh_workpiece.coordinates() ymin = min(coords[:, 1]) ymax = max(coords[:, 1]) # Find the top right point. k = numpy.argmax(numpy.sum(coords, 1)) topright = coords[k, :] # Initialize mesh function for boundary domains class Left(SubDomain): def inside(self, x, on_boundary): # Explicitly exclude the lowest and the highest point of the # symmetry axis. # It is necessary for the consistency of the pressure-Poisson # system in the Navier-Stokes solver that the velocity is # exactly 0 at the boundary r>0. Hence, at the corner points # (r=0, melt-crucible, melt-crystal) we must enforce u=0 # already and cannot have a component in z-direction. return (on_boundary and x[0] < GMSH_EPS and x[1] < ymax - GMSH_EPS and x[1] > ymin + GMSH_EPS) class Crucible(SubDomain): def inside(self, x, on_boundary): return on_boundary and ( (x[0] > GMSH_EPS and x[1] < ymax - GMSH_EPS) or (x[0] > topright[0] - GMSH_EPS and x[1] > topright[1] - GMSH_EPS) or (x[0] < GMSH_EPS and x[1] < ymin + GMSH_EPS)) # At the top right part (boundary melt--gas), slip is allowed, so only # n.u=0 is enforced. Very weirdly, the PPE is consistent if and only if # the end points of UpperRight are in UpperRight. This contrasts # Left(), where the end points must NOT belong to Left(). Judging from # the experiments, these settings do the right thing. # TODO try to better understand the PPE system/dolfin's boundary # settings class Upper(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > ymax - GMSH_EPS class UpperRight(SubDomain): def inside(self, x, on_boundary): return (on_boundary and x[1] > ymax - GMSH_EPS and x[0] > 0.038 - GMSH_EPS) # The crystal boundary is taken to reach up to 0.038 where the # Dirichlet boundary data is about the melting point of the crystal, # 1511K. This setting gives pretty acceptable results when there is no # convection except the one induced by buoyancy. Is there is any more # stirring going on, though, the end point of the crystal with its # fixed temperature of 1511K might be the hottest point globally. This # looks rather unphysical. # TODO check out alternatives class UpperLeft(SubDomain): def inside(self, x, on_boundary): return (on_boundary and x[1] > ymax - GMSH_EPS and x[0] < 0.038 + GMSH_EPS) left = Left() crucible = Crucible() upper_left = UpperLeft() upper_right = UpperRight() self.wp_boundaries = MeshFunction( "size_t", self.submesh_workpiece, self.submesh_workpiece.topology().dim() - 1, ) self.wp_boundaries.set_all(0) left.mark(self.wp_boundaries, 1) crucible.mark(self.wp_boundaries, 2) upper_right.mark(self.wp_boundaries, 3) upper_left.mark(self.wp_boundaries, 4) if DEBUG: from dolfin import plot, interactive plot(self.wp_boundaries, title="Boundaries") interactive() submesh_boundary_indices = { "left": 1, "crucible": 2, "upper right": 3, "upper left": 4, } # Boundary conditions for the velocity. # # [1] Incompressible flow and the finite element method; volume two; # Isothermal Laminar Flow; # P.M. Gresho, R.L. Sani; # # For the choice of function space, [1] says: # "In 2D, the triangular elements P_2^+P_1 and P_2^+P_{-1} are very # good [...]. [...] If you wish to avoid bubble functions on # triangular elements, P_2P_1 is not bad, and P_2(P_1+P_0) is even # better [...]." # # It turns out that adding the bubble space significantly hampers the # convergence of the Stokes solver and also considerably increases the # time it takes to construct the Jacobian matrix of the Navier--Stokes # problem if no optimization is applied. V_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(), 2) with_bubbles = False if with_bubbles: V_element += FiniteElement("B", self.submesh_workpiece.ufl_cell(), 2) self.W_element = MixedElement(3 * [V_element]) self.W = FunctionSpace(self.submesh_workpiece, self.W_element) rot0 = Expression(("0.0", "0.0", "-2*pi*x[0] * 5.0/60.0"), degree=1) # rot0 = (0.0, 0.0, 0.0) rot1 = Expression(("0.0", "0.0", "2*pi*x[0] * 5.0/60.0"), degree=1) self.u_bcs = [ DirichletBC(self.W, rot0, crucible), DirichletBC(self.W.sub(0), 0.0, left), DirichletBC(self.W.sub(2), 0.0, left), # Make sure that u[2] is 0 at r=0. DirichletBC(self.W, rot1, upper_left), DirichletBC(self.W.sub(1), 0.0, upper_right), ] self.p_bcs = [] self.P_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(), 1) self.P = FunctionSpace(self.submesh_workpiece, self.P_element) self.Q_element = FiniteElement("CG", self.submesh_workpiece.ufl_cell(), 2) self.Q = FunctionSpace(self.submesh_workpiece, self.Q_element) # Dirichlet. # This is a bit of a tough call since the boundary conditions need to # be read from a Tecplot file here. filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data/crucible-boundary.dat") data = tecplot_reader.read(filename) RZ = numpy.c_[data["ZONE T"]["node data"]["r"], data["ZONE T"]["node data"]["z"]] T_vals = data["ZONE T"]["node data"]["temp. [K]"] class TecplotDirichletBC(Expression): def eval(self, value, x): # Find on which edge x sits, and raise exception if it doesn't. edge_found = False for edge in data["ZONE T"]["element data"]: # Given a point X and an edge X0--X1, # # (1 - theta) X0 + theta X1, # # the minimum distance is assumed for # # argmin_theta ||(1-theta) X0 + theta X1 - X||^2 # = <X1 - X0, X - X0> / ||X1 - X0||^2. # # If the distance is 0 and 0<=theta<=1, we found the edge. # # Note that edges are 1-based in Tecplot. X0 = RZ[edge[0] - 1] X1 = RZ[edge[1] - 1] theta = numpy.dot(X1 - X0, x - X0) / numpy.dot( X1 - X0, X1 - X0) diff = (1.0 - theta) * X0 + theta * X1 - x if (numpy.dot(diff, diff) < 1.0e-10 and 0.0 <= theta and theta <= 1.0): # Linear interpolation of the temperature value. value[0] = (1.0 - theta) * T_vals[ edge[0] - 1] + theta * T_vals[edge[1] - 1] edge_found = True break # This class is supposed to be used for Dirichlet boundary # conditions. For some reason, FEniCS also evaluates # DirichletBC objects at coordinates which do not sit on the # boundary, see # <http://fenicsproject.org/qa/1033/dirichletbc-expressions-evaluated-away-from-the-boundary>. # The assigned values have no meaning though, so not assigning # values[0] here is okay. # # from matplotlib import pyplot as pp # pp.plot(x[0], x[1], 'xg') if not edge_found: value[0] = 0.0 if False: warnings.warn( "Coordinate ({:e}, {:e}) doesn't sit on edge.". format(x[0], x[1])) # pp.plot(RZ[:, 0], RZ[:, 1], '.k') # pp.plot(x[0], x[1], 'xr') # pp.show() # raise RuntimeError('Input coordinate ' # '{} is not on boundary.'.format(x)) return tecplot_dbc = TecplotDirichletBC(degree=5) self.theta_bcs_d = [DirichletBC(self.Q, tecplot_dbc, upper_left)] self.theta_bcs_d_strict = [ DirichletBC(self.Q, tecplot_dbc, upper_right), DirichletBC(self.Q, tecplot_dbc, crucible), DirichletBC(self.Q, tecplot_dbc, upper_left), ] # Neumann dTdr_vals = data["ZONE T"]["node data"]["dTempdx [K/m]"] dTdz_vals = data["ZONE T"]["node data"]["dTempdz [K/m]"] class TecplotNeumannBC(Expression): def eval(self, value, x): # Same problem as above: This expression is not only evaluated # at boundaries. for edge in data["ZONE T"]["element data"]: X0 = RZ[edge[0] - 1] X1 = RZ[edge[1] - 1] theta = numpy.dot(X1 - X0, x - X0) / numpy.dot( X1 - X0, X1 - X0) dist = numpy.linalg.norm((1 - theta) * X0 + theta * X1 - x) if dist < 1.0e-5 and 0.0 <= theta and theta <= 1.0: value[0] = (1 - theta) * dTdr_vals[ edge[0] - 1] + theta * dTdr_vals[edge[1] - 1] value[1] = (1 - theta) * dTdz_vals[ edge[0] - 1] + theta * dTdz_vals[edge[1] - 1] break return def value_shape(self): return (2, ) tecplot_nbc = TecplotNeumannBC(degree=5) n = FacetNormal(self.Q.mesh()) self.theta_bcs_n = { submesh_boundary_indices["upper right"]: dot(n, tecplot_nbc), submesh_boundary_indices["crucible"]: dot(n, tecplot_nbc), } self.theta_bcs_r = {} # It seems that the boundary conditions from above are inconsistent in # that solving with Dirichlet overall and mixed Dirichlet-Neumann give # different results; the value *cannot* correspond to one solution. # From looking at the solutions, the pure Dirichlet setting appears # correct, so extract the Neumann values directly from that solution. # Pick fixed coefficients roughly at the temperature that we expect. # This could be made less magic by having the coefficients depend on # theta and solving the quasilinear equation. temp_estimate = 1550.0 # Get material parameters wp_material = self.subdomain_materials[self.wpi] if isinstance(wp_material.specific_heat_capacity, float): cp = wp_material.specific_heat_capacity else: cp = wp_material.specific_heat_capacity(temp_estimate) if isinstance(wp_material.density, float): rho = wp_material.density else: rho = wp_material.density(temp_estimate) if isinstance(wp_material.thermal_conductivity, float): k = wp_material.thermal_conductivity else: k = wp_material.thermal_conductivity(temp_estimate) reference_problem = cyl_heat.Heat( self.Q, convection=None, kappa=k, rho=rho, cp=cp, source=Constant(0.0), dirichlet_bcs=self.theta_bcs_d_strict, ) theta_reference = reference_problem.solve_stationary() theta_reference.rename("theta", "temperature (Dirichlet)") # Create equivalent boundary conditions from theta_ref. This # makes sure that the potentially expensive Expression evaluation in # theta_bcs_* is replaced by something reasonably cheap. self.theta_bcs_d = [ DirichletBC(bc.function_space(), theta_reference, bc.domain_args[0]) for bc in self.theta_bcs_d ] # Adapt Neumann conditions. n = FacetNormal(self.Q.mesh()) self.theta_bcs_n = { k: dot(n, grad(theta_reference)) # k: Constant(1000.0) for k in self.theta_bcs_n } if DEBUG: # Solve the heat equation with the mixed Dirichlet-Neumann # boundary conditions and compare it to the Dirichlet-only # solution. theta_new = Function(self.Q, name="temperature (Neumann + Dirichlet)") from dolfin import Measure ds_workpiece = Measure("ds", subdomain_data=self.wp_boundaries) heat = cyl_heat.Heat( self.Q, convection=None, kappa=k, rho=rho, cp=cp, source=Constant(0.0), dirichlet_bcs=self.theta_bcs_d, neumann_bcs=self.theta_bcs_n, robin_bcs=self.theta_bcs_r, my_ds=ds_workpiece, ) theta_new = heat.solve_stationary() theta_new.rename("theta", "temperature (Neumann + Dirichlet)") from dolfin import plot, interactive, errornorm print("||theta_new - theta_ref|| = {:e}".format( errornorm(theta_new, theta_reference))) plot(theta_reference) plot(theta_new) plot(theta_reference - theta_new, title="theta_ref - theta_new") interactive() self.background_temp = 1400.0 # self.omega = 2 * pi * 10.0e3 self.omega = 2 * pi * 300.0 return
TestFunction, FunctionSpace) import matplotlib.pyplot as plt import subprocess, os import numpy as np ratios = [] exponents = [2, 3, 3.5, 4.0, 4.5, 5.0, 5.5] for hein in exponents[-1:]: subprocess.call( ['gmsh -3 -clscale 0.075 -setnumber Hein %d tile_1_hein.geo' % hein], shell=True) outputs = convert('tile_1_hein.msh', 'tile_1_hein.h5') mesh, surfaces, volumes = outputs dx = Measure('dx', domain=mesh, subdomain_data=volumes) intra = assemble(1 * dx(1)) extra = assemble(1 * dx(0)) ratios.append(extra / (intra + extra)) print('Extracellular volume %.2f' % ratios[-1]) # Now want to get ratio of cell surface area to its volume # Want to keep track of port areas - these are boundary integrals ds = Measure('ds', domain=mesh, subdomain_data=surfaces) dS = Measure('dS', domain=mesh, subdomain_data=surfaces) area_no_port = assemble(1 * dS(1)) area_port = assemble(1 * ds(1)) volume = intra
k = 1 # Directory for output outdir_base = './../../results/MovingMesh/' mesh = RectangleMesh(Point(xmin, ymin), Point(xmax, ymax), nx, ny) n = FacetNormal(mesh) outfile = File(mesh.mpi_comm(), outdir_base+"psi_h.pvd") V = VectorFunctionSpace(mesh, 'DG', 2) Vcg = VectorFunctionSpace(mesh, 'CG', 1) boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1) boundaries.set_all(0) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) # Create function spaces Q_E_Rho = FiniteElement("DG", mesh.ufl_cell(), k) T_1 = FunctionSpace(mesh, 'DG', 0) Qbar_E = FiniteElement("DGT", mesh.ufl_cell(), k) Q_Rho = FunctionSpace(mesh, Q_E_Rho) Qbar = FunctionSpace(mesh, Qbar_E) phih, phih0 = Function(Q_Rho), Function(Q_Rho) phibar = Function(Qbar) # Advective velocity # Swirling deformation advection (see LeVeque) ux = 'pow(sin(pi*x[0]), 2) * sin(2*pi*x[1])'
def create_integration_subdomains(self): self._dx = Measure("dx")(subdomain_data=self._subdomains)
def transport_linear(integrator_type, mesh, subdomains, boundaries, t_start, dt, T, solution0, \ alpha_0, K_0, mu_l_0, lmbda_l_0, Ks_0, \ alpha_1, K_1, mu_l_1, lmbda_l_1, Ks_1, \ alpha, K, mu_l, lmbda_l, Ks, \ cf_0, phi_0, rho_0, mu_0, k_0,\ cf_1, phi_1, rho_1, mu_1, k_1,\ cf, phi, rho, mu, k, \ d_0, d_1, d_t, vel_c, p_con, A_0, Temp, c_extrapolate): # Create mesh and define function space parameters["ghost_mode"] = "shared_facet" # required by dS dx = Measure('dx', domain=mesh, subdomain_data=subdomains) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) dS = Measure('dS', domain=mesh, subdomain_data=boundaries) C_cg = FiniteElement("CG", mesh.ufl_cell(), 1) C_dg = FiniteElement("DG", mesh.ufl_cell(), 0) mini = C_cg + C_dg C = FunctionSpace(mesh, mini) C = BlockFunctionSpace([C]) TM = TensorFunctionSpace(mesh, 'DG', 0) PM = FunctionSpace(mesh, 'DG', 0) n = FacetNormal(mesh) vc = CellVolume(mesh) fc = FacetArea(mesh) h = vc / fc h_avg = (vc('+') + vc('-')) / (2 * avg(fc)) penalty1 = Constant(1.0) tau = Function(PM) tau = tau_cal(tau, phi, -0.5) tuning_para = 0.25 vel_norm = (dot(vel_c, n) + abs(dot(vel_c, n))) / 2.0 cell_size = CellDiameter(mesh) vnorm = sqrt(dot(vel_c, vel_c)) I = Identity(mesh.topology().dim()) d_eff = Function(TM) d_eff = diff_coeff_cal_rev(d_eff, d_0, tau, phi) + tuning_para * cell_size * vnorm * I monitor_dt = dt # Define variational problem dc, = BlockTrialFunction(C) dc_dot, = BlockTrialFunction(C) psic, = BlockTestFunction(C) block_c = BlockFunction(C) c, = block_split(block_c) block_c_dot = BlockFunction(C) c_dot, = block_split(block_c_dot) theta = -1.0 a_time = phi * rho * inner(c_dot, psic) * dx a_dif = dot(rho*d_eff*grad(c),grad(psic))*dx \ - dot(avg_w(rho*d_eff*grad(c),weight_e(rho*d_eff,n)), jump(psic, n))*dS \ + theta*dot(avg_w(rho*d_eff*grad(psic),weight_e(rho*d_eff,n)), jump(c, n))*dS \ + penalty1/h_avg*k_e(rho*d_eff,n)*dot(jump(c, n), jump(psic, n))*dS a_adv = -dot(rho*vel_c*c,grad(psic))*dx \ + dot(jump(psic), rho('+')*vel_norm('+')*c('+') - rho('-')*vel_norm('-')*c('-') )*dS \ + dot(psic, rho*vel_norm*c)*ds(3) R_c = R_c_cal(c_extrapolate, p_con, Temp) c_D1 = Constant(0.5) rhs_c = R_c * A_s_cal(phi, phi_0, A_0) * psic * dx - dot( rho * phi * vel_c, n) * c_D1 * psic * ds(1) r_u = [a_dif + a_adv] j_u = block_derivative(r_u, [c], [dc]) r_u_dot = [a_time] j_u_dot = block_derivative(r_u_dot, [c_dot], [dc_dot]) r = [r_u_dot[0] + r_u[0] - rhs_c] # this part is not applied. exact_solution_expression1 = Expression("1.0", t=0, element=C[0].ufl_element()) def bc(t): p5 = DirichletBC(C.sub(0), exact_solution_expression1, boundaries, 1, method="geometric") return BlockDirichletBC([p5]) # Define problem wrapper class ProblemWrapper(object): def set_time(self, t): pass # Residual and jacobian functions def residual_eval(self, t, solution, solution_dot): return r def jacobian_eval(self, t, solution, solution_dot, solution_dot_coefficient): return [[ Constant(solution_dot_coefficient) * j_u_dot[0, 0] + j_u[0, 0] ]] # Define boundary condition def bc_eval(self, t): pass # Define initial condition def ic_eval(self): return solution0 # Define custom monitor to plot the solution def monitor(self, t, solution, solution_dot): pass problem_wrapper = ProblemWrapper() (solution, solution_dot) = (block_c, block_c_dot) solver = TimeStepping(problem_wrapper, solution, solution_dot) solver.set_parameters({ "initial_time": t_start, "time_step_size": dt, "monitor": { "time_step_size": monitor_dt, }, "final_time": T, "exact_final_time": "stepover", "integrator_type": integrator_type, "problem_type": "linear", "linear_solver": "mumps", "report": True }) export_solution = solver.solve() return export_solution, T