def __init__(self, fem, source, fields, Mn=None, Mf1=None, Mf2=None, abs_du_tol=1e-8, rel_du_tol=1e-8, abs_res_tol=1e-10, rel_res_tol=1e-10, max_iter=100, criterion='residual', norm_change='linf', norm_res='linf'): """The constructor""" Solver.__init__(self, fem, source, fields, Mn, abs_du_tol, rel_du_tol, abs_res_tol, rel_res_tol, max_iter, criterion, norm_change, norm_res) # vector finite element and function space for rescaled (phi, h, y, z) self.E = d.MixedElement( [self.fem.Pn, self.fem.Pn, self.fem.Pn, self.fem.Pn]) self.V = d.FunctionSpace(self.fem.mesh.mesh, self.E) # (discontinuous) vector finite element and function space for the four strong residuals self.dE = d.MixedElement( [self.fem.dPn, self.fem.dPn, self.fem.dPn, self.fem.dPn]) self.dV = d.FunctionSpace(self.fem.mesh.mesh, self.dE) # fields' rescalings if Mf1 is None: self.Mf1 = self.source.Ms * self.Mn / self.fields.Mp else: self.Mf1 = Mf1 if Mf2 is None: if (self.fields.alpha != 0.): self.Mf2 = abs(self.fields.alpha) * self.Mf1 else: self.Mf2 = self.Mf1 else: self.Mf2 = Mf2 # solution and field profiles (computed by the solver) self.u = None self.phi, self.h, self.y, self.z = None, None, None, None self.Phi, self.H, self.Y, self.Z = None, None, None, None # gradients of the scalar fields self.grad_phi = None # rescaled self.grad_Phi = None # physical self.grad_h = None self.grad_H = None # phi scalar force (physical units) self.force = None
def __init__(self, fem, source, fields, Mn=None, Mf1='NL', guess_choice='NL', abs_du_tol=1e-8, rel_du_tol=1e-8, abs_res_tol=1e-10, rel_res_tol=1e-10, max_iter=100, criterion='residual', norm_change='linf', norm_res='linf'): """The constructor""" Solver.__init__(self, fem, source, fields, Mn, abs_du_tol, rel_du_tol, abs_res_tol, rel_res_tol, max_iter, criterion, norm_change, norm_res) # vector finite element and function space for rescaled (pi, w, y) self.E = d.MixedElement([self.fem.Pn, self.fem.Pn, self.fem.Pn]) self.V = d.FunctionSpace(self.fem.mesh.mesh, self.E) # (discontinuous) vector finite element and function space for the three strong residuals self.dE = d.MixedElement([self.fem.dPn, self.fem.dPn, self.fem.dPn]) self.dV = d.FunctionSpace(self.fem.mesh.mesh, self.dE) # field rescaling if Mf1 == 'NL': self.Mf1 = ( self.fields.Lambda / self.Mn )**(3.-1./self.fields.n) * \ ( self.source.Ms / self.fields.Mp )**(1./self.fields.n) * self.fields.m elif Mf1 == 'source': self.Mf1 = self.source.Ms / self.fields.Mp * self.Mn else: self.Mf1 = Mf1 # choice of initial guess self.guess_choice = guess_choice # solution and field profiles (computed by the solver) self.u = None self.pi, self.w, self.y = None, None, None # rescaled self.Pi, self.W, self.Y = None, None, None # physical # gradient of the scalar field self.grad_pi = None # rescaled self.grad_Pi = None # physical # scalar force (physical units) self.force = None
def extension_element(elm): ''' Produce an intermerdiate element for computing with extension of functions in FEM space over elm ''' # Want exact match here; otherwise VectorElement is MixedElement and while # it works I don't find it pretty if type(elm) == df.MixedElement: return df.MixedElement(map(extension_element, elm.sub_elements())) family = elm.family() family_map = {'Lagrange': 'Lagrange'} # This seems like a reasonable fall back option family = family_map.get(family, 'Discontinuous Lagrange') degree = elm.degree() # Preserve degree cell = extension_cell(elm) # How to construct: # There is an issue here where e.g. Hdiv are not scalars, their # element is FiniteElement but we want trace space from VectorElement elmtype_map = { 0: df.FiniteElement, 1: df.VectorElement, 2: df.TensorElement } # So let's check first for elements where scalar = FiniteElm, vector == VectorElm rank = len(elm.value_shape()) if elmtype_map[rank] == type(elm): elm = type(elm) # i.e. vector element stays vector element else: elm = elmtype_map[rank] return elm(family, cell, degree)
def generate_function_spaces(self, order=1, use_periodic=False): r""" Generates the finite-element function spaces used with topological dimension :math:`d` set by variable ``self.top_dim``. :param order: order :math:`k` of the shape function, currently only supported are Lagrange :math:`P_1` elements. :param use_periodic: use periodic boundaries along lateral boundary (currently not supported). :type use_periodic: bool The element shape-functions available from this method are : * ``self.Q`` -- :math:`\mathcal{H}^k(\Omega)` * ``self.Q3`` -- :math:`[\mathcal{H}^k(\Omega)]^3` * ``self.V`` -- :math:`[\mathcal{H}^k(\Omega)]^d` formed using :func:`~dolfin.functions.functionspace.VectorFunctionSpace` * ``self.T`` -- :math:`[\mathcal{H}^k(\Omega)]^{d \times d}` formed using :func:`~dolfin.functions.functionspace.TensorFunctionSpace` """ s = "::: generating fundamental function spaces of order %i :::" % order print_text(s, cls=self.this) if use_periodic: self.generate_pbc() else: self.pBC = None order = 1 space = 'CG' Qe = dl.FiniteElement("CG", self.mesh.ufl_cell(), order) self.Q3 = dl.FunctionSpace(self.mesh, dl.MixedElement([Qe] * 3)) self.Q = dl.FunctionSpace(self.mesh, space, order) self.V = dl.VectorFunctionSpace(self.mesh, space, order) self.T = dl.TensorFunctionSpace(self.mesh, space, order) s = " - fundamental function spaces created - " print_text(s, cls=self.this)
def computeVelocityField(mesh): Xh = dl.VectorFunctionSpace(mesh,'Lagrange', 2) Wh = dl.FunctionSpace(mesh, 'Lagrange', 1) mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()]) XW = dl.FunctionSpace(mesh, mixed_element) Re = 1e2 g = dl.Expression(('0.0','(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element()) bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary) bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise') bcs = [bc1, bc2] vq = dl.Function(XW) (v,q) = ufl.split(vq) (v_test, q_test) = dl.TestFunctions (XW) def strain(v): return ufl.sym(ufl.grad(v)) F = ( (2./Re)*ufl.inner(strain(v),strain(v_test))+ ufl.inner (ufl.nabla_grad(v)*v, v_test) - (q * ufl.div(v_test)) + ( ufl.div(v) * q_test) ) * ufl.dx dl.solve(F == 0, vq, bcs, solver_parameters={"newton_solver": {"relative_tolerance":1e-4, "maximum_iterations":100, "linear_solver":"default"}}) return v
def __init__(self, parameters, mesh, parser): super().__init__(parameters, mesh, parser) V = df.FunctionSpace( self.mesh, df.MixedElement( df.VectorElement('CG', self.mesh.ufl_cell(), parameters["fe degree solid"]), df.VectorElement('CG', self.mesh.ufl_cell(), parameters["fe degree fluid"]), df.FiniteElement('CG', self.mesh.ufl_cell(), parameters["fe degree pressure"]))) self.V = V self.two_way = True self.three_way = False if "3-way" in self.parameters["pc type"]: self.two_way = False self.three_way = True parprint("---- Problem dofs={}, h={}, solving with {} procs".format( V.dim(), mesh.hmin(), MPI.COMM_WORLD.size)) self.assembler = PoromechanicsAssembler(parameters, V, self.three_way) self.index_map = IndexSet(V, self.two_way) # Start by assembling system matrices self.assembler.assemble() self.sol = df.Function(V) self.us_nm1, self.uf_nm1, self.p_nm1 = self.sol.split(True) self.us_nm2 = self.us_nm1.copy(True) self.first_timestep = True
def test_dirichlet_boundary(self): frequency=50 omega = 2.*np.pi*frequency c1,c2 = [343.4,6320] gamma=8.4e-4 kappa = omega/c1 Nx, Ny = [21,21] Lx,Ly=[1,1] # create function space mesh = dl.RectangleMesh(dl.Point(0., 0.), dl.Point(Lx, Ly), Nx, Ny) degree=1 P1=dl.FiniteElement('Lagrange',mesh.ufl_cell(),degree) element=dl.MixedElement([P1,P1]) function_space=dl.FunctionSpace(mesh,element) boundary_conditions=None kappa=dl.Constant(kappa) # do not pass element=function_space.ufl_element() # as want forcing to be a scalar pass degree instead forcing=[ Forcing(kappa,'real',degree=function_space.ufl_element().degree()), Forcing(kappa,'imag',degree=function_space.ufl_element().degree())] p=run_model(kappa,forcing,function_space,boundary_conditions) error = dl.errornorm( ExactSolution(kappa,element=function_space.ufl_element()),p) print('Error',error) assert error<=3e-2
def test_robin_boundary(self): frequency=50 omega = 2.*np.pi*frequency c1,c2 = [343.4,6320] gamma=8.4e-4 kappa = omega/c1 alpha=kappa*gamma Nx, Ny = 21,21; Lx, Ly = 1,1 mesh = dl.RectangleMesh(dl.Point(0., 0.), dl.Point(Lx, Ly), Nx, Ny) degree=1 P1=dl.FiniteElement('Lagrange',mesh.ufl_cell(),degree) element=dl.MixedElement([P1,P1]) function_space=dl.FunctionSpace(mesh,element) boundary_conditions=get_robin_bndry_conditions( kappa,alpha,function_space) kappa=dl.Constant(kappa) forcing=[ Forcing(kappa,'real',degree=function_space.ufl_element().degree()), Forcing(kappa,'imag',degree=function_space.ufl_element().degree())] p=run_model(kappa,forcing,function_space,boundary_conditions) error = dl.errornorm( ExactSolution(kappa,element=function_space.ufl_element()),p,) print('Error',error) assert error<=3e-2
def _setup_function_spaces(self): assert hasattr(self, "_mesh") # element and function space definition cell = self._mesh.ufl_cell() # taylor-hood element self._elemV = dlfn.VectorElement("CG", cell, self._parameters.velocity_degree) self._elemP = dlfn.FiniteElement("CG", cell, self._parameters.pressure_degree) self._elemT = dlfn.FiniteElement("CG", cell, self._parameters.temperature_degree) self._mixedElem = dlfn.MixedElement( [self._elemV, self._elemP, self._elemT]) self._Wh = dlfn.FunctionSpace(self._mesh, self._mixedElem) # print info message ndofs_velocity = self._Wh.sub(0).dim() ndofs_pressure = self._Wh.sub(1).dim() ndofs_temperature = self._Wh.sub(2).dim() print "DOFs velocity : ", ndofs_velocity, "\n" \ "DOFs pressure : ", ndofs_pressure, "\n" \ "DOFs temperature : ", ndofs_temperature # functions self._sol = dlfn.Function(self._Wh) self._sol0 = dlfn.Function(self._Wh) self._sol00 = dlfn.Function(self._Wh) self._v0, _, self._T0 = dlfn.split(self._sol0) self._v00, _, self._T00 = dlfn.split(self._sol00)
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 _element(s): elements = [ s[k + '/element'] for k in s[key + '/subfunctions_keys'] ] if len(elements) == 0: raise AssertionError() elif len(elements) == 1: return elements[0] else: return dolfin.MixedElement(elements)
def get_element(self): ''' use `element` property instead ''' descs = self.subspace_descriptors elements = [desc['element'] for desc in descs] n = len(elements) if n == 0: raise AssertionError() elif n == 1: return elements[0] else: return dolfin.MixedElement(elements)
def create_functions(self): """ Create functions to hold solutions """ sim = self.simulation # Function spaces Vu = sim.data['Vu'] Vp = sim.data['Vp'] cd = sim.data['constrained_domain'] # Create coupled mixed function space and mixed function to hold results func_spaces = [Vu] * sim.ndim + [Vp] self.subspace_names = ['u%d' % d for d in range(sim.ndim)] + ['p'] # Create stress tensor space P = Vu.ufl_element().degree() Vs = dolfin.FunctionSpace(sim.data['mesh'], 'DG', P, constrained_domain=cd) for i in range(sim.ndim**2): stress_name = 'stress_%d' % i sim.data[stress_name] = dolfin.Function(Vs) func_spaces.append(Vs) self.subspace_names.append(stress_name) # Create mixed space e_mixed = dolfin.MixedElement([fs.ufl_element() for fs in func_spaces]) Vcoupled = dolfin.FunctionSpace(sim.data['mesh'], e_mixed) sim.data['Vcoupled'] = Vcoupled # Create function assigner Nspace = len(func_spaces) self.subspaces = [Vcoupled.sub(i) for i in range(Nspace)] sim.data['coupled'] = self.coupled_func = dolfin.Function(Vcoupled) self.assigner = dolfin.FunctionAssigner(func_spaces, Vcoupled) # Create segregated functions on component and vector form u_list, up_list, upp_list, u_conv = [], [], [], [] for d in range(sim.ndim): sim.data['u%d' % d] = u = dolfin.Function(Vu) sim.data['up%d' % d] = up = dolfin.Function(Vu) sim.data['upp%d' % d] = upp = dolfin.Function(Vu) sim.data['u_conv%d' % d] = uc = dolfin.Function(Vu) u_list.append(u) up_list.append(up) upp_list.append(upp) u_conv.append(uc) sim.data['u'] = dolfin.as_vector(u_list) sim.data['up'] = dolfin.as_vector(up_list) sim.data['upp'] = dolfin.as_vector(upp_list) sim.data['u_conv'] = dolfin.as_vector(u_conv) sim.data['p'] = dolfin.Function(Vp)
def _init_spaces(self): mesh = self.geometry.mesh P1 = dolfin.FiniteElement("Lagrange", mesh.ufl_cell(), 1) P2 = dolfin.VectorElement("Lagrange", mesh.ufl_cell(), 2) P3 = dolfin.VectorElement("Real", mesh.ufl_cell(), 0, 6) self.state_space = dolfin.FunctionSpace(mesh, dolfin.MixedElement([P1, P2, P3])) self.state = Function(self.state_space, name="state") self.state_test = dolfin.TestFunction(self.state_space)
def computeVelocityField(self): """ The steady-state Navier-Stokes equation for velocity v: -1/Re laplace v + nabla q + v dot nabla v = 0 in Omega nabla dot v = 0 in Omega v = g on partial Omega """ Xh = dl.VectorFunctionSpace(self.mesh, 'Lagrange', self.eldeg) Wh = dl.FunctionSpace(self.mesh, 'Lagrange', 1) mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()]) XW = dl.FunctionSpace(self.mesh, mixed_element) Re = dl.Constant(self.Re) def v_boundary(x, on_boundary): return on_boundary def q_boundary(x, on_boundary): return x[0] < dl.DOLFIN_EPS and x[1] < dl.DOLFIN_EPS g = dl.Expression(('0.0', '(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element()) bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary) bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise') bcs = [bc1, bc2] vq = dl.Function(XW) (v, q) = ufl.split(vq) (v_test, q_test) = dl.TestFunctions(XW) def strain(v): return ufl.sym(ufl.grad(v)) F = ((2. / Re) * ufl.inner(strain(v), strain(v_test)) + ufl.inner(ufl.nabla_grad(v) * v, v_test) - (q * ufl.div(v_test)) + (ufl.div(v) * q_test)) * ufl.dx dl.solve(F == 0, vq, bcs, solver_parameters={ "newton_solver": { "relative_tolerance": 1e-4, "maximum_iterations": 100, "linear_solver": "default" } }) return v
def _generate_function_spaces(self, **kwargs): """ Generates a dolfin FunctionSpace of either single Finite Element (if only one Space is provided) or Mixed Elements (if more the one Space provided). """ elements = [ self._generate_finite_element(space, **kwargs) for space in self.spaces ] if len(elements) == 1: return dolf.FunctionSpace(self.domain.mesh, elements[0], **kwargs) mixed_element = dolf.MixedElement(elements) return dolf.FunctionSpace(self.domain.mesh, mixed_element, **kwargs)
def __init__(self, t_end = None, func = None, para_stiff = None, adjoint = False): Problem_Basic.__init__(self, t_end = t_end, func = func, para_stiff = para_stiff) self.k = dol.Constant(self.k) self.u0_expr = dol.Constant(self.u0) # initial value mesh = dol.UnitIntervalMesh(1) R_elem = dol.FiniteElement("R", mesh.ufl_cell(), 0) V_elem = dol.MixedElement([R_elem, R_elem]) self.V = dol.FunctionSpace(mesh, V_elem) if adjoint: self.z0_expr = dol.Constant(np.array([0., 0.])) # initial value adj Problem_FE.__init__(self, adjoint) (self.v1 , self.v2) = dol.split(self.v) (self.u1trial, self.u2trial) = dol.split(self.utrial) (self.u1old , self.u2old) = dol.split(self.uold) (self.u1low , self.u2low) = dol.split(self.ulow) ## Crank nicolson weak formulation F = (dol.inner(self.v1, self.u1trial - self.u1old + self.dt * (0.5 * (self.u1old + self.u1trial) - 0.5 * (self.u2old + self.u2trial)))*dol.dx + dol.inner(self.v2, self.u2trial - self.u2old - self.k * self.dt * 0.5 * (self.u2old + self.u2trial))*dol.dx) prob = dol.LinearVariationalProblem(dol.lhs(F), dol.rhs(F), self.unew) self.solver = dol.LinearVariationalSolver(prob) ## Implicit Euler weak formulation for error estimation Flow = (dol.inner(self.v1, self.u1trial - self.u1old + self.dt * (self.u1trial - self.u2trial))*dol.dx + dol.inner(self.v2, self.u2trial - self.u2old - self.k * self.dt * self.u2trial)*dol.dx) problow = dol.LinearVariationalProblem(dol.lhs(Flow), dol.rhs(Flow), self.ulow) self.solver_low = dol.LinearVariationalSolver(problow) if adjoint: (self.z1old , self.z2old) = dol.split(self.zold) (self.z1trial, self.z2trial) = dol.split(self.ztrial) if self.func not in [1, 2]: raise ValueError('DWR not (yet) implemented for this functional') adj_src = dol.Function(self.V) if self.func == 1: adj_src.interpolate(dol.Constant((1, 0))) elif self.func == 2: adj_src.interpolate(dol.Constant((0, 1))) src1, src2 = dol.split(adj_src) Fadj = (dol.inner(self.z1trial - self.z1old + 0.5 * self.dt * (-self.z1trial - self.z1old + 2*src1), self.v1)*dol.dx + dol.inner(self.z2trial - self.z2old + 0.5 * self.dt * ( self.z1trial + self.z1old + self.k*(self.z2trial + self.z2old) + 2*src2), self.v2)*dol.dx) prob_adj = dol.LinearVariationalProblem(dol.lhs(Fadj), dol.rhs(Fadj), self.znew) self.solver_adj = dol.LinearVariationalSolver(prob_adj)
def ode_test_form(request): Model = eval(request.param) model = Model() mesh = df.UnitSquareMesh(10, 10) V = df.FunctionSpace(mesh, "CG", 1) S = state_space(mesh, model.num_states()) Mx = df.MixedElement((V.ufl_element(), S.ufl_element())) VS = df.FunctionSpace(mesh, Mx) vs = df.Function(VS) vs.assign(df.project(model.initial_conditions(), VS)) (v, s) = df.split(vs) (w, r) = df.TestFunctions(VS) rhs = df.inner(model.F(v, s), r) + df.inner(- model.I(v, s), w) form = rhs*df.dP return form
def _init_spaces(self): mesh = self.geometry.mesh V = dolfin.VectorElement("P", mesh.ufl_cell(), 2) Q = dolfin.FiniteElement("P", mesh.ufl_cell(), 1) R = dolfin.FiniteElement("Real", mesh.ufl_cell(), 0) el = dolfin.MixedElement([V, Q, R]) self.state_space = dolfin.FunctionSpace(mesh, el) self.state = dolfin.Function(self.state_space) self.state_test = dolfin.TestFunction(self.state_space) self._Vu = get_cavity_volume_form(self.geometry.mesh, u=dolfin.split(self.state)[0], xshift=self.geometry.xshift) self._V0 = dolfin.Constant(self.geometry.cavity_volume())
def create_mixed_space(mesh, k=1, augmentedTH=False, periodic_boundary=None): Pk = df.FiniteElement("CG", mesh.ufl_cell(), k) Pk1 = df.FiniteElement("CG", mesh.ufl_cell(), k + 1) FE_v = df.VectorElement(Pk1, dim=mesh.geometry().dim()) FE_p = Pk if augmentedTH: # Use enriched element for p -> augmented TH, see Boffi et al. (2011) P0 = df.FiniteElement("DG", mesh.ufl_cell(), 0) gdim = mesh.geometry().dim() assert k >= gdim - 1 # see Boffi et al. (2011, Eq. (3.1)) FE_p = df.EnrichedElement(Pk, P0) W = df.FunctionSpace(mesh, df.MixedElement([FE_v, FE_p]), constrained_domain=periodic_boundary) return W
def create_functions(self): """ Create functions to hold solutions """ sim = self.simulation # Function spaces Vu = sim.data['Vu'] Vp = sim.data['Vp'] cd = sim.data['constrained_domain'] # Create coupled mixed function space and mixed function to hold results func_spaces = [Vu] * sim.ndim + [Vp] self.subspace_names = ['u%d' % d for d in range(sim.ndim)] + ['p'] if self.use_lagrange_multiplicator: Vl = dolfin.FunctionSpace(sim.data['mesh'], "R", 0, constrained_domain=cd) sim.data['l'] = dolfin.Function(Vl) func_spaces.append(Vl) self.subspace_names.append('l') e_mixed = dolfin.MixedElement([fs.ufl_element() for fs in func_spaces]) Vcoupled = dolfin.FunctionSpace(sim.data['mesh'], e_mixed) sim.data['Vcoupled'] = Vcoupled sim.ndofs += Vcoupled.dim() Nspace = len(func_spaces) self.subspaces = [Vcoupled.sub(i) for i in range(Nspace)] sim.data['coupled'] = self.coupled_func = dolfin.Function(Vcoupled) self.assigner = dolfin.FunctionAssigner(func_spaces, Vcoupled) # Create segregated functions on component and vector form create_vector_functions(sim, 'u', 'u%d', Vu) create_vector_functions(sim, 'up', 'up%d', Vu) create_vector_functions(sim, 'upp', 'upp%d', Vu) create_vector_functions(sim, 'u_conv', 'u_conv%d', Vu) create_vector_functions(sim, 'up_conv', 'up_conv%d', Vu) create_vector_functions(sim, 'upp_conv', 'upp_conv%d', Vu) create_vector_functions(sim, 'u_unlim', 'u_unlim%d', Vu) sim.data['p'] = dolfin.Function(Vp) sim.data['ui_tmp'] = dolfin.Function(Vu)
def test_variable_kappa(self): frequency = 50 omega = 2. * np.pi * frequency c1, c2 = [343.4, 6320 * 100] gamma = 8.4e-4 kappa1 = omega / c1 kappa2 = omega / c2 Nx, Ny = 21, 21 Lx, Ly = 1, 1 #mesh = RectangleMesh(Point(0., 0.), Point(Lx, Ly), Nx, Ny) mesh = generate_mesh_with_cicular_subdomain(15, 0.25, False) degree = 1 P1 = dl.FiniteElement('Lagrange', mesh.ufl_cell(), degree) element = dl.MixedElement([P1, P1]) function_space = dl.FunctionSpace(mesh, element) boundary_conditions = None forcing = [ ForcingVariableKappa(kappa1, kappa2, 'real', degree=function_space.ufl_element().degree()), ForcingVariableKappa(kappa1, kappa2, 'imag', degree=function_space.ufl_element().degree()) ] kappa = dl.Expression('x[1] <= 0.5 + tol ? k_0 : k_1', degree=0, tol=1e-14, k_0=kappa1, k_1=kappa2) # use mesh with circular subdomain as this should not effect result # significantly but will test if subdomain mesh works correctly p = run_model(kappa, forcing, function_space, boundary_conditions) error = dl.errornorm( ExactSolution(kappa, element=function_space.ufl_element()), p) print('Error', error) assert error <= 3e-2
def create_functions(self): """ Create functions to hold solutions """ sim = self.simulation # Function spaces Vu = sim.data['Vu'] Vp = sim.data['Vp'] # Create velocity functions on component and vector form create_vector_functions(sim, 'u', 'u%d', Vu) create_vector_functions(sim, 'up', 'up%d', Vu) create_vector_functions(sim, 'upp', 'upp%d', Vu) create_vector_functions(sim, 'u_conv', 'u_conv%d', Vu) create_vector_functions(sim, 'up_conv', 'up_conv%d', Vu) create_vector_functions(sim, 'upp_conv', 'upp_conv%d', Vu) create_vector_functions(sim, 'u_unlim', 'u_unlim%d', Vu) sim.data['ui_tmp'] = dolfin.Function(Vu) # Create coupled vector function ue = Vu.ufl_element() e_mixed = dolfin.MixedElement([ue] * sim.ndim) Vcoupled = dolfin.FunctionSpace(Vu.mesh(), e_mixed) sim.data['uvw_star'] = dolfin.Function(Vcoupled) sim.data['uvw_temp'] = dolfin.Function(Vcoupled) sim.ndofs += Vcoupled.dim() + Vp.dim() # Create assigner to extract split function from uvw and vice versa self.assigner_split = dolfin.FunctionAssigner([Vu] * sim.ndim, Vcoupled) self.assigner_merge = dolfin.FunctionAssigner(Vcoupled, [Vu] * sim.ndim) # Create pressure function sim.data['p'] = dolfin.Function(Vp) sim.data['p_hat'] = dolfin.Function(Vp)
def __init__( self, energy, state, bcs, # rayleigh=None, Hessian=None, nullspace=None, parameters=None): """Solves second order stability problem - computes inertia - solves full eigenvalue problem * Parameters: - energy (form) - state (tuple) - bcs (list) Optional arguments: rayleigh (form), Hessian (form), nullspace, parameters """ OptDB = PETSc.Options() OptDB.view() self.i = 0 self.u = state['u'] self.alpha = state['alpha'] self._u = dolfin.Vector(self.u.vector()) self._alpha = dolfin.Vector(self.alpha.vector()) self.mesh = state['alpha'].function_space().mesh() self.Z = dolfin.FunctionSpace( self.mesh, dolfin.MixedElement( [self.u.ufl_element(), self.alpha.ufl_element()])) self.z = dolfin.Function(self.Z) self.z_old = dolfin.Function(self.Z) zeta = dolfin.TestFunction(self.Z) v, beta = dolfin.split(zeta) self.dm = self.Z.dofmap() self.ownership = self.Z.dofmap().ownership_range() Zu = self.Z.extract_sub_space([0]) Za = self.Z.extract_sub_space([1]) self.Xa = Za.collapse().tabulate_dof_coordinates() self.Xu = Zu.collapse().tabulate_dof_coordinates() (_, self.mapa) = Za.collapse(collapsed_dofs=True) (_, self.mapu) = Zu.collapse(collapsed_dofs=True) self.assigner = dolfin.FunctionAssigner( self.Z, # receiving space [self.u.function_space(), self.alpha.function_space()]) # assigning spaces self.parameters = self.setParameters(parameters) self.ownership = self.Z.dofmap().ownership_range() self.assigner = dolfin.FunctionAssigner( self.Z, # receiving space [self.u.function_space(), self.alpha.function_space()]) # assigning space dim = self.u.function_space().ufl_element().value_size() self.stable = '' self.negev = -1 self.mineig = 1. self.Ealpha = derivative( energy, self.alpha, dolfin.TestFunction(self.alpha.ufl_function_space())) self.energy = energy (z_u, z_a) = dolfin.split(self.z) energy = ufl.replace(energy, {self.u: z_u, self.alpha: z_a}) self.J = derivative(energy, self.z, dolfin.TestFunction(self.Z)) self.H = derivative(self.J, self.z, dolfin.TrialFunction(self.Z)) self.nullspace = nullspace if Hessian: self.Hessian = Hessian self.ownership_range = self.Z.dofmap().ownership_range() if len(bcs) > 0: self.bcs = bcs self.bc_dofs = self.get_bc_dofs(bcs) else: self.bcs = None self.bc_dofs = set() self.perturbation_v = dolfin.Function(self.Z.sub(0).collapse()) self.perturbation_beta = dolfin.Function(self.Z.sub(1).collapse()) self._Hessian = Hessian if Hessian.__class__ == ufl.form.Form else self.H
def comp_axisymmetric_pure_neumann(mat_obj, mesh_obj, bc, omega, save_path): E = mat_obj.E rho = mat_obj.rho nu = mat_obj.nu mesh = mesh_obj.create() Rext = mesh_obj.Rext Rint = mesh_obj.Rint # rename x[0], x[1] by x, y x, y = df.SpatialCoordinate(mesh) dim = mesh.topology().dim() cell_markers = df.MeshFunction("size_t", mesh, dim) facet_markers = df.MeshFunction("size_t", mesh, dim - 1) coord = mesh.coordinates() class OuterRadius(df.SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0]**2 + x[1]**2 >= Rext**2 - 1e-3 class InnerRadius(df.SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0]**2 + x[1]**2 <= Rint**2 + 1e-3 OuterRadius().mark(facet_markers, 1) InnerRadius().mark(facet_markers, 2) df.File(save_path + 'cell_markers.pvd') << cell_markers df.File(save_path + 'facet_markers.pvd') << facet_markers # Create mesh and define function space V = df.FunctionSpace(mesh, "CG", 1) # =========================== Define Finite Element =========================== degree = 1 #P1 table of periodic # CG: Continuous Galerkin V_ele = df.FiniteElement("CG", mesh.ufl_cell(), degree) # scalar, Ex: u R_ele = df.FiniteElement("R", mesh.ufl_cell(), 0) # scalar, Ex: u # Vector element # akternative : manually define vector function : better for 3D adaptation than above total_ele = df.MixedElement([V_ele, R_ele]) W = df.FunctionSpace(mesh, total_ele) # Define trial function dunks = df.TrialFunction(W) (du, dc) = df.split(dunks) # Define variational problem tunks = df.TestFunction(W) (tu, tc) = df.split(tunks) # displacement in radial direction u(x,y) unks = df.Function(W) #(u, c) = df.split(unks) class THETA(df.UserExpression): def eval(self, values, x): values[0] = math.atan2(x[1], x[0]) def value_shape(self): #return (1,) # vector return () # scalar theta = THETA(degree=1) #theta_int = df.interpolate(theta, df.FunctionSpace(mesh, "DG", 0)) #df.File(save_path + 'theta.pvd') << theta_int class RADIUS(df.UserExpression): def eval(self, values, x): values[0] = df.sqrt(x[0] * x[0] + x[1] * x[1]) def value_shape(self): return () # scalar r = RADIUS(degree=1) # strain radial def epsilon_r(du): return 1.0 / r * (x * df.Dx(du, 0) + y * df.Dx(du, 1)) # strain circumferential def epsilon_theta(du): return du / df.sqrt(x**2 + y**2) # radial stress # train-stress relation def sigma_r(du): return E / (1.0 - nu**2) * (epsilon_r(du) + nu * epsilon_theta(du)) # circumferential stress def sigma_theta(du): return E / (1.0 - nu**2) * (nu * epsilon_r(du) + epsilon_theta(du)) # Weak form dFu = r * sigma_r(du) * epsilon_r(tu) * df.dx(0) dFu = dFu + sigma_theta(du) * tu * df.dx(0) dFu = dFu + dc * tu * df.dx(0) dFu = dFu - rho * omega**2 * r**2 * tu * df.dx(0) dFc = du * tc * df.dx(1) dFu = r * sigma_r(du) * epsilon_r(tu) * df.dx dFu = dFu + sigma_theta(du) * tu * df.dx dFu = dFu + dc * tu * df.dx dFu = dFu - rho * omega**2 * r**2 * tu * df.dx dFc = du * tc * df.dx dF = dFu + dFc # residual #F = df.action(dF, unks) a = df.lhs(dF) L = df.rhs(dF) df.solve(a == L, unks) (_u, _c) = unks.split(True) u_pro = df.project(_u, V) u_pro.rename('dis u [m]', 'dis u [m]') # displacement df.File(save_path + 'displacement.pvd') << u_pro # compute stresses sigma_r_pro = df.project(sigma_r(_u), V) sigma_r_pro.rename('sigma_r [Pa]', 'sigma_r [Pa]') df.File(save_path + 'sigma_r.pvd') << sigma_r_pro sigma_theta_pro = df.project(sigma_theta(_u), V) sigma_theta_pro.rename('sigma_theta [Pa]', 'sigma_theta [Pa]') df.File(save_path + 'sigma_theta.pvd') << sigma_theta_pro # compute von Mises stress def von_mises_stress(sigma_r, sigma_theta): return df.sqrt(sigma_r**2 + sigma_theta**2 - sigma_r * sigma_theta) von_stress_pro = df.project(von_mises_stress(sigma_r(_u), sigma_theta(_u)), V) von_stress_pro.rename('von Mises Stress [Pa]', 'von Mises Stress [Pa]') df.File(save_path + 'von_mises_stress.pvd') << von_stress_pro
''' # name = 'density', function = density_function (function is the solution vector here) density_function_space = df.FunctionSpace(mesh, 'DG', 0) density_function = df.Function(density_function_space) pde_problem.add_input('density', density_function) ''' 4. 2. Add states ''' # Define mixed function space-split into temperature and displacement FS d = mesh.geometry().dim() cell = mesh.ufl_cell() displacement_fe = df.VectorElement("CG", cell, 1) temperature_fe = df.FiniteElement("CG", cell, 1) mixed_fs = df.FunctionSpace(mesh, df.MixedElement([displacement_fe, temperature_fe])) mixed_fs.sub(1).dofmap().dofs() mixed_function = df.Function(mixed_fs) displacements_function, temperature_function = df.split(mixed_function) # displacements_function,temperature_function = mixed_function.split() v, T_hat = df.TestFunctions(mixed_fs) residual_form = get_residual_form(displacements_function, v, density_function, temperature_function, T_hat, KAPPA, K, ALPHA) residual_form -= (df.dot(f_r, v) * dss(10) + df.dot(f_t, v) * dss(14) + \ q*T_hat*dss(5) + q_half*T_hat*dss(6) + q_quart*T_hat*dss(7)) print("get residual_form-------") # print('ssssssss',df.assemble(T_hat*df.dx).get_local()) pde_problem.add_state('mixed_states', mixed_function, residual_form, 'density')
# Declare finite elements elements = dict() for name, (family, degree, is_vector) in base_elements.items(): if is_vector: elements[name] = df.VectorElement(family, mesh.ufl_cell(), degree) else: elements[name] = df.FiniteElement(family, mesh.ufl_cell(), degree) # Declare function spaces spaces = dict() for name, subproblem in subproblems.items(): if len(subproblem) > 1: spaces[name] = df.FunctionSpace( mesh, df.MixedElement([elements[s["element"]] for s in subproblem]), constrained_domain=constrained_domain(**vars())) # If there is only one field in the subproblem, don't bother with # the MixedElement. elif len(subproblem) == 1: spaces[name] = df.FunctionSpace( mesh, elements[subproblem[0]["element"]], constrained_domain=constrained_domain(**vars())) else: info_on_red("Something went wrong here!") exit("") # dim = mesh.topology().dim() # In case the velocity fields should be # # segregated at some point fields = []
def __init__(self, fenics_2d_rve, **kwargs): """[summary] Parameters ---------- object : [type] [description] fenics_2d_rve : [type] [description] element : tuple or dict Type and degree of element for displacement FunctionSpace Ex: ('CG', 2) or {'family':'Lagrange', degree:2} solver : dict Choose the type of the solver, its method and the preconditioner. An up-to-date list of the available solvers and preconditioners can be obtained with dolfin.list_linear_solver_methods() and dolfin.list_krylov_solver_preconditioners(). """ self.rve = fenics_2d_rve self.topo_dim = topo_dim = fenics_2d_rve.dim try: bottom_left_corner = fenics_2d_rve.bottom_left_corner except AttributeError: logger.warning( "For the definition of the periodicity boundary conditions," "the bottom left corner of the RVE is assumed to be on (0.,0.)" ) bottom_left_corner = np.zeros(shape=(topo_dim, )) self.pbc = periodicity.PeriodicDomain.pbc_dual_base( fenics_2d_rve.gen_vect, "XY", bottom_left_corner, topo_dim) solver = kwargs.pop("solver", {}) # {'type': solver_type, 'method': solver_method, 'preconditioner': preconditioner} s_type = solver.pop("type", None) s_method = solver.pop("method", SOLVER_METHOD) s_precond = solver.pop("preconditioner", None) if s_type is None: if s_method in DOLFIN_KRYLOV_METHODS.keys(): s_type = "Krylov" elif s_method in DOLFIN_LU_METHODS.keys(): s_type = "LU" else: raise RuntimeError("The indicated solver method is unknown.") self._solver = dict(type=s_type, method=s_method) if s_precond: self._solver["preconditioner"] = s_precond element = kwargs.pop("element", ("Lagrange", 2)) if isinstance(element, dict): element = (element["family"], element["degree"]) self._element = element # * Function spaces cell = self.rve.mesh.ufl_cell() self.scalar_FE = fe.FiniteElement(element[0], cell, element[1]) self.displ_FE = fe.VectorElement(element[0], cell, element[1]) strain_deg = element[1] - 1 if element[1] >= 1 else 0 strain_dim = int(topo_dim * (topo_dim + 1) / 2) self.strain_FE = fe.VectorElement("DG", cell, strain_deg, dim=strain_dim) # Espace fonctionel scalaire self.X = fe.FunctionSpace(self.rve.mesh, self.scalar_FE, constrained_domain=self.pbc) # Espace fonctionnel 3D : deformations, notations de Voigt self.W = fe.FunctionSpace(self.rve.mesh, self.strain_FE) # Espace fonctionel 2D pour les champs de deplacement # TODO : reprendre le Ve défini pour l'espace fonctionnel mixte. Par ex: V = FunctionSpace(mesh, Ve) self.V = fe.VectorFunctionSpace(self.rve.mesh, element[0], element[1], constrained_domain=self.pbc) # * Espace fonctionel mixte pour la résolution : # * 2D pour les champs + scalaire pour multiplicateur de Lagrange # "R" : Real element with one global degree of freedom self.real_FE = fe.VectorElement("R", cell, 0) self.M = fe.FunctionSpace( self.rve.mesh, fe.MixedElement([self.displ_FE, self.real_FE]), constrained_domain=self.pbc, ) # Define variational problem self.v, self.lamb_ = fe.TestFunctions(self.M) self.u, self.lamb = fe.TrialFunctions(self.M) self.w = fe.Function(self.M) # bilinear form self.a = ( fe.inner(sigma(self.rve.C_per, epsilon(self.u)), epsilon(self.v)) * fe.dx + fe.dot(self.lamb_, self.u) * fe.dx + fe.dot(self.lamb, self.v) * fe.dx) self.K = fe.assemble(self.a) if self._solver["type"] == "Krylov": self.solver = fe.KrylovSolver(self.K, self._solver["method"]) elif self._solver["type"] == "LU": self.solver = fe.LUSolver(self.K, self._solver["method"]) self.solver.parameters["symmetric"] = True try: self.solver.parameters.preconditioner = self._solver[ "preconditioner"] except KeyError: pass # fe.info(self.solver.parameters, True) self.localization = dict() # dictionary of localization field objects, # will be filled up when calling auxiliary problems (lazy evaluation) self.ConstitutiveTensors = dict()
def __init__(self, mesh: df.Mesh, time: df.Constant, M_i: tp.Union[df.Expression, tp.Dict[int, df.Expression]], M_e: tp.Union[df.Expression, tp.Dict[int, df.Expression]], I_s: tp.Union[df.Expression, tp.Dict[int, df.Expression]] = None, I_a: tp.Union[df.Expression, tp.Dict[int, df.Expression]] = None, ect_current: tp.Dict[int, df.Expression] = None, v_: df.Function = None, cell_domains: df.MeshFunction = None, facet_domains: df.MeshFunction = None, dirichlet_bc: tp.List[tp.Tuple[df.Expression, int]] = None, dirichlet_bc_v: tp.List[tp.Tuple[df.Expression, int]] = None, periodic_domain: df.SubDomain = None, parameters: df.Parameters = None) -> None: """Initialise solverand check all parametersare correct. NB! The periodic domain has to be set in the cellsolver too. """ self._timestep = None comm = df.MPI.comm_world rank = df.MPI.rank(comm) msg = "Expecting mesh to be a Mesh instance, not {}".format(mesh) assert isinstance(mesh, df.Mesh), msg msg = "Expecting time to be a Constant instance (or None)." assert isinstance(time, df.Constant) or time is None, msg msg = "Expecting parameters to be a Parameters instance (or None)" assert isinstance(parameters, df.Parameters) or parameters is None, msg self._nullspace_basis = None # Store input self._mesh = mesh self._time = time # Initialize and update parameters if given self._parameters = self.default_parameters() if parameters is not None: self._parameters.update(parameters) if self._parameters["Chi"] == -1 or self._parameters["Cm"] == -1: raise ValueError( "Need Chi and Cm to be specified explicitly throug the parameters." ) # Set-up function spaces k = self._parameters["polynomial_degree"] Ve = df.FiniteElement("CG", self._mesh.ufl_cell(), k) V = df.FunctionSpace(self._mesh, "CG", k, constrained_domain=periodic_domain) Ue = df.FiniteElement("CG", self._mesh.ufl_cell(), k) if self._parameters["linear_solver_type"] == "direct": Re = df.FiniteElement("R", self._mesh.ufl_cell(), 0) _element = df.MixedElement((Ve, Ue, Re)) self.VUR = df.FunctionSpace(mesh, _element, constrained_domain=periodic_domain) else: _element = df.MixedElement((Ve, Ue)) self.VUR = df.FunctionSpace(mesh, _element, constrained_domain=periodic_domain) self.V = V if cell_domains is None: cell_domains = df.MeshFunction("size_t", mesh, self._mesh.geometry().dim()) cell_domains.set_all(0) # Chech that it is indeed a cell function. cell_dim = cell_domains.dim() mesh_dim = self._mesh.geometry().dim() msg = "Got {cell_dim}, expected {mesh_dim}.".format(cell_dim=cell_dim, mesh_dim=mesh_dim) assert cell_dim == mesh_dim, msg self._cell_domains = cell_domains if facet_domains is None: facet_domains = df.MeshFunction("size_t", mesh, self._mesh.geometry().dim() - 1) facet_domains.set_all(0) # Check that it is indeed a facet function. facet_dim = facet_domains.dim() msg = "Got {facet_dim}, expected {mesh_dim}.".format( facet_dim=facet_dim, mesh_dim=mesh_dim - 1) assert facet_dim == mesh_dim - 1, msg self._facet_domains = facet_domains # Gather all cell keys on all processes. Greatly simplifies things cell_keys = set(self._cell_domains.array()) all_cell_keys = comm.allgather(cell_keys) all_cell_keys = reduce(or_, all_cell_keys) # If Mi is not dict, make dict if not isinstance(M_i, dict): M_i = {int(i): M_i for i in all_cell_keys} else: # Check that the keys match the cell function M_i_keys = set(M_i.keys()) msg = "Got {M_i_keys}, expected {cell_keys}.".format( M_i_keys=M_i_keys, cell_keys=all_cell_keys) assert M_i_keys == all_cell_keys, msg # If Me is not dict, make dict if not isinstance(M_e, dict): M_e = {int(i): M_e for i in all_cell_keys} else: # Check that the keys match the cell function M_e_keys = set(M_e.keys()) msg = "Got {M_e_keys}, expected {cell_keys}.".format( M_e_keys=M_e_keys, cell_keys=all_cell_keys) assert M_e_keys == all_cell_keys, msg self._M_i = M_i self._M_e = M_e # Store source terms if I_s is not None and not isinstance(I_s, dict): I_s = {key: I_s for key in all_cell_keys} self._I_s = I_s if I_a is not None and not isinstance(I_a, dict): I_a = {key: I_a for key in all_cell_keys} self._I_a = I_a # Set the ECT current, Note, it myst depend on `time` to be updated if ect_current is not None: ect_tags = set(ect_current.keys()) facet_tags = set(self._facet_domains.array()) msg = "{} not in facet domains ({}).".format(ect_tags, facet_tags) assert ect_tags <= facet_tags, msg self._ect_current = ect_current # Set-up solution fields: if v_ is None: self.merger = df.FunctionAssigner(V, self.VUR.sub(0)) self.v_ = df.Function(V, name="v_") else: # df.debug("Experimental: v_ shipped from elsewhere.") self.merger = None self.v_ = v_ self.vur = df.Function(self.VUR, name="vur") # Set Dirichlet bcs for the transmembrane potential self._bcs = [] if dirichlet_bc_v is not None: for function, marker in dirichlet_bc_v: self._bcs.append( df.DirichletBC(self.VUR.sub(0), function, self._facet_domains, marker)) # Set Dirichlet bcs for the extra cellular potential if dirichlet_bc is not None: for function, marker in dirichlet_bc: self._bcs.append( df.DirichletBC(self.VUR.sub(1), function, self._facet_domains, marker))
def traction_test(ell=0.05, ell_e=.1, degree=1, n=3, nu=0., load_min=0, load_max=2, loads=None, nsteps=20, Lx=1., Ly=0.1, outdir="outdir", postfix='', savelag=1, sigma_D0=1., periodic=False, continuation=False, checkstability=True, configString='', test=True): # constants # ell = ell Lx = Lx load_min = load_min load_max = load_max nsteps = nsteps outdir = outdir loads = loads savelag = 1 nu = dolfin.Constant(nu) ell = dolfin.Constant(ell) ell_e = ell_e E = dolfin.Constant(1.0) K = E.values()[0] / ell_e**2. sigma_D0 = E n = n # h = ell.values()[0]/n h = max(ell.values()[0] / n, .005) cell_size = h continuation = continuation isPeriodic = periodic config = json.loads(configString) if configString != '' else '' cmd_parameters = { 'material': { "ell": ell.values()[0], "ell_e": ell_e, "K": K, "E": E.values()[0], "nu": nu.values()[0], "sigma_D0": sigma_D0.values()[0] }, 'geometry': { 'Lx': Lx, 'Ly': Ly, 'n': n, }, 'experiment': { 'test': test, 'periodic': isPeriodic, 'signature': '' }, 'stability': { 'checkstability': checkstability, 'continuation': continuation }, 'time_stepping': { 'load_min': load_min, 'load_max': load_max, 'nsteps': nsteps, 'outdir': outdir, 'postfix': postfix, 'savelag': savelag }, 'alt_min': {}, "code": {} } # -------------------- for par in parameters: parameters[par].update(cmd_parameters[par]) if config: for par in config: parameters[par].update(config[par]) # else: # parameters['material']['ell_e'] = Lx = parameters['geometry']['Lx'] Ly = parameters['geometry']['Ly'] ell = parameters['material']['ell'] ell_e = parameters['material']['ell_e'] BASE_DIR = os.path.dirname(os.path.realpath(__file__)) fname = "film" print(BASE_DIR) os.path.isfile(fname) signature = hashlib.md5(str(parameters).encode('utf-8')).hexdigest() if parameters['experiment']['test'] == True: outdir += '-{}'.format(cmd_parameters['time_stepping']['postfix']) else: outdir += '-{}{}'.format(signature, cmd_parameters['time_stepping']['postfix']) outdir = outdir + '-cont' parameters['time_stepping']['outdir'] = outdir Path(outdir).mkdir(parents=True, exist_ok=True) print('Outdir is: ' + outdir) with open(os.path.join(outdir, 'rerun.sh'), 'w') as f: configuration = deepcopy(parameters) configuration['time_stepping'].pop('outdir') str(configuration).replace("\'True\'", "True").replace("\'False\'", "False") rerun_cmd = 'python3 {} --config="{}"'.format( os.path.basename(__file__), configuration) f.write(rerun_cmd) with open(os.path.join(outdir, 'parameters.pkl'), 'w') as f: json.dump(parameters, f) with open(os.path.join(outdir, 'signature.md5'), 'w') as f: f.write(signature) print(parameters) # boundary_meshfunction = dolfin.MeshFunction("size_t", mesh, "meshes/%s-%s_facet_region.xml"%(fname, signature)) # cells_meshfunction = dolfin.MeshFunction("size_t", mesh, "meshes/%s-%s_physical_region.xml"%(fname, signature)) # ------------------ geometry_parameters = parameters['geometry'] geom_signature = hashlib.md5( str(geometry_parameters).encode('utf-8')).hexdigest() meshfile = "%s/meshes/%s-%s.xml" % (BASE_DIR, fname, geom_signature) # cmd_parameters['experiment']['signature']=signature if os.path.isfile(meshfile): print("Meshfile %s exists" % meshfile) mesh = dolfin.Mesh("meshes/%s-%s.xml" % (fname, geom_signature)) else: print("Creating meshfile: %s" % meshfile) print(('DEBUG: (-Lx/2. ={} , -Ly/2.={})'.format(Lx / 2., -Ly / 2.))) geom = mshr.Rectangle(dolfin.Point(-Lx / 2., -Ly / 2.), dolfin.Point(Lx / 2., Ly / 2.)) mesh = mshr.generate_mesh(geom, n * int(float(Lx / ell))) print(meshfile) mesh_xdmf = dolfin.XDMFFile("meshes/%s-%s.xdmf" % (fname, geom_signature)) mesh_xdmf.write(mesh) if rank == 0: meshf = dolfin.File(os.path.join(outdir, "mesh.xml")) meshf << mesh V_u = dolfin.VectorFunctionSpace(mesh, "CG", 1) V_alpha = dolfin.FunctionSpace(mesh, "CG", 1) u = dolfin.Function(V_u, name="Total displacement") alpha = dolfin.Function(V_alpha, name="Damage") bcs_alpha = [] bcs_u = [ DirichletBC(V_u, Constant((0., 0)), '(near(x[0], %f) or near(x[0], %f))' % (-Lx / 2., Lx / 2.)) ] left = dolfin.CompiledSubDomain("near(x[0], -Lx/2.)", Lx=Lx) right = dolfin.CompiledSubDomain("near(x[0], Lx/2.)", Lx=Lx) bottom = dolfin.CompiledSubDomain("near(x[1],-Ly/2.)", Ly=Ly) top = dolfin.CompiledSubDomain("near(x[1],Ly/2.)", Ly=Ly) mf = dolfin.MeshFunction("size_t", mesh, 1, 0) right.mark(mf, 1) left.mark(mf, 2) bottom.mark(mf, 3) state = [u, alpha] Z = dolfin.FunctionSpace( mesh, dolfin.MixedElement([u.ufl_element(), alpha.ufl_element()])) z = dolfin.Function(Z) v, beta = dolfin.split(z) dx = dolfin.Measure("dx", metadata=form_compiler_parameters, domain=mesh) ds = dolfin.Measure("ds", subdomain_data=mf) # Files for output file_out = dolfin.XDMFFile(os.path.join(outdir, "output.xdmf")) file_eig = dolfin.XDMFFile(os.path.join(outdir, "perturbations.xdmf")) file_con = dolfin.XDMFFile(os.path.join(outdir, "continuation.xdmf")) file_bif = dolfin.XDMFFile( os.path.join(outdir, "bifurcation_postproc.xdmf")) for f in [file_out, file_eig, file_con, file_bif]: f.parameters["functions_share_mesh"] = True f.parameters["flush_output"] = True # Problem definition foundation_density = 1. / 2. * 1. / ell_e**2. * dot(u, u) model = DamagePrestrainedElasticityModel( state, E, nu, ell, sigma_D0, user_functional=foundation_density, eps0t=Expression([['t', 0.], [0., 0.]], t=0., degree=0)) # import pdb; .set_trace() model.dx = dx model.ds = ds energy = model.total_energy_density(u, alpha) * dx # Alternate minimization solver solver = solvers.AlternateMinimizationSolver( energy, [u, alpha], [bcs_u, bcs_alpha], parameters=parameters['alt_min']) rP = model.rP(u, alpha, v, beta) * dx + 1 / ell_e**2. * dot(v, v) * dx rN = model.rN(u, alpha, beta) * dx stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, parameters=parameters['stability']) # stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, parameters = parameters['stability'], rayleigh=[rP, rN]) # if isPeriodic: # stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, # parameters = stability_parameters, # constrained_domain = PeriodicBoundary(Lx)) # else: # stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, parameters = parameters['stability']) load_steps = np.linspace(load_min, load_max, parameters['time_stepping']['nsteps']) if loads: load_steps = loads time_data = [] linesearch = LineSearch(energy, [u, alpha]) alpha_old = dolfin.Function(alpha.function_space()) lmbda_min_prev = 0.000001 bifurcated = False bifurcation_loads = [] save_current_bifurcation = False bifurc_count = 0 alpha_bif = dolfin.Function(V_alpha) alpha_bif_old = dolfin.Function(V_alpha) bifurcation_loads = [] tot_energy = model.elastic_energy_density(model.eps(u), alpha)*dx + \ 1./2.*1/ell_e**2. * dot(u, u)*dx + \ model.damage_dissipation_density(alpha)*dx cont_atol = 1e-3 for it, load in enumerate(load_steps): model.eps0t.t = load alpha_old.assign(alpha) ColorPrint.print_warn('Solving load t = {:.2f}'.format(load)) # First order stability conditions (time_data_i, am_iter) = solver.solve() # Second order stability conditions (stable, negev) = stability.solve(solver.problem_alpha.lb) ColorPrint.print_pass( 'Current state is{}stable'.format(' ' if stable else ' un')) # import pdb; pdb.set_trace() mineig = stability.mineig if hasattr(stability, 'mineig') else 0.0 # print('DEBUG: lmbda min', lmbda_min_prev) # print('DEBUG: mineig', mineig) Deltav = (mineig - lmbda_min_prev) if hasattr(stability, 'eigs') else 0 if (mineig + Deltav) * (lmbda_min_prev + dolfin.DOLFIN_EPS) < 0 and not bifurcated: bifurcated = True # save 3 bif modes print('DEBUG: About to bifurcate load ', load, 'step', it) bifurcation_loads.append(load) bifurc_count += 1 lmbda_min_prev = mineig if hasattr(stability, 'mineig') else 0. if stable: solver.update() else: # Continuation iteration = 1 energy_pre = dolfin.assemble(tot_energy) alpha_bif.assign(alpha) alpha_bif_old.assign(alpha_old) while stable == False and iteration < 30: # linesearch perturbation_v = stability.perturbation_v perturbation_beta = stability.perturbation_beta h_opt, (hmin, hmax), energy_perturbations = linesearch.search( [u, alpha, alpha_old], perturbation_v, perturbation_beta) # import pdb; pdb.set_trace() # if h_opt != 0: if h_opt > cont_atol: save_current_bifurcation = True # admissible uval = u.vector()[:] + h_opt * perturbation_v.vector()[:] aval = alpha.vector( )[:] + h_opt * perturbation_beta.vector()[:] u.vector()[:] = uval alpha.vector()[:] = aval u.vector().vec().ghostUpdate() alpha.vector().vec().ghostUpdate() (time_data_i, am_iter) = solver.solve() (stable, negev) = stability.solve(alpha_old) ColorPrint.print_pass( ' Continuation iteration #{}, current state is{}stable' .format(iteration, ' ' if stable else ' un')) energy_post = dolfin.assemble(tot_energy) ener_diff = energy_post - energy_pre ColorPrint.print_warn( 'DEBUG: step {}, iteration {}, En_post - En_pre ={}'. format(it, iteration, energy_post - energy_pre)) iteration += 1 if ener_diff < 0: bifurcated = False else: # warn ColorPrint.print_warn( 'DEBUG: Found (almost) zero increment, we are stuck in the matrix' ) ColorPrint.print_warn('DEBUG: h_opt = {}'.format(h_opt)) ColorPrint.print_warn('DEBUG: Continuing load program') break solver.update() # stable == True # modes = np.where(stability.eigs < 0)[0] # with file_bif as file: # leneigs = len(modes) # maxmodes = min(3, leneigs) # for n in range(maxmodes): # mode = dolfin.project(stability.linsearch[n]['beta_n'], V_alpha) # modename = 'beta-%d'%n # print(modename) # file.write_checkpoint(mode, modename, 0, append=True) # bifurc_count += 1 time_data_i["load"] = load time_data_i["stable"] = stable time_data_i["dissipated_energy"] = dolfin.assemble( model.damage_dissipation_density(alpha) * dx) time_data_i["foundation_energy"] = dolfin.assemble( 1. / 2. * 1 / ell_e**2. * dot(u, u) * dx) time_data_i["membrane_energy"] = dolfin.assemble( model.elastic_energy_density(model.eps(u), alpha) * dx) time_data_i["elastic_energy"] = time_data_i[ "membrane_energy"] + time_data_i["foundation_energy"] time_data_i["eigs"] = stability.eigs if hasattr(stability, 'eigs') else np.inf time_data_i["stable"] = stability.stable time_data_i["# neg ev"] = stability.negev # import pdb; pdb.set_trace() _sigma = model.stress(model.eps(u), alpha) e1 = dolfin.Constant([1, 0]) _snn = dolfin.dot(dolfin.dot(_sigma, e1), e1) time_data_i["sigma"] = 1 / Ly * dolfin.assemble(_snn * model.ds(1)) time_data_i["S(alpha)"] = dolfin.assemble(1. / (model.a(alpha)) * model.dx) time_data_i["A(alpha)"] = dolfin.assemble((model.a(alpha)) * model.dx) time_data_i["avg_alpha"] = dolfin.assemble(alpha * model.dx) ColorPrint.print_pass( "Time step {:.4g}: it {:3d}, err_alpha={:.4g}".format( time_data_i["load"], time_data_i["iterations"], time_data_i["alpha_error"])) time_data.append(time_data_i) time_data_pd = pd.DataFrame(time_data) if np.mod(it, savelag) == 0: with file_out as f: f.write(alpha, load) f.write(u, load) f.write_checkpoint(alpha, "alpha-{}".format(it), 0, append=True) # with file_bif as f: print('DEBUG: written step ', it) if save_current_bifurcation: # modes = np.where(stability.eigs < 0)[0] time_data_i['h_opt'] = h_opt time_data_i['max_h'] = hmax time_data_i['min_h'] = hmin with file_bif as file: beta0v = dolfin.project(stability.perturbation_beta, V_alpha) file.write_checkpoint(beta0v, 'beta0', bifurc_count - 1, append=True) file.write_checkpoint(alpha_bif_old, 'alpha-old', bifurc_count - 1, append=True) file.write_checkpoint(alpha_bif, 'alpha-bif', bifurc_count - 1, append=True) file.write_checkpoint(alpha, 'alpha', bifurc_count - 1, append=True) np.save(os.path.join(outdir, 'energy_perturbations'), energy_perturbations, allow_pickle=True, fix_imports=True) with file_eig as file: _v = dolfin.project( dolfin.Constant(h_opt) * perturbation_v, V_u) _beta = dolfin.project( dolfin.Constant(h_opt) * perturbation_beta, V_alpha) _v.rename('perturbation displacement', 'perturbation displacement') _beta.rename('perturbation damage', 'perturbation damage') # import pdb; pdb.set_trace() f.write(_v, load) f.write(_beta, load) file.write_checkpoint(_v, 'perturbation_v', bifurc_count - 1, append=True) file.write_checkpoint(_beta, 'perturbation_beta', bifurc_count - 1, append=True) save_current_bifurcation = False time_data_pd.to_json(os.path.join(outdir, "time_data.json")) plt.figure() plt.plot(time_data_pd["load"].values(), time_data_pd["iterations"].values(), label='its') plt.semilogy() ax = plt.gca() ax2 = ax.twinx() ax2.plot(time_data_pd["load"].values(), time_data_pd["alpha_error"].values(), 'o', c='C1', label='alpha error') plt.savefig(os.path.join(outdir, 'am.pdf')) plt.legend() plt.close() # user_postprocess_timestep(alpha, parameters, load, xresol = 100) plt.figure() dolfin.plot(alpha) plt.savefig(os.path.join(outdir, "alpha.png")) plt.figure() dolfin.plot(u, mode="displacement") plt.savefig(os.path.join(outdir, "u.png")) _nu = parameters['material']['nu'] _E = parameters['material']['E'] _w1 = parameters['material']['sigma_D0']**2. / parameters['material']['E'] tc = np.sqrt(2 * _w1 / (_E * (1. - 2. * _nu) * (1. + _nu))) if parameters['stability']['checkstability'] == 'True': pp.plot_spectrum(parameters, outdir, time_data_pd.sort_values('load'), tc) # plt.show() print(time_data_pd) print() print('Output in: ' + outdir) return time_data_pd