def __init__(self, form, Space, bcs=[], name="x", matvec=[None, None], method="default", solver_type="cg", preconditioner_type="default"): Function.__init__(self, Space, name=name) self.form = form self.method = method self.bcs = bcs self.matvec = matvec self.trial = trial = TrialFunction(Space) self.test = test = TestFunction(Space) Mass = inner(trial, test) * dx() self.bf = inner(form, test) * dx() self.rhs = Vector(self.vector()) if method.lower() == "default": self.A = A_cache[(Mass, tuple(bcs))] self.sol = Solver_cache[(Mass, tuple(bcs), solver_type, preconditioner_type)] elif method.lower() == "lumping": assert Space.ufl_element().degree() < 2 self.A = A_cache[(Mass, tuple(bcs))] ones = Function(Space) ones.vector()[:] = 1. self.ML = self.A * ones.vector() self.ML.set_local(1. / self.ML.array())
def solve(self, dt): self.u = Function(self.V0) self.w = TestFunction(self.V0) self.du = TrialFunction(self.V0) x = SpatialCoordinate(self.mesh0) L = inner( self.S(), self.eps(self.w) )*dx(degree=4)\ - inner( self.b, self.w )*dx(degree=4)\ - inner( self.h, self.w )*ds(degree=4)\ + inner( 1e-6*self.u, self.w )*ds(degree=4)\ - inner( min_value(x[2]+self.ut[2]+self.u[2], 0) * Constant((0,0,-1.0)), self.w )*ds(degree=4) a = derivative(L, self.u, self.du) problem = NonlinearVariationalProblem(L, self.u, bcs=[], J=a) solver = NonlinearVariationalSolver(problem) solver.solve() self.ut.vector()[:] = self.ut.vector()[:] + self.u.vector()[:] ALE.move(self.mesh, Function(self.V, self.u.vector())) self.v.vector()[:] = self.u.vector()[:] / dt self.n = FacetNormal(self.mesh)
def __new__(cls, mesh, tolerance=1e-12): dim = mesh.geometry().dim() X = MeshPool._X[dim - 1] test = assemble(dot(X, X) * CellVolume(mesh)**(0.25) * dx()) * assemble(Constant(1) * dx(domain=mesh)) assert test > 0.0 assert test < np.inf # Do a garbage collect to collect any garbage references # Needed for full parallel compatibility gc.collect() keys = np.array(MeshPool._existing.keys()) self = None if len(keys) > 0: diff = np.abs(keys - test) / np.abs(test) idx = np.argmin(np.abs(keys - test)) if diff[idx] <= tolerance and isinstance( mesh, type(MeshPool._existing[keys[idx]])): self = MeshPool._existing[keys[idx]] if self is None: self = mesh MeshPool._existing[test] = self return self
def __init__(self, p_, Space, i=0, bcs=[], name="grad", method={}): assert len(p_.ufl_shape) == 0 assert i >= 0 and i < Space.mesh().geometry().dim() solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') low_memory_version = method.get('low_memory_version', False) OasisFunction.__init__(self, p_.dx(i), Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) self.i = i Source = p_.function_space() if not low_memory_version: self.matvec = [ A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], p_] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module DG = FunctionSpace(Space.mesh(), 'DG', 0) G = assemble(TrialFunction(DG) * self.test * dx()) dg = Function(DG) dP = assemble(TrialFunction(p_.function_space()).dx(i) * TestFunction(DG) * dx()) self.WGM = compiled_gradient_module.compute_weighted_gradient_matrix( G, dP, dg)
def __init__(self, form, Space, bcs=[], name="x", matvec=[None, None], method="default", solver_type="cg", preconditioner_type="default"): Function.__init__(self, Space, name=name) self.form = form self.method = method self.bcs = bcs self.matvec = matvec self.trial = trial = TrialFunction(Space) self.test = test = TestFunction(Space) Mass = inner(trial, test) * dx() self.bf = inner(form, test) * dx() self.rhs = Vector(self.vector()) if method.lower() == "default": self.A = A_cache[(Mass, tuple(bcs))] self.sol = Solver_cache[(Mass, tuple( bcs), solver_type, preconditioner_type)] elif method.lower() == "lumping": assert Space.ufl_element().degree() < 2 self.A = A_cache[(Mass, tuple(bcs))] ones = Function(Space) ones.vector()[:] = 1. self.ML = self.A * ones.vector() self.ML.set_local(1. / self.ML.array())
def __init__(self, form, Space, bcs=[], name="x", matvec=[None, None], method="default", solver_type="cg", preconditioner_type="default"): Function.__init__(self, Space, name=name) self.form = form self.method = method self.bcs = bcs self.matvec = matvec self.trial = trial = TrialFunction(Space) self.test = test = TestFunction(Space) Mass = inner(trial, test)*dx() self.bf = inner(form, test)*dx() self.rhs = Vector(self.vector()) if method.lower() == "default": self.A = A_cache[(Mass, tuple(bcs))] self.sol = KrylovSolver(solver_type, preconditioner_type) self.sol.parameters["preconditioner"]["structure"] = "same" self.sol.parameters["error_on_nonconvergence"] = False self.sol.parameters["monitor_convergence"] = False self.sol.parameters["report"] = False elif method.lower() == "lumping": assert Space.ufl_element().degree() < 2 self.A = A_cache[(Mass, tuple(bcs))] ones = Function(Space) ones.vector()[:] = 1. self.ML = self.A * ones.vector() self.ML.set_local(1. / self.ML.array())
def __init__(self, form, mesh, bcs=[], name="CG1", method={}, bounded=False): solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') self.bounded = bounded Space = FunctionSpace(mesh, "CG", 1) OasisFunction.__init__(self, form, Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) if solver_method.lower() == "weightedaverage": from fenicstools import compiled_gradient_module DG = FunctionSpace(mesh, 'DG', 0) # Cannot use cache. Matrix will be modified self.A = assemble(TrialFunction(DG) * self.test * dx()) self.dg = dg = Function(DG) compiled_gradient_module.compute_DG0_to_CG_weight_matrix( self.A, dg) self.bf_dg = inner(form, TestFunction(DG)) * dx()
def err_est_fun(mesh_name2, hol_cyl, T_sol1, T_sol2, deg_choice2, hol_cyl2, count_it): ''' Error estimate. ''' #comm1 = MPI.COMM_WORLD #rank1 = comm1.Get_rank() #e1 = sqrt(int_Omega (T - T_ex)**2. dx)/sqrt(int_Omega T**2. dx) #do.assemble yields integration e1 = do.sqrt(do.assemble(pow(T_sol2 - T_sol1, 2.) * do.dx(domain = hol_cyl))) / \ do.sqrt(do.assemble(pow(T_sol1, 2.) * do.dx(domain = hol_cyl))) #sometimes e1 does not work properly (it might be unstable) -> e2 #the degree of piecewise polynomials used to approximate T_th and T... #...will be the degree of T + degree_rise e2 = do.errornorm(T_sol1, T_sol2, norm_type = 'l2', degree_rise = 2, mesh = hol_cyl2) / \ do.sqrt(do.assemble(pow(T_sol1, 2.) * do.dx(domain = hol_cyl))) print 'err: count_t = {}, error_1 = {}, error_2 = {}'.format( count_it, e1, e2) #print 'rank = ', rank1, ', print 'max(T_sol) = ', max(T_sol2.vector().array()) #print 'rank = ', rank1, ', print 'min(T_sol) = ', min(T_sol2.vector().array()), '\n' return e1, e2
def __init__(self, aneurysm, near_vessel, *args, **kwargs): Field.__init__(self, *args, **kwargs) self.aneurysm = aneurysm self.near_vessel = near_vessel self.Vnv = assemble(Constant(1)*dx(near_vessel[1], domain=near_vessel[0].mesh(), subdomain_data=near_vessel[0])) self.Va = assemble(Constant(1)*dx(aneurysm[1], domain=aneurysm[0].mesh(), subdomain_data=aneurysm[0]))
def _setup_energy(self, rho, vel, gvec, x0): """ Calculate kinetic and potential energy """ x = df.SpatialCoordinate(self.mesh) self._form_E_k = Form(1 / 2 * rho * dot(vel, vel) * dx(domain=self.mesh)) self._form_E_p = Form(rho * dot(-gvec, x - x0) * dx(domain=self.mesh))
def __init__(self, aneurysm, near_vessel, *args, **kwargs): Field.__init__(self, *args, **kwargs) self.aneurysm = aneurysm self.near_vessel = near_vessel self.Vnv = assemble( Constant(1) * dx(near_vessel[1], domain=near_vessel[0].mesh(), subdomain_data=near_vessel[0])) self.Va = assemble( Constant(1) * dx(aneurysm[1], domain=aneurysm[0].mesh(), subdomain_data=aneurysm[0]))
def __init__(self, u_, Space, bcs=[], name="div", method={}): solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') low_memory_version = method.get('low_memory_version', False) OasisFunction.__init__(self, div(u_), Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) Source = u_[0].function_space() if not low_memory_version: self.matvec = [[A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], u_[i]] for i in range(Space.mesh().geometry().dim())] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module DG = FunctionSpace(Space.mesh(), 'DG', 0) G = assemble(TrialFunction(DG) * self.test * dx()) dg = Function(DG) self.WGM = [] st = TrialFunction(Source) for i in range(Space.mesh().geometry().dim()): dP = assemble(st.dx(i) * TestFunction(DG) * dx) A = Matrix(G) self.WGM.append(compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, dg))
def divergence_matrix(mesh): CR = VectorFunctionSpace(mesh, 'CR', 1) DG = FunctionSpace(mesh, 'DG', 0) A = cg1_cr_interpolation_matrix(mesh) M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG)) * dx()) C = compiled_cr_module.cr_divergence_matrix(M, A, DG, CR) return C
def dx(self, domain = "all", dx = None): """ Convenience wrapper for integral-cell 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 dx (:class:`dolfin:Measure`) alternative measure *Returns* :class:`dolfin:Measure` the measure # Compute volume of magnetic domain assemble(Constant(1.0) * state.dx('magnetic')) # Compute volume of domain with ID 3 assemble(Constant(1.0) * state.dx(3)) """ # return measure for whole mesh if no domains are defined if not self.mesh_has_domains(): return self._dx domain_ids = self.domain_ids(domain) # XXX fall back to zero measure if len(domain_ids) == 0: domain_ids = (999999,) if dx == None: dx = self._dx return reduce(lambda x,y: x+y, map(lambda i: dx(i), domain_ids))
def __init__( self, mesh, field, strain_tensor="E", dmu=None, approx="original", F_ref=None, isochoric=True, displacement_space="CG_2", interpolation_space="CG_1", description="", ): ModelObservation.__init__(self, mesh, target_space="R_0", description=description) # Check that the given field is a vector of the same dim as the mesh dim = mesh.geometry().dim() # assert isinstance(field, (dolfin.Function, dolfin.Constant) assert field.ufl_shape[0] == dim approxs = ["project", "interpolate", "original"] msg = 'Expected "approx" for be one of {}, got {}'.format( approxs, approx) self.field = field assert approx in approxs, msg self._approx = approx self._F_ref = F_ref if F_ref is not None else dolfin.Identity(dim) self._isochoric = isochoric tensors = ["gradu", "E", "almansi"] msg = "Expected strain tensor to be one of {}, got {}".format( tensors, strain_tensor) assert strain_tensor in tensors, msg self._tensor = strain_tensor if dmu is None: dmu = dolfin.dx(domain=mesh) assert isinstance(dmu, dolfin.Measure) self._dmu = dmu self._vol = dolfin_adjoint.Constant( dolfin.assemble(dolfin.Constant(1.0) * dmu)) # These spaces are only used if you want to project # or interpolate the displacement before assigning it # Space for interpolating the displacement if needed family, degree = interpolation_space.split("_") self._interpolation_space = dolfin.VectorFunctionSpace( mesh, family, int(degree)) # Displacement space family, degree = displacement_space.split("_") self._displacement_space = dolfin.VectorFunctionSpace( mesh, family, int(degree))
def test_to_DG0(self): subdomains = (df.CompiledSubDomain('near(x[0], 0.5)'), df.DomainBoundary()) for subd in subdomains: mesh = df.UnitCubeMesh(4, 4, 4) facet_f = df.MeshFunction('size_t', mesh, 2, 0) subd.mark(facet_f, 1) submesh = EmbeddedMesh(facet_f, 1) transfer = SubMeshTransfer(mesh, submesh) V = df.FunctionSpace(mesh, 'Discontinuous Lagrange Trace', 0) Vsub = df.FunctionSpace(submesh, 'DG', 0) to_Vsub = transfer.compute_map(Vsub, V, strict=False) # Set degree 0 to get the quad order right f = df.Expression('x[0] + 2*x[1] - x[2]', degree=0) fV = df.interpolate(f, V) fsub = df.Function(Vsub) to_Vsub(fsub, fV) error = df.inner(fsub - f, fsub - f)*df.dx(domain=submesh) error = df.sqrt(abs(df.assemble(error))) self.assertTrue(error < 1E-13)
def divergence_matrix(mesh): CR = VectorFunctionSpace(mesh, 'CR', 1) DG = FunctionSpace(mesh, 'DG', 0) A = cg1_cr_interpolation_matrix(mesh) M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG))*dx()) C = compiled_cr_module.cr_divergence_matrix(M, A, DG, CR) return C
def test_mat_without_dictionnary(): """FenicsPart instance initialized with only one instance of Material""" L_x, L_y = 1, 1 mesh = fe.RectangleMesh(fe.Point(0.0, 0.0), fe.Point(L_x, L_y), 10, 10) dimensions = np.array(((L_x, 0.0), (0.0, L_y))) E, nu = 1, 0.3 material = mat.Material(E, nu, "cp") rect_part = part.FenicsPart( mesh, materials=material, subdomains=None, global_dimensions=dimensions, facet_regions=None, ) elem_type = "CG" degree = 2 strain_fspace = fe.FunctionSpace( mesh, fe.VectorElement(elem_type, mesh.ufl_cell(), degree, dim=3), ) strain = fe.project(fe.Expression(("1.0+x[0]*x[0]", "0", "1.0"), degree=2), strain_fspace) stress = mat.sigma(rect_part.elasticity_tensor, strain) energy = fe.assemble(fe.inner(stress, strain) * fe.dx(rect_part.mesh)) energy_theo = E / (1 + nu) * (1 + 28 / (15 * (1 - nu))) assert energy == approx(energy_theo, rel=1e-13)
def verify_function_slice(func_slice, u, cpp_2d, expected_area): u_2D = func_slice.get_slice(u) # The 2D solution we want to obtain analytical = dolfin.Expression(cpp_2d, degree=2 + 3) comm = dolfin.MPI.comm_world if comm.rank == 0: error = dolfin.errornorm(analytical, u_2D) mesh = func_slice.slice_function_space.mesh() area = dolfin.assemble(1 * dolfin.dx(domain=mesh)) if True: import matplotlib matplotlib.use('Agg') from matplotlib import pyplot fig = pyplot.figure() dolfin.plot(u_2D) pyplot.gca().view_init(90, 270) pyplot.gca().set_proj_type('ortho') pyplot.gca().set_xlabel('x') pyplot.gca().set_ylabel('y') fig.savefig('test_func_slice.png') else: error = 0.0 area = 0.0 assert dolfin.MPI.max(comm, error) < 0.015 area = dolfin.MPI.sum(comm, area) assert abs(area - expected_area) < 1e-8
def forward(control, annotate=True): self.reset_problem() annotation.annotate = annotate states = [] functional_values = [] functional = self.create_functional() functionals_time = [] gen = self.iteration(control) for count in gen: # Collect stuff states.append(dolfin.Vector(self.problem.state.vector())) functional_values.append(functional) functionals_time.append(functional) return forward_result( functional=dolfin_adjoint.assemble( list_sum(functionals_time) / self._meshvol * dolfin.dx(domain=self.problem.geometry.mesh)), converged=True, )
def get_residual_form(u, v, rho_e, method='RAMP'): df.dx = df.dx(metadata={"quadrature_degree": 4}) # stiffness = rho_e/(1 + 8. * (1. - rho_e)) if method == 'SIMP': stiffness = rho_e**3 else: #RAMP stiffness = rho_e / (1 + 8. * (1. - rho_e)) # print('the value of stiffness is:', rho_e.vector().get_local()) # Kinematics k = 3e1 E = k * stiffness nu = 0.3 mu, lmbda = (E / (2 * (1 + nu))), (E * nu / ((1 + nu) * (1 - 2 * nu))) d = len(u) I = df.Identity(d) # Identity tensor F = I + df.grad(u) # Deformation gradient C = F.T * F # Right Cauchy-Green tensor E_ = 0.5 * (C - I) # Green--Lagrange strain S = 2.0 * mu * E_ + lmbda * df.tr(E_) * df.Identity( d) # stress tensor (C:eps) psi = 0.5 * df.inner(S, E_) # 0.5*eps:C:eps # Total potential energy Pi = psi * df.dx # Solve weak problem obtained by differentiating Pi: res = df.derivative(Pi, u, v) return res
def test_2_materials(): """FenicsPart instance initialized with only one instance of Material in the materials dictionnary""" L_x, L_y = 1, 1 mesh = fe.RectangleMesh(fe.Point(-L_x, -L_y), fe.Point(L_x, L_y), 20, 20) dimensions = np.array(((2 * L_x, 0.0), (0.0, 2 * L_y))) subdomains = fe.MeshFunction("size_t", mesh, 2) class Right_part(fe.SubDomain): def inside(self, x, on_boundary): return x[0] >= 0 - fe.DOLFIN_EPS subdomain_right = Right_part() subdomains.set_all(0) subdomain_right.mark(subdomains, 1) E_1, E_2, nu = 1, 3, 0.3 materials = {0: mat.Material(1, 0.3, "cp"), 1: mat.Material(3, 0.3, "cp")} rect_part = part.FenicsPart(mesh, materials, subdomains, dimensions) elem_type = "CG" degree = 2 strain_fspace = fe.FunctionSpace( mesh, fe.VectorElement(elem_type, mesh.ufl_cell(), degree, dim=3), ) strain = fe.project(fe.Expression(("1.0+x[0]*x[0]", "0", "1.0"), degree=2), strain_fspace) stress = mat.sigma(rect_part.elasticity_tensor, strain) energy = fe.assemble(fe.inner(stress, strain) * fe.dx(rect_part.mesh)) energy_theo = 2 * ((E_1 + E_2) / (1 + nu) * (1 + 28 / (15 * (1 - nu)))) assert energy == approx(energy_theo, rel=1e-13)
def strain_cross_energy(sig, eps, mesh, area): """ Calcul de l'energie croisée des champs de contrainte sig et de deformation eps. """ # TODO : Redondant. Voir si cela est nécessaire. return fe.assemble(fe.inner(sig, eps) * fe.dx(mesh)) / area
def test_local_assembler_1D(): mesh = UnitIntervalMesh(MPI.comm_world, 20) V = FunctionSpace(mesh, 'CG', 1) u = TrialFunction(V) v = TestFunction(V) c = Cell(mesh, 0) a_scalar = 1.0 * dx(domain=mesh) a_vector = v * dx a_matrix = u * v * dx A_scalar = assemble_local(a_scalar, c) A_vector = assemble_local(a_vector, c) A_matrix = assemble_local(a_matrix, c) assert isinstance(A_scalar, float) assert numpy.isclose(A_scalar, 0.05) assert isinstance(A_vector, numpy.ndarray) assert A_vector.shape == (2,) assert numpy.isclose(A_vector[0], 0.025) assert numpy.isclose(A_vector[1], 0.025) assert isinstance(A_matrix, numpy.ndarray) assert A_matrix.shape == (2, 2) assert numpy.isclose(A_matrix[0, 0], 1 / 60) assert numpy.isclose(A_matrix[0, 1], 1 / 120) assert numpy.isclose(A_matrix[1, 0], 1 / 120) assert numpy.isclose(A_matrix[1, 1], 1 / 60)
def __init__(self, V, parameters=None): # Set parameters self.parameters = self.default_parameters() if parameters is not None: self.parameters.update(parameters) # Set-up mass matrix for L^2 projection self.V = V self.u = df.TrialFunction(self.V) self.v = df.TestFunction(self.V) self.m = df.inner(self.u, self.v) * df.dx() self.M = df.assemble(self.m) self.b = df.Vector(V.mesh().mpi_comm(), V.dim()) solver_type = self.parameters["linear_solver_type"] assert(solver_type == "lu" or solver_type == "cg"), \ "Expecting 'linear_solver_type' to be 'lu' or 'cg'" if solver_type == "lu": df.debug("Setting up direct solver for projecter") # Customize LU solver (reuse everything) solver = df.LUSolver(self.M) solver.parameters["same_nonzero_pattern"] = True solver.parameters["reuse_factorization"] = True else: df.debug("Setting up iterative solver for projecter") # Customize Krylov solver (reuse everything) solver = df.KrylovSolver("cg", "ilu") solver.set_operator(self.M) solver.parameters["preconditioner"]["structure"] = "same" # solver.parameters["nonzero_initial_guess"] = True self.solver = solver
def test_to_DG0_subdomain(self): mesh = df.UnitSquareMesh(4, 4) cell_f = df.MeshFunction('size_t', mesh, 2, 0) df.CompiledSubDomain('x[0] < 0.5 + DOLFIN_EPS').mark(cell_f, 1) submesh = EmbeddedMesh(cell_f, 1) transfer = SubMeshTransfer(mesh, submesh) V = df.FunctionSpace(mesh, 'DG', 0) Vsub = df.FunctionSpace(submesh, 'DG', 0) to_Vsub = transfer.compute_map(Vsub, V, strict=True) # Set degree 0 to get the quad order right f = df.Expression('x[0] + 2*x[1]', degree=0) fV = df.interpolate(f, V) fsub = df.Function(Vsub) to_Vsub(fsub, fV) error = df.inner(fsub - f, fsub - f)*df.dx(domain=submesh) error = df.sqrt(abs(df.assemble(error))) self.assertTrue(error < 1E-13)
def create(self): self.metadata = { "quadrature_degree": self.deg_q, "quadrature_scheme": "default", } self.dxm = df.dx(metadata=self.metadata, subdomain_data=self.mesh_function) # solution field Ed = df.VectorElement("CG", self.mesh.ufl_cell(), degree=self.deg_d) Ee = df.FiniteElement("CG", self.mesh.ufl_cell(), degree=self.deg_d) self.V = df.FunctionSpace(self.mesh, Ed * Ee) self.Vd, self.Ve = self.V.split() self.dd, self.de = df.TrialFunctions(self.V) self.d_, self.e_ = df.TestFunctions(self.V) self.u = df.Function(self.V, name="d-e mixed space") self.d, self.e = df.split(self.u) # generic quadrature function spaces VQF, VQV, VQT = c.helper.spaces(self.mesh, self.deg_q, c.q_dim(self.constraint)) # quadrature functions Q = c.Q # inputs to the model self.q_in = OrderedDict() self.q_in[Q.EPS] = df.Function(VQV, name="current strains") self.q_in[Q.E] = df.Function( VQF, name="current nonlocal equivalent strains") self.q_in_calc = {} self.q_in_calc[Q.EPS] = c.helper.LocalProjector( self.eps(self.d), VQV, self.dxm) self.q_in_calc[Q.E] = c.helper.LocalProjector(self.e, VQF, self.dxm) # outputs of the model self.q = {} self.q[Q.SIGMA] = df.Function(VQV, name="current stresses") self.q[Q.DSIGMA_DEPS] = df.Function(VQT, name="stress-strain tangent") self.q[Q.DSIGMA_DE] = df.Function( VQV, name="stress-nonlocal-strain tangent") self.q[Q.EEQ] = df.Function(VQF, name="current (local) equivalent strain") self.q[Q.DEEQ] = df.Function(VQV, name="equivalent-strain-strain tangent") self.q_history = { Q.KAPPA: df.Function(VQF, name="current history variable kappa") } self.n = len(self.q[Q.SIGMA].vector().get_local()) // c.q_dim( self.constraint) self.nq = self.n // self.mesh.num_cells() self.ip_flags = None if self.mesh_function is not None: self.ip_flags = np.repeat(self.mesh_function.array(), self.nq)
def pressure_correction(self): """ Solve the pressure correction equation We handle the case where only Neumann conditions are given for the pressure by taking out the nullspace, a constant shift of the pressure, by providing the nullspace to the solver """ p = self.simulation.data['p'] p_hat = self.simulation.data['p_hat'] # Temporarily store the old pressure p_hat.vector().zero() p_hat.vector().axpy(-1, p.vector()) # Assemble the A matrix only the first inner iteration if self.inner_iteration == 1: self.Ap = dolfin.as_backend_type(self.eq_pressure.assemble_lhs()) A = self.Ap b = dolfin.as_backend_type(self.eq_pressure.assemble_rhs()) # Inform PETSc about the null space if self.remove_null_space: if self.pressure_null_space is None: # Create vector that spans the null space null_vec = dolfin.Vector(p.vector()) null_vec[:] = 1 null_vec *= 1 / null_vec.norm("l2") # Create null space basis object self.pressure_null_space = dolfin.VectorSpaceBasis([null_vec]) # Make sure the null space is set on the matrix if self.inner_iteration == 1: A.set_nullspace(self.pressure_null_space) # Orthogonalize b with respect to the null space self.pressure_null_space.orthogonalize(b) # Solve for the new pressure correction self.niters_p = self.pressure_solver.inner_solve( A, p.vector(), b, in_iter=self.inner_iteration, co_iter=self.co_inner_iter) # Removing the null space of the matrix system is not strictly the same as removing # the null space of the equation, so we correct for this here if self.remove_null_space: dx2 = dolfin.dx(domain=p.function_space().mesh()) vol = dolfin.assemble(dolfin.Constant(1) * dx2) pavg = dolfin.assemble(p * dx2) / vol p.vector()[:] -= pavg # Calculate p_hat = p_new - p_old p_hat.vector().axpy(1, p.vector()) return p_hat.vector().norm('l2')
def main(): fsr = FunctionSubspaceRegistry() deg = 2 mesh = dolfin.UnitSquareMesh(100, 3) muc = mesh.ufl_cell() el_w = dolfin.FiniteElement('DG', muc, deg - 1) el_j = dolfin.FiniteElement('BDM', muc, deg) el_DG0 = dolfin.FiniteElement('DG', muc, 0) el = dolfin.MixedElement([el_w, el_j]) space = dolfin.FunctionSpace(mesh, el) DG0 = dolfin.FunctionSpace(mesh, el_DG0) fsr.register(space) facet_normal = dolfin.FacetNormal(mesh) xyz = dolfin.SpatialCoordinate(mesh) trial = dolfin.Function(space) test = dolfin.TestFunction(space) w, c = dolfin.split(trial) v, phi = dolfin.split(test) sympy_exprs = derive_exprs() exprs = { k: sympy_dolfin_printer.to_ufl(sympy_exprs['R'], mesh, v) for k, v in sympy_exprs['quantities'].items() } f = exprs['f'] w0 = dolfin.project(dolfin.conditional(dolfin.gt(xyz[0], 0.5), 1.0, 0.3), DG0) w_BC = exprs['w'] dx = dolfin.dx() form = (+v * dolfin.div(c) * dx - v * f * dx + dolfin.exp(w + w0) * dolfin.dot(phi, c) * dx + dolfin.div(phi) * w * dx - (w_BC - w0) * dolfin.dot(phi, facet_normal) * dolfin.ds() - (w0('-') - w0('+')) * dolfin.dot(phi('+'), facet_normal('+')) * dolfin.dS()) solver = NewtonSolver(form, trial, [], parameters=dict(relaxation_parameter=1.0, maximum_iterations=15, extra_iterations=10, relative_tolerance=1e-6, absolute_tolerance=1e-7)) solver.solve() with closing(XdmfPlot("out/qflop_test.xdmf", fsr)) as X: CG1 = dolfin.FunctionSpace(mesh, dolfin.FiniteElement('CG', muc, 1)) X.add('w0', 1, w0, CG1) X.add('w_c', 1, w + w0, CG1) X.add('w_e', 1, exprs['w'], CG1) X.add('f', 1, f, CG1) X.add('cx_c', 1, c[0], CG1) X.add('cx_e', 1, exprs['c'][0], CG1)
def matvec(self, b): '''Action on vector from V1''' V, Q = self.V1, self.V0 gamma_mesh = V.mesh() auxiliary_facet_f = self.facet_f aux_mesh = auxiliary_facet_f.mesh() # The problem for uh V2 = df.FunctionSpace(aux_mesh, Q.ufl_element().family(), Q.ufl_element().degree()) u, v = df.TrialFunction(V2), df.TestFunction(V2) # Wrap the vector as function ... f = df.Function(V, b) # ... to be used in the weak form for the Laplacian a = df.inner(df.grad(u), df.grad(v))*df.dx + df.inner(u, v)*df.dx L = df.inner(f, Trace(v, gamma_mesh))*df.dx(domain=gamma_mesh) A, b = list(map(xii.assembler.xii_assembly.assemble, (a, L))) # We have boundary conditions to apply # bc = df.DirichletBC(V2, df.Constant(0), auxiliary_facet_f, 1) # A, b = apply_bc(A, b, bc) uh = df.Function(V2) df.solve(A, uh.vector(), b) # Now take trace of that ext_mesh = Q.mesh() # Get the trace at extended domain by projection p, q = df.TrialFunction(Q), df.TestFunction(Q) f = Trace(uh, ext_mesh) a = df.inner(p, q)*df.dx L = df.inner(f, q)*df.dx(domain=ext_mesh) A, b = list(map(xii.assembler.xii_assembly.assemble, (a, L))) # We have boundary conditions to apply # FIXME: inherit from uh? # bc = df.DirichletBC(Q, uh, 'on_boundary') # A, b = apply_bc(A, b, bc) qh = df.Function(Q) df.solve(A, qh.vector(), b) return qh.vector()
def compute(self, get): u = get("Velocity") assemble(dot(u[1].dx(0) - u[0].dx(1), self.q) * dx(), tensor=self.L) self.bc.apply(self.L) self.solver.solve(self.psi.vector(), self.L) #solve(self.A, self.psi.vector(), self.L) return self.psi
def test_nasty_jit_caching_bug(): # This may result in something like "matrices are not aligned" # from FIAT if the JIT caching does not recognize that the two # forms are different default_parameters = parameters["form_compiler"]["representation"] for representation in ["quadrature"]: parameters["form_compiler"]["representation"] = representation M1 = assemble(Constant(1.0)*dx(UnitSquareMesh(4, 4))) M2 = assemble(Constant(1.0)*dx(UnitCubeMesh(4, 4, 4))) assert round(M1 - 1.0, 7) == 0 assert round(M2 - 1.0, 7) == 0 parameters["form_compiler"]["representation"] = default_parameters
def __init__(self, valuename, nu, subdomain,*args, **kwargs): Field.__init__(self, *args, **kwargs) self.valuename = valuename mf = subdomain[0] idx = subdomain[1] self.dx = dx(idx, domain=mf.mesh(), subdomain_data=mf) self.vol = assemble(Constant(1)*self.dx) self.nu = nu
def set_cell_domains(self, cell_domains, cell_mark_value): """Set cell domain mesh function Needed if the functional is to be calculated over only part of the domain """ self.cell_domains = cell_domains self.cell_mark_value = cell_mark_value self.dx = dx(self.cell_mark_value) self.dirty = True
def __call__(self, u=None, assemb_rhs=True): if isinstance(u, Coefficient): self.matvec[1] = u self.bf = u.dx(self.i)*self.test*dx() if self.method.lower() == "gradient_matrix": self.vector()[:] = self.WGM * self.matvec[1].vector() else: OasisFunction.__call__(self, assemb_rhs=assemb_rhs)
def make_mass_matrix_quadrature_lumping(function_space_V): V = function_space_V u_trial = dl.TrialFunction(V) v_test = dl.TestFunction(V) # mass lumping scheme code by Jeremy Bleyer # See: https://comet-fenics.readthedocs.io/en/latest/demo/tips_and_tricks/mass_lumping.html mass_form = u_trial * v_test * dl.dx(scheme="lumped", degree=2) ML = dl.assemble(mass_form) return ML
def test_nasty_jit_caching_bug(): # This may result in something like "matrices are not aligned" # from FIAT if the JIT caching does not recognize that the two # forms are different default_parameters = parameters["form_compiler"]["representation"] for representation in ["quadrature"]: parameters["form_compiler"]["representation"] = representation M1 = assemble(Constant(1.0) * dx(UnitSquareMesh(4, 4))) M2 = assemble(Constant(1.0) * dx(UnitCubeMesh(4, 4, 4))) assert round(M1 - 1.0, 7) == 0 assert round(M2 - 1.0, 7) == 0 parameters["form_compiler"]["representation"] = default_parameters
def __init__(self, valuename, nu, subdomain, *args, **kwargs): Field.__init__(self, *args, **kwargs) self.valuename = valuename mf = subdomain[0] idx = subdomain[1] self.dx = dx(idx, domain=mf.mesh(), subdomain_data=mf) self.vol = assemble(Constant(1) * self.dx) self.nu = nu
def compute(self, get): u = get("Velocity") assemble(dot(u[1].dx(0)-u[0].dx(1), self.q)*dx(), tensor=self.L) self.bc.apply(self.L) self.solver.solve(self.psi.vector(), self.L) #solve(self.A, self.psi.vector(), self.L) return self.psi
def divergence_matrix(mesh): CR = VectorFunctionSpace(mesh, 'CR', 1) DG = FunctionSpace(mesh, 'DG', 0) A = cg1_cr_interpolation_matrix(mesh) M = assemble(dot(div(TrialFunction(CR)), TestFunction(DG))*dx()) compiled_cr_module.cr_divergence_matrix(M, A, DG, CR) M_mat = as_backend_type(M).mat() M_mat.matMult(A.mat()) return M
def __init__(self, form, mesh, bcs=[], name="CG1", method={}, bounded=False): solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') self.bounded = bounded Space = FunctionSpace(mesh, "CG", 1) OasisFunction.__init__(self, form, Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) if solver_method.lower() == "weightedaverage": from fenicstools import compiled_gradient_module DG = FunctionSpace(mesh, 'DG', 0) self.A = assemble(TrialFunction(DG)*self.test*dx()) # Cannot use cache. Matrix will be modified self.dg = dg = Function(DG) compiled_gradient_module.compute_DG0_to_CG_weight_matrix(self.A, dg) self.bf_dg = inner(form, TestFunction(DG))*dx()
def compute(self, get): t1 = get("t") t0 = get("t", -1) dt = Constant(t1 - t0) u = get("Velocity") hF = self._hF hK = self._hK scaling = 1.0 / hK assemble((dt * sqrt(u**2) / hF)*self._v*scaling*dx(), tensor=self._cfl.vector()) return self._cfl
def _print_diagnostics( theta0, umax, submesh_workpiece, wpi_area, subdomain_materials, wpi, rho, mu, char_length, grav, ): av_temperature = assemble(theta0 * dx(submesh_workpiece)) / wpi_area vec = theta0.vector() temperature_difference = vec.max() - vec.min() info("Max temperature: {:e}".format(vec.max())) info("Min temperature: {:e}".format(vec.min())) info("Av temperature: {:e}".format(av_temperature)) info("") info("Max velocity: {:e}".format(umax)) info("") char_velocity = umax melt_material = subdomain_materials[wpi] rho_const = rho(av_temperature) cp = melt_material.specific_heat_capacity if not isinstance(cp, float): cp = cp(av_temperature) k = melt_material.thermal_conductivity if not isinstance(k, float): k = k(av_temperature) mu_const = mu(av_temperature) # info("Prandtl number: {:e}".format(_get_prandtl(mu_const, rho_const, cp, k))) info( "Reynolds number: {:e}".format( _get_reynolds(rho_const, mu_const, char_length, char_velocity) ) ) info( "Grashof number: {:e}".format( _get_grashof( rho, mu_const, grav, av_temperature, char_length, temperature_difference ) ) ) return
def before_first_compute(self, get): u = get("Velocity") assert len(u) == 2, "Can only compute stream function for 2D problems" V = u.function_space() spaces = SpacePool(V.mesh()) degree = V.ufl_element().degree() V = spaces.get_space(degree, 0) psi = TrialFunction(V) self.q = TestFunction(V) a = dot(grad(psi), grad(self.q))*dx() self.bc = DirichletBC(V, Constant(0), DomainBoundary()) self.A = assemble(a) self.L = Vector() self.bc.apply(self.A) self.solver = KrylovSolver(self.A, "cg") self.psi = Function(V)
def add_fields(self): Field.start_recording() params = self.params.copy_recursive() if not self.params.debug: params["save"] = False params["plot"] = False params.pop("debug") params.pop("use_timeaverage") params.pop("finalize") T0, T1 = self.params.start_time, self.params.end_time assert T0 != Field.default_params().start_time assert T1 != Field.default_params().end_time tau = Magnitude("WSS") if self.params.use_timeaverage: tau = TimeAverage(tau, params=params) threshold = DomainAvg(tau, cell_domains=self.near_vessel[0], indicator=self.near_vessel[1], label="nv") + \ DomainSD(tau, cell_domains=self.aneurysm[0], indicator=self.aneurysm[1], label="aneurysm") threshold.name = "threshold_sci_nv" mask = Threshold(tau, threshold, dict(threshold_by="above")) mf = self.aneurysm[0] idx = self.aneurysm[1] Aa = ConstantField(assemble(Constant(1)*dx(idx, domain=mf.mesh(), subdomain_data=mf))) Aa.name = "AneurysmArea" Fh = Aa*DomainAvg(tau*mask, cell_domains=mf, indicator=idx, params=params) Fh.name = "HighShear" Ah = Aa*DomainAvg(mask, cell_domains=mf, indicator=idx, params=params)+ConstantField(1e-12) Ah.name = "HighShearArea" Fa = Aa*DomainAvg(tau, cell_domains=mf, indicator=idx, params=params) Fa.name = "TotalShear" f = (Fh/Fa)/(Ah/Aa) if not self.params.use_timeaverage: f = TimeAverage(f, params=params) self.valuename = f.name fields = Field.stop_recording() return fields
def assemble_rhs(self, u=None): """ Assemble right hand side trial.dx(i)*test*dx. Possible Coefficient u may replace p_ and makes it possible to use this Function to compute both grad(p) and grad(dp), i.e., the gradient of pressure correction. """ if isinstance(u, Coefficient): self.matvec[1] = u self.bf = u.dx(self.i) * self.test * dx() if not self.matvec[0] is None: mat, func = self.matvec self.rhs.zero() self.rhs.axpy(1.0, mat * func.vector()) else: assemble(self.bf, tensor=self.rhs)
def sobolev_norm(u, p, k=1, domain=None): """Return Sobolev seminorm on W^{k, p} of function u. If u is None, return infinity.""" # Special case if u is None: return np.infty # Prepare exponent and measure p = Constant(p) if p is not 2 else p dX = dx(domain) # Take derivative if k==1 if k == 1: u = grad(u) elif k == 0: u = u else: raise NotImplementedError # Assemble functional and return return assemble(inner(u, u)**(p/2)*dX)**(1.0/float(p))
# Right hand side and boundary value for velocity f = Expression(('sin(pi*x[1])', 'cos(pi*(x[0]+x[1]))')) g = Constant((0, 0)) N = 20 gamma_d = 'everywhere' Ad, ud, pd, eigs_d = dolfin_system(f=f, g=g, N=N, gamma_d=gamma_d) Ac, uc, pc, eigs_c = cbc_block_system(f=f, g=g, N=N, gamma_d=gamma_d) plt.figure() plt.suptitle('DOLFIN') plt.spy(Ad, marker='.') plt.figure() plt.suptitle('CBC.BLOCK') plt.spy(Ac, marker='.') plt.show() mesh = UnitSquareMesh(20, 20) print 'Velocity diff', assemble(inner(ud-uc, ud-uc)*dx(domain=mesh)) print 'Pressure diff', assemble(inner(pd-pc, pd-pc)*dx(domain=mesh)) print 'DOLFIN eigs', eigs_d print 'CBC.BLOCK eigs', eigs_c print 'Norm of diff', (eigs_d - eigs_c).dot(eigs_d - eigs_c) # All okay # Setting sigma for eigensolver to detect zero! # Sign of a21 to get eigenvalue agreement with DOLFIN
def _evaluateLocalEstimator(cls, mu, w, coeff_field, pde, f, quadrature_degree, epsilon=1e-5): """Evaluation of patch local equilibrated estimator.""" # prepare numerical flux and f sigma_mu, f_mu = evaluate_numerical_flux(w, mu, coeff_field, f) # ################### # ## MIXED PROBLEM ## # ################### # get setup data for mixed problem V = w[mu]._fefunc.function_space() mesh = V.mesh() mesh.init() degree = element_degree(w[mu]._fefunc) # data for nodal bases V_dm = V.dofmap() V_dofs = dict([(i, V_dm.cell_dofs(i)) for i in range(mesh.num_cells())]) V1 = FunctionSpace(mesh, 'CG', 1) # V1 is to define nodal base functions phi_z = Function(V1) phi_coeffs = np.ndarray(V1.dim()) vertex_dof_map = V1.dofmap().vertex_to_dof_map(mesh) # vertex_dof_map = vertex_to_dof_map(V1) dof_list = vertex_dof_map.tolist() # DG0 localisation DG0 = FunctionSpace(mesh, 'DG', 0) DG0_dofs = dict([(c.index(),DG0.dofmap().cell_dofs(c.index())[0]) for c in cells(mesh)]) dg0 = TestFunction(DG0) # characteristic function of patch xi_z = Function(DG0) xi_coeffs = np.ndarray(DG0.dim()) # mesh data h = CellSize(mesh) n = FacetNormal(mesh) cf = CellFunction('size_t', mesh) # setup error estimator vector eq_est = np.zeros(DG0.dim()) # setup global equilibrated flux vector DG = VectorFunctionSpace(mesh, "DG", degree) DG_dofmap = DG.dofmap() # define form functions tau = TrialFunction(DG) v = TestFunction(DG) # define global tau tau_global = Function(DG) tau_global.vector()[:] = 0.0 # iterate vertices for vertex in vertices(mesh): # get patch cell indices vid = vertex.index() patch_cid, FF_inner, FF_boundary = get_vertex_patch(vid, mesh, layers=1) # set nodal base function phi_coeffs[:] = 0 phi_coeffs[dof_list.index(vid)] = 1 phi_z.vector()[:] = phi_coeffs # set characteristic function and mark patch cf.set_all(0) xi_coeffs[:] = 0 for cid in patch_cid: xi_coeffs[DG0_dofs[int(cid)]] = 1 cf[int(cid)] = 1 xi_z.vector()[:] = xi_coeffs # determine local dofs lDG_cell_dofs = dict([(cid, DG_dofmap.cell_dofs(cid)) for cid in patch_cid]) lDG_dofs = [cd.tolist() for cd in lDG_cell_dofs.values()] lDG_dofs = list(iter.chain(*lDG_dofs)) # print "\nlocal DG subspace has dimension", len(lDG_dofs), "degree", degree, "cells", len(patch_cid), patch_cid # print "local DG_cell_dofs", lDG_cell_dofs # print "local DG_dofs", lDG_dofs # create patch measures dx = Measure('dx')[cf] dS = Measure('dS')[FF_inner] # define forms alpha = Constant(1 / epsilon) / h a = inner(tau,v) * phi_z * dx(1) + alpha * div(tau) * div(v) * dx(1) + avg(alpha) * jump(tau,n) * jump(v,n) * dS(1)\ + avg(alpha) * jump(xi_z * tau,n) * jump(v,n) * dS(2) L = -alpha * (div(sigma_mu) + f) * div(v) * phi_z * dx(1)\ - avg(alpha) * jump(sigma_mu,n) * jump(v,n) * avg(phi_z)*dS(1) # print "L2 f + div(sigma)", assemble((f + div(sigma)) * (f + div(sigma)) * dx(0)) # assemble forms lhs = assemble(a, form_compiler_parameters={'quadrature_degree': quadrature_degree}) rhs = assemble(L, form_compiler_parameters={'quadrature_degree': quadrature_degree}) # convert DOLFIN representation to scipy sparse arrays rows, cols, values = lhs.data() lhsA = sps.csr_matrix((values, cols, rows)).tocoo() # slice sparse matrix and solve linear problem lhsA = coo_submatrix_pull(lhsA, lDG_dofs, lDG_dofs) lx = spsolve(lhsA, rhs.array()[lDG_dofs]) # print ">>> local solution lx", type(lx), lx local_tau = Function(DG) local_tau.vector()[lDG_dofs] = lx # print "div(tau)", assemble(inner(div(local_tau),div(local_tau))*dx(1)) # add up local fluxes tau_global.vector()[lDG_dofs] += lx # evaluate estimator # maybe TODO: re-define measure dx eq_est = assemble( inner(tau_global, tau_global) * dg0 * (dx(0)+dx(1)),\ form_compiler_parameters={'quadrature_degree': quadrature_degree}) # reorder according to cell ids eq_est = eq_est[DG0_dofs.values()].array() global_est = np.sqrt(np.sum(eq_est)) # eq_est_global = assemble( inner(tau_global, tau_global) * (dx(0)+dx(1)), form_compiler_parameters={'quadrature_degree': quadrature_degree} ) # global_est2 = np.sqrt(np.sum(eq_est_global)) return global_est, FlatVector(np.sqrt(eq_est))#, tau_global
def __init__(self, Vh, covariance, mean=None): """ Constructor Inputs: - :code:`Vh`: Finite element space on which the prior is defined. Must be the Real space with one global degree of freedom - :code:`covariance`: The covariance of the prior. Must be a :code:`numpy.ndarray` of appropriate size - :code:`mean`(optional): Mean of the prior distribution. Must be of type `dolfin.Vector()` """ self.Vh = Vh if Vh.dim() != covariance.shape[0] or Vh.dim() != covariance.shape[1]: raise ValueError("Covariance incompatible with Finite Element space") if not np.issubdtype(covariance.dtype, np.floating): raise TypeError("Covariance matrix must be a float array") self.covariance = covariance #np.linalg.cholesky automatically provides more error checking, #so use those self.chol = np.linalg.cholesky(self.covariance) self.chol_inv = scila.solve_triangular( self.chol, np.identity(Vh.dim()), lower=True) self.precision = np.dot(self.chol_inv.T, self.chol_inv) trial = dl.TrialFunction(Vh) test = dl.TestFunction(Vh) domain_measure_inv = dl.Constant(1.0 \ / dl.assemble(dl.Constant(1.) * dl.dx(Vh.mesh()))) #Identity mass matrix self.M = dl.assemble(domain_measure_inv * dl.inner(trial, test) * dl.dx) self.Msolver = Operator2Solver(self.M) if mean: self.mean = mean else: tmp = dl.Vector() self.M.init_vector(tmp, 0) tmp.zero() self.mean = tmp if Vh.dim() == 1: trial = dl.as_matrix([[trial]]) test = dl.as_matrix([[test]]) #Create form matrices covariance_op = dl.as_matrix(list(map(list, self.covariance))) precision_op = dl.as_matrix(list(map(list, self.precision))) chol_op = dl.as_matrix(list(map(list, self.chol))) chol_inv_op = dl.as_matrix(list(map(list, self.chol_inv))) #variational for the regularization operator, or the precision matrix var_form_R = domain_measure_inv \ * dl.inner(test, dl.dot(precision_op, trial)) * dl.dx #variational for the inverse regularization operator, or the covariance #matrix var_form_Rinv = domain_measure_inv \ * dl.inner(test, dl.dot(covariance_op, trial)) * dl.dx #variational form for the square root of the regularization operator var_form_R_sqrt = domain_measure_inv \ * dl.inner(test, dl.dot(chol_inv_op.T, trial)) * dl.dx #variational form for the square root of the inverse regularization #operator var_form_Rinv_sqrt = domain_measure_inv \ * dl.inner(test, dl.dot(chol_op, trial)) * dl.dx self.R = dl.assemble(var_form_R) self.RSolverOp = dl.assemble(var_form_Rinv) self.Rsolver = Operator2Solver(self.RSolverOp) self.sqrtR = dl.assemble(var_form_R_sqrt) self.sqrtRinv = dl.assemble(var_form_Rinv_sqrt)
def compute_time_errors(problem, MethodClass, mesh_sizes, Dt): mesh_generator, solution, f, mu, rho, cell_type = problem() # Translate data into FEniCS expressions. sol_u = Expression((smp.printing.ccode(solution['u']['value'][0]), smp.printing.ccode(solution['u']['value'][1]) ), degree=_truncate_degree(solution['u']['degree']), t=0.0, cell=cell_type ) sol_p = Expression(smp.printing.ccode(solution['p']['value']), degree=_truncate_degree(solution['p']['degree']), t=0.0, cell=cell_type ) fenics_rhs0 = Expression((smp.printing.ccode(f['value'][0]), smp.printing.ccode(f['value'][1]) ), degree=_truncate_degree(f['degree']), t=0.0, mu=mu, rho=rho, cell=cell_type ) # Deep-copy expression to be able to provide f0, f1 for the Dirichlet- # boundary conditions later on. fenics_rhs1 = Expression(fenics_rhs0.cppcode, degree=_truncate_degree(f['degree']), t=0.0, mu=mu, rho=rho, cell=cell_type ) # Create initial states. p0 = Expression( sol_p.cppcode, degree=_truncate_degree(solution['p']['degree']), t=0.0, cell=cell_type ) # Compute the problem errors = {'u': numpy.empty((len(mesh_sizes), len(Dt))), 'p': numpy.empty((len(mesh_sizes), len(Dt))) } for k, mesh_size in enumerate(mesh_sizes): info('') info('') with Message('Computing for mesh size %r...' % mesh_size): mesh = mesh_generator(mesh_size) mesh_area = assemble(1.0 * dx(mesh)) W = VectorFunctionSpace(mesh, 'CG', 2) P = FunctionSpace(mesh, 'CG', 1) method = MethodClass(W, P, rho, mu, theta=1.0, #theta=0.5, stabilization=None #stabilization='SUPG' ) u1 = Function(W) p1 = Function(P) err_p = Function(P) divu1 = Function(P) for j, dt in enumerate(Dt): # Prepare previous states for multistepping. u = [Expression( sol_u.cppcode, degree=_truncate_degree(solution['u']['degree']), t=0.0, cell=cell_type ), # Expression( #sol_u.cppcode, #degree=_truncate_degree(solution['u']['degree']), #t=0.5*dt, #cell=cell_type #) ] sol_u.t = dt u_bcs = [DirichletBC(W, sol_u, 'on_boundary')] sol_p.t = dt #p_bcs = [DirichletBC(P, sol_p, 'on_boundary')] p_bcs = [] fenics_rhs0.t = 0.0 fenics_rhs1.t = dt method.step(dt, u1, p1, u, p0, u_bcs=u_bcs, p_bcs=p_bcs, f0=fenics_rhs0, f1=fenics_rhs1, verbose=False, tol=1.0e-10 ) sol_u.t = dt sol_p.t = dt errors['u'][k][j] = errornorm(sol_u, u1) # The pressure is only determined up to a constant which makes # it a bit harder to define what the error is. For our # purposes, choose an alpha_0\in\R such that # # alpha0 = argmin ||e - alpha||^2 # # with e := sol_p - p. # This alpha0 is unique and explicitly given by # # alpha0 = 1/(2|Omega|) \int (e + e*) # = 1/|Omega| \int Re(e), # # i.e., the mean error in \Omega. alpha = assemble(sol_p * dx(mesh)) \ - assemble(p1 * dx(mesh)) alpha /= mesh_area # We would like to perform # p1 += alpha. # To avoid creating a temporary function every time, assume # that p1 lives in a function space where the coefficients # represent actual function values. This is true for CG # elements, for example. In that case, we can just add any # number to the vector of p1. p1.vector()[:] += alpha errors['p'][k][j] = errornorm(sol_p, p1) show_plots = False if show_plots: plot(p1, title='p1', mesh=mesh) plot(sol_p, title='sol_p', mesh=mesh) err_p.vector()[:] = p1.vector() sol_interp = interpolate(sol_p, P) err_p.vector()[:] -= sol_interp.vector() #plot(sol_p - p1, title='p1 - sol_p', mesh=mesh) plot(err_p, title='p1 - sol_p', mesh=mesh) #r = Expression('x[0]', degree=1, cell=triangle) #divu1 = 1 / r * (r * u1[0]).dx(0) + u1[1].dx(1) divu1.assign(project(u1[0].dx(0) + u1[1].dx(1), P)) plot(divu1, title='div(u1)') interactive() return errors
def average(u): """Computes the average value of a function u over its domain. """ return assemble(u * dx) / assemble(1.0 * dx(u.function_space().mesh()))
def add_fields(self): Field.start_recording() params = self.params.copy_recursive() if not self.params.debug: params["save"] = False params["plot"] = False params.pop("debug") params.pop("use_timeaverage") params.pop("finalize") T0, T1 = self.params.start_time, self.params.end_time assert T0 != Field.default_params().start_time assert T1 != Field.default_params().end_time if self.params.use_timeaverage: u = TimeAverage("Velocity", params=params) velocity = u.name else: velocity = "Velocity" uneck = SubFunction(velocity, self.neck, params=params, label="neck") A = assemble(Constant(1)*dx(domain=self.neck)) Qin = Dot(ConstantField(self.necknormal), uneck, params=params) t = Threshold(Qin, ConstantField(0), dict(threshold_by="above")) t.params.update(params) t.name = "threshold_neck" Ain = A*DomainAvg(t) Ain.name = "Ain" Ain.params.update(params) Qin = A*DomainAvg(Dot(Qin,t, params=params)) Qin.name = "Qin" Qin.params.update(params) Qpa = 0 for i, (plane, n) in enumerate(self.pa_planes): upa = SubFunction(velocity, plane, params=params, label="pa_%d" %i) Ai = assemble(Constant(1)*dx(domain=plane)) Q = Ai*DomainAvg(Dot(ConstantField(n), upa, params=params)) Q.name = "Qpa%d" %i Q.params.update(params) Qpa += Magnitude(Q) Qpa.params.update(params) Qpa.name = "Sum_Qpa" f = (Qin/Qpa)/(Ain/A) if not self.params.use_timeaverage: f = TimeAverage(f.name, params=params) self.valuename = f.name self.Qin = Qin.name self.Qpa = Qpa.name self.Ain = Ain.name self.A = A fields = Field.stop_recording() return fields
def _average(u): '''Computes the average value of a function u over its domain. ''' return assemble(u * dx) \ / assemble(1.0 * dx(u.function_space().mesh()))
def test_boussinesq(with_voltage, target_time=1.0e-2, show=False): """Simple boussinesq test; no Maxwell involved. """ problem = problems.Crucible() # Solve construct initial state without Lorentz force and Joule heat. m = problem.subdomain_materials[problem.wpi] k_wpi = m.thermal_conductivity cp_wpi = m.specific_heat_capacity rho_wpi = m.density mu_wpi = m.dynamic_viscosity g = Constant((0.0, -9.80665, 0.0)) submesh_workpiece = problem.W.mesh() ds_workpiece = Measure("ds", subdomain_data=problem.wp_boundaries) u0, p0, theta0 = _construct_initial_state( submesh_workpiece, problem.W_element, problem.P_element, problem.Q_element, k_wpi, cp_wpi, rho_wpi, mu_wpi, Constant(0.0), problem.u_bcs, problem.p_bcs, problem.theta_bcs_d, problem.theta_bcs_n, dx(submesh_workpiece), ds_workpiece, g, extra_force=None, ) if with_voltage: voltages = [ 38.0 * numpy.exp(-1j * 2 * pi * 2 * 70.0 / 360.0), 38.0 * numpy.exp(-1j * 2 * pi * 1 * 70.0 / 360.0), 38.0 * numpy.exp(-1j * 2 * pi * 0 * 70.0 / 360.0), 25.0 * numpy.exp(-1j * 2 * pi * 0 * 70.0 / 360.0), 25.0 * numpy.exp(-1j * 2 * pi * 1 * 70.0 / 360.0), ] lorentz, joule, _ = get_lorentz_joule(problem, voltages, show=show) else: lorentz = None joule = Constant(0.0) u1, _, theta1 = _compute_boussinesq( problem, u0, p0, theta0, lorentz=lorentz, joule=joule, target_time=target_time, show=show, ) if with_voltage: # p is only defined up to a constant ref = 0.001069306823450495 assert abs(norm(u1, "L2") - ref) < 1.0e-3 * ref ref = 86.96271240592199 assert abs(norm(theta1, "L2") - ref) < 1.0e-3 * ref else: ref = 0.001069283700624996 assert abs(norm(u1, "L2") - ref) < 1.0e-3 * ref ref = 86.96274092197706 assert abs(norm(theta1, "L2") - ref) < 1.0e-3 * ref return
def _compute_boussinesq( problem, u0, p0, theta0, lorentz, joule, target_time=0.1, show=False ): # Define a facet measure on the boundaries. See discussion on # <https://bitbucket.org/fenics-project/dolfin/issue/249/facet-specification-doesnt-work-on-ds>. ds_workpiece = Measure("ds", subdomain_data=problem.wp_boundaries) submesh_workpiece = problem.W.mesh() # Start time, time step. t = 0.0 dt = 1.0e-3 dt_max = 1.0e-1 # Standard gravity, <https://en.wikipedia.org/wiki/Standard_gravity>. grav = 9.80665 assert problem.W.num_sub_spaces() == 3 g = Constant((0.0, -grav, 0.0)) # Compute a few mesh characteristics. wpi_area = assemble(1.0 * dx(submesh_workpiece)) # mesh.hmax() is a local function; get the global hmax. hmax_workpiece = MPI.max(submesh_workpiece.mpi_comm(), submesh_workpiece.hmax()) # Take the maximum length in x-direction as characteristic length of the # domain. coords = submesh_workpiece.coordinates() char_length = max(coords[:, 0]) - min(coords[:, 0]) # Prepare some parameters for the Navier-Stokes simulation in the workpiece m = problem.subdomain_materials[problem.wpi] k_wpi = m.thermal_conductivity cp_wpi = m.specific_heat_capacity rho_wpi = m.density mu_wpi = m.dynamic_viscosity theta_average = average(theta0) # show_total_force = True # if show_total_force: # f = rho_wpi(theta0) * g # if lorentz: # f += as_vector((lorentz[0], lorentz[1], 0.0)) # tri = plot(f, mesh=submesh_workpiece, title='Total external force') # plt.colorbar(tri) # plt.show() with XDMFFile(submesh_workpiece.mpi_comm(), "all.xdmf") as outfile: outfile.parameters["flush_output"] = True outfile.parameters["rewrite_function_mesh"] = False _store(outfile, u0, p0, theta0, t) if show: _plot(p0, theta0) plt.show() successful_steps = 0 failed_steps = 0 while t < target_time + DOLFIN_EPS: info( "Successful steps: {} (failed: {}, total: {})".format( successful_steps, failed_steps, successful_steps + failed_steps ) ) with Message("Time step {:e} -> {:e}...".format(t, t + dt)): # Do one heat time step. with Message("Computing heat..."): # Redefine the heat problem with the new u0. heat_problem = cyl_heat.Heat( problem.Q, kappa=k_wpi, rho=rho_wpi(theta_average), cp=cp_wpi, convection=u0, source=joule, dirichlet_bcs=problem.theta_bcs_d, neumann_bcs=problem.theta_bcs_n, my_dx=dx(submesh_workpiece), my_ds=ds_workpiece, ) # For time-stepping in buoyancy-driven flows, see # # Numerical solution of buoyancy-driven flows; # Einar Rossebø Christensen; # Master's thesis; # <http://www.diva-portal.org/smash/get/diva2:348831/FULLTEXT01.pdf>. # # Similar to the present approach, one first solves for # velocity and pressure, then for temperature. # heat_stepper = parabolic.ImplicitEuler(heat_problem) ns_stepper = cyl_ns.IPCS(time_step_method="backward euler") theta1 = heat_stepper.step(theta0, t, dt) theta0_average = average(theta0) try: # Do one Navier-Stokes time step. with Message("Computing flux and pressure..."): # Include proper temperature-dependence here to account # for the Boussinesq effect. f0 = rho_wpi(theta0) * g f1 = rho_wpi(theta1) * g if lorentz is not None: f = as_vector((lorentz[0], lorentz[1], 0.0)) f0 += f f1 += f u1, p1 = ns_stepper.step( Constant(dt), {0: u0}, p0, problem.W, problem.P, problem.u_bcs, problem.p_bcs, # Make constant TODO Constant(rho_wpi(theta0_average)), Constant(mu_wpi(theta0_average)), f={0: f0, 1: f1}, tol=1.0e-10, my_dx=dx(submesh_workpiece), ) except RuntimeError as e: info(e.args[0]) info( "Navier--Stokes solver failed to converge. " "Decrease time step from {:e} to {:e} and try again.".format( dt, 0.5 * dt ) ) dt *= 0.5 failed_steps += 1 continue successful_steps += 1 # Assignments and plotting. theta0.assign(theta1) u0.assign(u1) p0.assign(p1) _store(outfile, u0, p0, theta0, t + dt) if show: _plot(p0, theta0) plt.show() t += dt with Message("Diagnostics..."): # Print some general info on the flow in the crucible. umax = get_umax(u0) _print_diagnostics( theta0, umax, submesh_workpiece, wpi_area, problem.subdomain_materials, problem.wpi, rho_wpi, mu_wpi, char_length, grav, ) info("") with Message("Step size adaptation..."): # Some smooth step-size adaption. target_dt = 0.2 * hmax_workpiece / umax info("previous dt: {:e}".format(dt)) info("target dt: {:e}".format(target_dt)) # agg is the aggressiveness factor. The distance between # the current step size and the target step size is reduced # by |1-agg|. Hence, if agg==1 then dt_next==target_dt. # Otherwise target_dt is approached more slowly. agg = 0.5 dt = min( dt_max, # At most double the step size from step to step. dt * min(2.0, 1.0 + agg * (target_dt - dt) / dt), ) info("new dt: {:e}".format(dt)) info("") info("") return u0, p0, theta0
def compute_time_errors(problem, MethodClass, mesh_sizes, Dt): mesh_generator, solution, f, mu, rho, cell_type = problem() # Compute the problem errors = { "u": numpy.empty((len(mesh_sizes), len(Dt))), "p": numpy.empty((len(mesh_sizes), len(Dt))), } for k, mesh_size in enumerate(mesh_sizes): info("") info("") with Message("Computing for mesh size {}...".format(mesh_size)): mesh = mesh_generator(mesh_size) # Define all expression with `domain`, see # <https://bitbucket.org/fenics-project/ufl/issues/96>. # # Translate data into FEniCS expressions. sol_u = Expression( (ccode(solution["u"]["value"][0]), ccode(solution["u"]["value"][1])), degree=_truncate_degree(solution["u"]["degree"]), t=0.0, domain=mesh, ) sol_p = Expression( ccode(solution["p"]["value"]), degree=_truncate_degree(solution["p"]["degree"]), t=0.0, domain=mesh, ) fenics_rhs0 = Expression( (ccode(f["value"][0]), ccode(f["value"][1])), degree=_truncate_degree(f["degree"]), t=0.0, mu=mu, rho=rho, domain=mesh, ) # Deep-copy expression to be able to provide f0, f1 for the # Dirichlet boundary conditions later on. fenics_rhs1 = Expression( fenics_rhs0.cppcode, degree=_truncate_degree(f["degree"]), t=0.0, mu=mu, rho=rho, domain=mesh, ) # Create initial states. W = VectorFunctionSpace(mesh, "CG", 2) P = FunctionSpace(mesh, "CG", 1) p0 = Expression( sol_p.cppcode, degree=_truncate_degree(solution["p"]["degree"]), t=0.0, domain=mesh, ) mesh_area = assemble(1.0 * dx(mesh)) method = MethodClass( time_step_method="backward euler", # time_step_method='crank-nicolson', # stabilization=None # stabilization='SUPG' ) u1 = Function(W) p1 = Function(P) err_p = Function(P) divu1 = Function(P) for j, dt in enumerate(Dt): # Prepare previous states for multistepping. u = { 0: Expression( sol_u.cppcode, degree=_truncate_degree(solution["u"]["degree"]), t=0.0, cell=cell_type, ) } sol_u.t = dt u_bcs = [DirichletBC(W, sol_u, "on_boundary")] sol_p.t = dt # p_bcs = [DirichletBC(P, sol_p, 'on_boundary')] p_bcs = [] fenics_rhs0.t = 0.0 fenics_rhs1.t = dt u1, p1 = method.step( Constant(dt), u, p0, W, P, u_bcs, p_bcs, Constant(rho), Constant(mu), f={0: fenics_rhs0, 1: fenics_rhs1}, verbose=False, tol=1.0e-10, ) sol_u.t = dt sol_p.t = dt errors["u"][k][j] = errornorm(sol_u, u1) # The pressure is only determined up to a constant which makes # it a bit harder to define what the error is. For our # purposes, choose an alpha_0\in\R such that # # alpha0 = argmin ||e - alpha||^2 # # with e := sol_p - p. # This alpha0 is unique and explicitly given by # # alpha0 = 1/(2|Omega|) \int (e + e*) # = 1/|Omega| \int Re(e), # # i.e., the mean error in \Omega. alpha = +assemble(sol_p * dx(mesh)) - assemble(p1 * dx(mesh)) alpha /= mesh_area # We would like to perform # p1 += alpha. # To avoid creating a temporary function every time, assume # that p1 lives in a function space where the coefficients # represent actual function values. This is true for CG # elements, for example. In that case, we can just add any # number to the vector of p1. p1.vector()[:] += alpha errors["p"][k][j] = errornorm(sol_p, p1) show_plots = False if show_plots: plot(p1, title="p1", mesh=mesh) plot(sol_p, title="sol_p", mesh=mesh) err_p.vector()[:] = p1.vector() sol_interp = interpolate(sol_p, P) err_p.vector()[:] -= sol_interp.vector() # plot(sol_p - p1, title='p1 - sol_p', mesh=mesh) plot(err_p, title="p1 - sol_p", mesh=mesh) # r = SpatialCoordinate(mesh)[0] # divu1 = 1 / r * (r * u1[0]).dx(0) + u1[1].dx(1) divu1.assign(project(u1[0].dx(0) + u1[1].dx(1), P)) plot(divu1, title="div(u1)") return errors