def getLinearVariationalForms(self, B, X): # Get the number of stage values s = B.shape[0] # Generate copies of time dependent functions self.tdfButcher = [[] for i in range(len(self.tdf))] for j in range(0, len(self.tdf)): for i in range(0, s): if self.tdf[j].__class__.__name__ == "CompiledExpression": self.tdfButcher[j].append(Expression(self.tdf[j].cppcode, t=self.tstart)) else: self.tdfButcher[j].append(self.tdf[j]) if self.n == 1: # Add differential equation L = [self.U * self.Q * dx - self.u * self.Q * dx for j in range(s - 1)] for j in range(0, s - 1): R = {} for k in range(0, len(self.tdf)): R[self.tdf[k]] = self.tdfButcher[k][j + 1] L[j] -= self.DT * B[1, 1] * replace(self.f[0], R) for i in range(0, s - 1): for j in range(0, i + 1): R = {} for k in range(0, len(self.tdf)): R[self.tdf[k]] = self.tdfButcher[k][j] L[i] -= self.DT * B[i + 1, j] * action(replace(self.f[0], R), X[j]) else: # Add differential equations L = [reduce((lambda x, y: x + y), [self.U[alpha] * self.Q[alpha] * dx - self.u[alpha] * self.Q[alpha] * dx for alpha in range(self.n - self.m)]) for i in range(s - 1)] for alpha in range(0, self.n - self.m): for i in range(s - 1): R = {} for k in range(0, len(self.tdf)): R[self.tdf[k]] = self.tdfButcher[k][i + 1] L[i] -= self.DT * B[1, 1] * replace(self.f[alpha], R) for j in range(i + 1): R = {} for k in range(0, len(self.tdf)): R[self.tdf[k]] = self.tdfButcher[k][j] L[i] -= self.DT * B[i + 1, j] * action(replace(self.f[alpha], R), X[j]) # Add algebraic equations for beta in range(self.m): for i in range(s - 1): R = {} for k in range(len(self.tdf)): R[self.tdf[k]] = self.tdfButcher[k][i + 1] L[i] += replace(self.g[beta], R) return L
def adjoint_genericmatrix_mul(self, other): out = dolfin_genericmatrix_mul(self, other) if hasattr(self, 'form') and isinstance(other, dolfin.GenericVector): if hasattr(other, 'form'): out.form = dolfin.action(self.form, other.form) elif hasattr(other, 'function'): if hasattr(other, 'function_factor'): out.form = dolfin.action(other.function_factor*self.form, other.function) else: out.form = dolfin.action(self.form, other.function) return out
def jtprod(self, x, v, apply_bcs=True, **kwargs): """Transposed-Jacobian-vector product. Evaluate matrix-vector product between the transposed of the constraint Jacobian at x and v. :parameters: :x: NumPy ``array`` or Dolfin ``Expression`` :v: Numpy ``array`` to multiply with :apply_bcs: apply boundary conditions to ``x`` prior to evaluation. If ``x`` is an ``Expression``, it must defined on the appropriate function space, by, e.g., declaring it as:: v = Expression('x[0]*sin(x[1])', element=pdenlp.function_space.ufl_element()) where ``pdenlp`` is a ``PDENPLModel`` instance. """ if self.__adjoint_jacobian is None: self.compile_adjoint_jacobian() self.assign_vector(x, apply_bcs=apply_bcs) w = Function(self.dual_function_space) w.vector()[:] = v JTop = action(self.__adjoint_jacobian, w) jtv = assemble(JTop) return jtv.array()
def derivative(self, parameter): """ Return the derivative of the residual with respect to the supplied Constant or Function. """ if not isinstance(parameter, (dolfin.Constant, dolfin.Function)): raise InvalidArgumentException( "parameter must be a Constant or Function") if self.is_linear(): if form_rank(self.__eq.lhs) == 1: if parameter is self.__x: form = self.__eq.lhs elif parameter in ufl.algorithms.extract_coefficients( self.__eq.lhs): raise NotImplementedException( "General derivative for linear variational problem with rank 1 LHS not implemented" ) else: form = ufl.form.Form([]) else: form = dolfin.action(self.__eq.lhs, self.__x) else: form = self.__eq.lhs if not is_zero_rhs(self.__eq.rhs): form -= self.__eq.rhs return derivative(form, parameter)
def M_inv_diag(self, domain = "all"): """ Returns the inverse lumped mass matrix for the vector function space. The result ist cached. .. note:: This method requires the PETSc Backend to be enabled. *Returns* :class:`dolfin.Matrix` the matrix """ if not self._M_inv_diag.has_key(domain): v = TestFunction(self.VectorFunctionSpace()) u = TrialFunction(self.VectorFunctionSpace()) mass_form = inner(v, u) * self.dx(domain) mass_action_form = action(mass_form, Constant((1.0, 1.0, 1.0))) diag = assemble(mass_action_form) as_backend_type(diag).vec().reciprocal() result = assemble(inner(v, u) * dP) result.zero() result.set_diagonal(diag) self._M_inv_diag[domain] = result return self._M_inv_diag[domain]
def test_unconstrained_newton_solver(self): L, nelem = 1, 201 mesh = dl.IntervalMesh(nelem, -L, L) Vh = dl.FunctionSpace(mesh, "CG", 2) forcing = dl.Constant(1) dirichlet_bcs = [dl.DirichletBC(Vh, dl.Constant(0.0), on_any_boundary)] bc0 = dl.DirichletBC(Vh, dl.Constant(0.0), on_any_boundary) uh = dl.TrialFunction(Vh) vh = dl.TestFunction(Vh) F = dl.inner((1 + uh**2) * dl.grad(uh), dl.grad(vh)) * dl.dx - forcing * vh * dl.dx u = dl.Function(Vh) F = dl.action(F, u) parameters = { "symmetric": True, "newton_solver": { # "relative_tolerance": 1e-8, "report": True, "linear_solver": "cg", "preconditioner": "petsc_amg" } } dl.solve(F == 0, u, dirichlet_bcs, solver_parameters=parameters) # dl.plot(uh) # plt.show() u_newton = dl.Function(Vh) F = dl.inner((1 + uh**2) * dl.grad(uh), dl.grad(vh)) * dl.dx - forcing * vh * dl.dx F = dl.action(F, u_newton) # Compute Jacobian J = dl.derivative(F, u_newton, uh) unconstrained_newton_solve( F, J, u_newton, dirichlet_bcs=dirichlet_bcs, bc0=bc0, # linear_solver='PETScLU',opts=dict()) linear_solver=None, opts=dict()) error = dl.errornorm(u, u_newton, mesh=mesh) assert error < 1e-15
def solve_molecular(self,rho_solute=const.rhom): """ Solve the molecular diffusion problem if 'solve_sol_mol' is not in the flags list this will be an instantaneous mixing problem. """ # Solve solution concentration # Diffusivity ramp = dolfin.Expression('x[0] > minR ? 100. : 1.',minR=np.log(self.Rstar)-0.5,degree=1) self.Dstar = dolfin.project(dolfin.Expression('ramp*diff_ratio*exp(-2.*x[0])',degree=1,ramp=ramp,diff_ratio=self.astar_i/self.Lewis),self.sol_V) # calculate solute flux (this is like the Stefan condition for the molecular diffusion problem Dwall = self.Dstar(self.sol_coords[self.sol_idx_wall]) self.solFlux = -(self.C_wall/Dwall)*(self.dR/self.dt) # Set the concentration for points that moved out of the grid to match the solute flux u0_c_hold = self.u0_c.vector()[:].copy() u0_c_hold[~self.sol_idx_extrapolate] = self.C_wall+self.solFlux*(np.exp(self.sol_coords[~self.sol_idx_extrapolate,0])-self.Rstar) u0_c_hold[u0_c_hold<0.]=0. self.u0_c.vector()[:] = u0_c_hold[:] # Variational Problem F_c = (self.u_s-self.u0_c)*self.v_s*dolfin.dx + \ self.dt*dolfin.inner(dolfin.grad(self.u_s), dolfin.grad(self.Dstar*self.v_s))*dolfin.dx - \ self.dt*self.solFlux*self.v_s*self.sds(1) F_c = dolfin.action(F_c,self.C) # First derivative J = dolfin.derivative(F_c, self.C, self.u_s) # handle the bounds lower = dolfin.project(dolfin.Constant(0.0),self.sol_V) upper = dolfin.project(dolfin.Constant(rho_solute),self.sol_V) # set bounds and solve snes_solver_parameters = {"nonlinear_solver": "snes", "snes_solver": {"linear_solver": "lu", "maximum_iterations": 20, "report": True, "error_on_nonconvergence": False}} problem = dolfin.NonlinearVariationalProblem(F_c, self.C, J=J) problem.set_bounds(lower, upper) solver = dolfin.NonlinearVariationalSolver(problem) solver.parameters.update(snes_solver_parameters) dolfin.info(solver.parameters, True) (iter, converged) = solver.solve() self.u0_c.assign(self.C) # Recalculate the freezing temperature self.Tf_last = self.Tf self.Tf = Tf_depression(self.C.vector()[self.sol_idx_wall,0],linear=True) # Get the updated solution properties self.rhos = dolfin.project(dolfin.Expression('C + rhow*(1.-C/rho_solute)', degree=1,C=self.C,rhow=const.rhow,rho_solute=rho_solute),self.sol_V) self.cs = dolfin.project(dolfin.Expression('ce*(C/rho_solute) + cw*(1.-C/rho_solute)', degree=1,C=self.C,cw=const.cw,ce=const.ce,rho_solute=rho_solute),self.sol_V) self.ks = dolfin.project(dolfin.Expression('ke*(C/rho_solute) + kw*(1.-C/rho_solute)', degree=1,C=self.C,kw=const.kw,ke=const.ke,rho_solute=rho_solute),self.sol_V) self.rhos_wall = self.rhos.vector()[self.sol_idx_wall] self.cs_wall = self.cs.vector()[self.sol_idx_wall] self.ks_wall = self.ks.vector()[self.sol_idx_wall]
def gaussian_distribution(mb, mu, sigma, function=None, lumping=True, nsteps=100): "Gaussian distribution via heat equation" tend = 0.5 * sigma**2 dt = Constant(tend / nsteps, name="smooth") # prepare the problem P1e = FiniteElement("CG", mb.ufl_cell(), 1) Ve = FunctionSpace(mb, P1e) u, v = TrialFunction(Ve), TestFunction(Ve) uold = Function(Ve) if lumping: # diffusion K = assemble(dt * inner(grad(u), grad(v)) * dx) # we use mass lumping to avoid negative values Md = assemble(action(u * v * dx, Constant(1.0))) # full matrix (divide my mass) M = Matrix(K) M.zero() M.set_diagonal(Md) A = M + K else: a = u * v * dx + dt * inner(grad(u), grad(v)) * dx L = uold * v * dx A = assemble(a) # initial conditions dist = function or Function(Ve) dist.vector().zero() PointSource(Ve, mu, 1.0).apply(dist.vector()) # iterations for t in range(nsteps): uold.assign(dist) if lumping: solve(A, dist.vector(), M * uold.vector()) else: b = assemble(L) solve(A, dist.vector(), b) # normalize area = assemble(dist * dx) dist.vector()[:] /= area if function is None: return dist
def assemble_lumpedmm(self): """ Assembly lumped mass matrix - plays role of identity matrix """ print("Assembling lumped mass matrix") mass_form = self.w * self.u * dx self.mass_matrix = assemble(mass_form) mass_action_form = action(mass_form, Constant(1)) self.MM_terms = assemble(mass_action_form) self.mass_matrix.zero() self.mass_matrix.set_diagonal(self.MM_terms) self.scipy_mass_matrix = toscipy(self.mass_matrix)
def action(form, coefficient): """ Wrapper for the DOLFIN action function. Correctly handles QForm s. """ if not isinstance(form, ufl.form.Form): raise InvalidArgumentException("form must be a Form") if not isinstance(coefficient, dolfin.Function): raise InvalidArgumentException("coefficient must be a Function") nform = dolfin.action(form, coefficient) if isinstance(form, QForm): return QForm(nform, quadrature_degree = form_quadrature_degree(form)) else: return nform
def J(self): """ Return the derivative of the residual with respect to x (the Jacobian). """ if self.__J is None: if self.is_linear(): form = dolfin.action(self.__eq.lhs, self.__x) else: form = self.__eq.lhs if not is_zero_rhs(self.__eq.rhs): form -= self.__eq.rhs self.__J = derivative(form, self.__x) return self.__J
def run_dolfin(): import dolfin as df x_array = np.linspace(-49.5, 49.5, 100) mesh = df.IntervalMesh(100, -50, 50) Delta = np.sqrt(A / K) xi = 2 * A / D Delta_s = Delta * 1e9 V = df.FunctionSpace(mesh, "Lagrange", 1) u = df.TrialFunction(V) v = df.TestFunction(V) u_ = df.Function(V) F = -df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx - \ (0.5 / Delta_s**2) * df.sin(2 * u) * v * df.dx F = df.action(F, u_) J = df.derivative(F, u_, u) # the boundary condition is from equation (8) theta0 = np.arcsin(Delta / xi) ss = 'x[0]<0? %g: %g ' % (-theta0, theta0) u0 = df.Expression(ss) def u0_boundary(x, on_boundary): return on_boundary bc = df.DirichletBC(V, u0, u0_boundary) problem = df.NonlinearVariationalProblem(F, u_, bcs=bc, J=J) solver = df.NonlinearVariationalSolver(problem) solver.solve() u_array = u_.vector().array() mx_df = [] for x in x_array: mx_df.append(u_(x)) return mx_df
def hprod(self, x, y, v, apply_bcs=True, **kwargs): """Hessian-vector product. Evaluate matrix-vector product between the Hessian of the Lagrangian at (x, z) and v. :parameters: :x: NumPy ``array`` or Dolfin ``Expression`` :y: Numpy ``array`` or Dolfin ``Expression`` for multipliers :v: Numpy ``array`` to multiply with :apply_bcs: apply boundary conditions to ``x`` prior to evaluation. If ``x`` is an ``Expression``, it must defined on the appropriate function space, by, e.g., declaring it as:: v = Expression('x[0]*sin(x[1])', element=pdenlp.function_space.ufl_element()) where ``pdenlp`` is a ``PDENPLModel`` instance. """ obj_weight = kwargs.get('obj_weight', 1.0) if self.__objective_hessian is None: self.compile_objective_hessian() self.assign_vector(x, apply_bcs=apply_bcs) w = Function(self.function_space) w.vector()[:] = v Hop = action(self.__objective_hessian, w) hv = obj_weight * assemble(Hop).array() if self.ncon > 0 and y is not None: if self.__constraint_jacobian is None: self.compile_constraint_jacobian() z = Function(self.__dual_function_space) z.vector()[:] = -y # ∑ⱼ yⱼ Hⱼ(u) may be viewed as the directional derivative # of J(.) with respect to u in the direction y. Hc = derivative(self.__constraint_jacobian, self.__u, z) hv += Hc * v return hv
def assemble_lumpedmm(self): """ Assembly lumped mass matrix - equal to 0 on robin boundary since there is no time derivative there. """ print("Assembling lumped mass matrix") mass_form = self.w * self.u * dx mass_action_form = action(mass_form, Constant(1)) self.MM_terms = assemble(mass_action_form) for n in self.robint_nodes_list: self.MM_terms[n] = 1.0 for n in self.robin_nodes_list: self.MM_terms[n] = 0.0 self.mass_matrix = assemble(mass_form) self.mass_matrix.zero() self.mass_matrix.set_diagonal(self.MM_terms) self.scipy_mass_matrix = toscipy(self.mass_matrix)
def setSolverParams(self, step=None): if self.eqn == "poisboltz": print("PoisBoltz") self.F = dolfin.action(self.F, self.u_s) J = dolfin.derivative(self.F, self.u_s, self.u) problem = dolfin.NonlinearVariationalProblem( self.F, self.u_s, self.bcs, J) self.solver = dolfin.NonlinearVariationalSolver(problem) prm = self.solver.parameters prm['newton_solver']['absolute_tolerance'] = self.max_abs_error prm['newton_solver']['relative_tolerance'] = self.max_rel_error prm['newton_solver']['maximum_iterations'] = 10000 prm['newton_solver']['relaxation_parameter'] = 0.1 prm['newton_solver']['report'] = True prm['newton_solver']['linear_solver'] = self.method prm['newton_solver']['preconditioner'] = self.preconditioner prm['newton_solver']['krylov_solver']['maximum_iterations'] = 10000 prm['newton_solver']['krylov_solver'][ 'absolute_tolerance'] = self.max_abs_error prm['newton_solver']['krylov_solver'][ 'relative_tolerance'] = self.max_rel_error prm['newton_solver']['krylov_solver']['monitor_convergence'] = True else: print("Separating LHS and RHS...") # Separate left and right hand sides of equation self.a, self.L = dolfin.lhs(self.F), dolfin.rhs(self.F) self.problem = dolfin.LinearVariationalProblem( self.a, self.L, self.u_s, self.bcs) self.solver = dolfin.LinearVariationalSolver(self.problem) dolfin.parameters['form_compiler']['optimize'] = True self.solver.parameters['linear_solver'] = self.method self.solver.parameters['preconditioner'] = self.preconditioner spec_param = self.solver.parameters['krylov_solver'] #These only accessible after spec_param available. if self.init_guess == "prev": if step == 0: spec_param['nonzero_initial_guess'] = False else: spec_param['nonzero_initial_guess'] = True elif self.init_guess == "zero": spec_param['nonzero_initial_guess'] = False spec_param['absolute_tolerance'] = self.max_abs_error spec_param['relative_tolerance'] = self.max_rel_error spec_param['maximum_iterations'] = self.max_linear_iters
def set_forms(self, unknown, geom_ord=[0]): """ Set up weak forms of elliptic PDE. """ if any(s >= 0 for s in geom_ord): ## forms for forward equation ## # 4. Define variational problem # functions if not hasattr(self, 'states_fwd'): self.states_fwd = df.Function(self.W) # u, l = df.split(self.states_fwd) u, l = df.TrialFunctions(self.W) v, m = df.TestFunctions(self.W) f = self._source_term(degree=2) # variational forms if 'true' in str(type(unknown)): unknown = df.interpolate(unknown, self.V) self.F = df.exp(unknown) * df.inner( df.grad(u), df.grad(v)) * df.dx + ( u * m + v * l) * self.ds - f * v * df.dx + self.nugg * l * m * df.dx # self.dFdstates = df.derivative(self.F, self.states_fwd) # Jacobian # self.a = unknown*df.inner(df.grad(u), df.grad(v))*df.dx + (u*m + v*l)*self.ds + self.nugg*l*m*df.dx # self.L = f*v*df.dx if any(s >= 1 for s in geom_ord): ## forms for adjoint equation ## # Set up the objective functional J # u,_,_ = df.split(self.states_fwd) # J_form = obj.form(u) # Compute adjoint of forward operator F2 = df.action(self.F, self.states_fwd) self.dFdstates = df.derivative( F2, self.states_fwd) # linearized forward operator args = ufl.algorithms.extract_arguments( self.dFdstates) # arguments for bookkeeping self.adj_dFdstates = df.adjoint( self.dFdstates, reordered_arguments=args ) # adjoint linearized forward operator # self.dJdstates = df.derivative(J_form, self.states_fwd, df.TestFunction(self.W)) # derivative of functional with respect to solution # self.dirac_1 = obj.ptsrc(u,1) # dirac_1 cannot be initialized here because it involves evaluation ## forms for gradient ## self.dFdunknown = df.derivative(F2, unknown) self.adj_dFdunknown = df.adjoint(self.dFdunknown)
def _assemble_and_solve_adj_eq(self, dFdu_form, dJdu): dJdu_copy = dJdu.copy() bcs = self._homogenize_bcs() solver = self.block_helper.adjoint_solver if solver is None: adj_sol = df.Function(self.function_space) adjoint_problem = pf.BlockProblem(dFdu_form, dJdu, adj_sol, bcs=bcs) for key, value in self.block_field.items(): adjoint_problem.field(key, value[1], solver=value[2]) for key, value in self.block_split.items(): adjoint_problem.split(key, value[0], solver=value[1]) solver = pf.LinearBlockSolver(adjoint_problem) self.block_helper.adjoint_solver = solver ############ ## Assemble ## rhs_bcs_form = df.inner(df.Function(self.function_space), dFdu_form.arguments()[0]) * df.dx A_, _ = df.assemble_system(dFdu_form, rhs_bcs_form, bcs) A = df.as_backend_type(A_) solver.linear_solver.set_operators(A, A) solver.linear_solver.init_solver_options() [bc.apply(dJdu) for bc in bcs] b = df.as_backend_type(dJdu) ## Actual solve ## its = solver.linear_solver.solve(adj_sol.vector(), b) ########### adj_sol_bdy = dfa.compat.function_from_vector( self.function_space, dJdu_copy - dfa.compat.assemble_adjoint_value(df.action(dFdu_form, adj_sol))) return adj_sol, adj_sol_bdy
def test_constrained_newton_energy_solver(self): L, nelem = 1, 201 mesh = dl.IntervalMesh(nelem, -L, L) Vh = dl.FunctionSpace(mesh, "CG", 2) forcing = dl.Constant(1) dirichlet_bcs = [dl.DirichletBC(Vh, dl.Constant(0.0), on_any_boundary)] bc0 = dl.DirichletBC(Vh, dl.Constant(0.0), on_any_boundary) uh = dl.TrialFunction(Vh) vh = dl.TestFunction(Vh) F = dl.inner((1 + uh**2) * dl.grad(uh), dl.grad(vh)) * dl.dx - forcing * vh * dl.dx F += uh * vh * dl.inner(dl.nabla_grad(uh), dl.nabla_grad(uh)) * dl.dx u = dl.Function(Vh) F = dl.action(F, u) parameters = { "symmetric": True, "newton_solver": { "relative_tolerance": 1e-12, "report": True, "linear_solver": "cg", "preconditioner": "petsc_amg" } } dl.solve(F == 0, u, dirichlet_bcs, solver_parameters=parameters) # dl.plot(uh) # plt.show() F = 0.5 * (1 + uh**2) * dl.inner(dl.nabla_grad(uh), dl.nabla_grad( uh)) * dl.dx - forcing * uh * dl.dx #F = dl.inner((1+uh**2)*dl.grad(uh),dl.grad(vh))*dl.dx-forcing*vh*dl.dx u_newton = dl.Function(Vh) F = dl.action(F, u_newton) constrained_newton_energy_solve(F, u_newton, dirichlet_bcs=dirichlet_bcs, bc0=bc0, linear_solver='PETScLU', opts=dict()) F = 0.5 * (1 + uh**2) * dl.inner(dl.nabla_grad(uh), dl.nabla_grad( uh)) * dl.dx - forcing * uh * dl.dx u_grad = dl.Function(Vh) F = dl.action(F, u_grad) grad = dl.derivative(F, u_grad) print(F) print(grad) parameters = { "symmetric": True, "newton_solver": { "relative_tolerance": 1e-12, "report": True, "linear_solver": "cg", "preconditioner": "petsc_amg" } } dl.solve(grad == 0, u_grad, dirichlet_bcs, solver_parameters=parameters) error1 = dl.errornorm(u_grad, u_newton, mesh=mesh) # print(error) error2 = dl.errornorm(u, u_newton, mesh=mesh) # print(error) # dl.plot(u) # dl.plot(u_newton) # dl.plot(u_grad) # plt.show() assert error1 < 1e-15 assert error2 < 1e-15
def assembleSystem(self): """Assemble the FEM system. This is only run a single time before time-stepping. The values of the coefficient fields need to be updated between time-steps """ # Loop through the entire model and composite the system of equations self.diffusors = [] # [[compartment, species, diffusivity of species],[ ...],[...]] """ Diffusors have source terms """ self.electrostatic_compartments = [] # (compartment) where electrostatic equations reside """ Has source term """ self.potentials = [] # (membrane) """ No spatial derivatives, just construct ODE """ self.channelvars = [] #(membrane, channel, ...) for compartment in self.compartments: s = 0 for species in compartment.species: if compartment.diffusivities[species] < 1e-10: continue self.diffusors.extend([ [compartment,species,compartment.diffusivities[species]] ]) s+=compartment.diffusivities[species]*abs(species.z) if s>0: self.electrostatic_compartments.extend([compartment]) # Otherwise, there are no mobile charges in the compartment # the number of potentials is the number of spatial potentials + number of membrane potentials self.numdiffusers = len(self.diffusors) self.numpoisson = len(self.electrostatic_compartments) # Functions # Reaction-diffusion type # Diffusers :numdiffusers # # Coefficient # Diffusivities self.V_np = dolfin.MixedFunctionSpace([self.v]*(self.numdiffusers)) self.V_poisson = dolfin.MixedFunctionSpace([self.v]*self.numpoisson) #self.V = self.V_diff*self.V_electro self.V = dolfin.MixedFunctionSpace([self.v]*(self.numdiffusers+self.numpoisson)) self.dofs_is = [self.V.sub(j).dofmap().dofs() for j in range(self.numdiffusers+self.numpoisson)] self.N = len(self.dofs_is[0]) self.diffusivities = [dolfin.Function(self.v) for j in range(self.numdiffusers)] self.trialfunctions = dolfin.TrialFunctions(self.V) # Trial function self.testfunctions = dolfin.TestFunctions(self.V) # test functions, one for each field self.sourcefunctions = [dolfin.Function(self.v) for j in range(self.numpoisson+self.numdiffusers)] self.permitivities = [dolfin.Function(self.v) for j in range(self.numpoisson)] # index the compartments! self.functions__ = dolfin.Function(self.V) self.np_assigner = dolfin.FunctionAssigner(self.V_np,[self.v]*self.numdiffusers) self.poisson_assigner = dolfin.FunctionAssigner(self.V_poisson,[self.v]*self.numpoisson) self.full_assigner = dolfin.FunctionAssigner(self.V,[self.v]*(self.numdiffusers+self.numpoisson)) self.prev_value__ = dolfin.Function(self.V) self.prev_value_ = dolfin.split(self.prev_value__) self.prev_value = [dolfin.Function(self.v) for j in range(self.numdiffusers+self.numpoisson)] self.vfractionfunctions = [dolfin.Function(self.v) for j in range(len(self.compartments))] # Each reaction diffusion eqn should be indexed to a single volume fraction function # Each reaction diffusion eqn should be indexed to a single potential function # Each reaction diffusion eqn should be indexed to a single valence self.dt = dolfin.Constant(0.1) self.eqs = [] self.phi = dolfin.Constant(phi) for membrane in self.membranes: self.potentials.extend([membrane]) membrane.phi_m = np.ones(self.N)*membrane.phi_m self.num_membrane_potentials = len(self.potentials) # improve this """ Assemble the equations for the system Order of equations: for compartment in compartments: for species in compartment.species diffusion (in order) volume potential for electrodiffusion Membrane potentials """ for j,compartment in enumerate(self.compartments): self.vfractionfunctions[j].vector()[:] = self.volfrac[compartment] # Set the reaction-diffusion equations for j,(trial,old,test,source,D,diffusor) in enumerate(zip(self.trialfunctions[:self.numdiffusers],self.prev_value_[:self.numdiffusers] \ ,self.testfunctions[:self.numdiffusers], self.sourcefunctions[:self.numdiffusers]\ ,self.diffusivities,self.diffusors)): """ This instance of the loop corresponds to a diffusion species in self.diffusors """ compartment_index = self.compartments.index(diffusor[0]) # we are in this compartment try: phi_index = self.electrostatic_compartments.index(diffusor[0]) + self.numdiffusers self.eqs.extend([ trial*test*dx-test*old*dx+ \ self.dt*(inner(D*nabla_grad(trial),nabla_grad(test)) + \ dolfin.Constant(diffusor[1].z/phi)*inner(D*trial*nabla_grad(self.prev_value[phi_index]),nabla_grad(test)))*dx ]) """ self.eqs.extend([ trial*test*dx-test*old*dx+ \ self.dt*(inner(D*nabla_grad(trial),nabla_grad(test)) + \ dolfin.Constant(diffusor[1].z/phi)*inner(D*trial*nabla_grad(self.prev_value[phi_index]),nabla_grad(test)) - source*test)*dx ]) """ # electrodiffusion here except ValueError: # No electrodiffusion for this species self.eqs.extend([trial*test*dx-old*test*dx+self.dt*(inner(D*nabla_grad(trial),nabla_grad(test))- source*test)*dx ]) self.prev_value[j].vector()[:] = diffusor[0].value(diffusor[1]) self.diffusivities[j].vector()[:] = diffusor[2] #diffusor[0].setValue(diffusor[1],self.prev_value[j].vector().array()) # do this below instead self.full_assigner.assign(self.prev_value__,self.prev_value) self.full_assigner.assign(self.functions__,self.prev_value) # Initial guess for Newton """ Vectorize the values that aren't already vectorized """ for compartment in self.compartments: for j,(species, val) in enumerate(compartment.values.items()): try: length = len(val) compartment.internalVars.extend([(species,self.N,j*self.N)]) compartment.species_internal_lookup[species] = j*self.N except: compartment.values[species]= np.ones(self.N)*val #compartment.internalVars.extend([(species,self.N,j*self.N)]) compartment.species_internal_lookup[species] = j*self.N # Set the electrostatic eqns # Each equation is associated with a single compartment as defined in for j,(trial, test, source, eps, compartment) in enumerate(zip(self.trialfunctions[self.numdiffusers:],self.testfunctions[self.numdiffusers:], \ self.sourcefunctions[self.numdiffusers:], self.permitivities, self.electrostatic_compartments)): # set the permitivity for this equation eps.vector()[:] = F**2*self.volfrac[compartment]/R/T \ *sum([compartment.diffusivities[species]*species.z**2*compartment.value(species) for species in compartment.species],axis=0) self.eqs.extend( [inner(eps*nabla_grad(trial),nabla_grad(test))*dx - source*test*dx] ) compartmentfluxes = self.updateSources() # """ Set indices for the "internal variables" List of tuples (compartment/membrane, num of variables) Each compartment or membrane has method getInternalVars() get_dot_InternalVars(t,values) get_jacobian_InternalVars(t,values) setInternalVars(values) The internal variables for each object are stored starting in y[obj.system_state_offset] """ self.internalVars = [] index = 0 for membrane in self.membranes: index2 = 0 for channel in membrane.channels: channeltmp = channel.getInternalVars() if channeltmp is not None: self.internalVars.extend([ (channel, len(channeltmp),index2)]) channel.system_state_offset = index+index2 channel.internalLength = len(channeltmp) index2+=len(channeltmp) tmp = membrane.getInternalVars() if tmp is not None: self.internalVars.extend( [(membrane,len(tmp),index)] ) membrane.system_state_offset = index index += len(tmp) membrane.points = self.N """ Compartments at the end, so we may reuse some computations """ for compartment in self.compartments: index2 = 0 compartment.system_state_offset = index # offset for this object in the overall state for species, value in compartment.values.items(): compartment.internalVars.extend([(species,len(compartment.value(species)),index2)]) index2 += len(value) tmp = compartment.getInternalVars() self.internalVars.extend( [(compartment,len(tmp),index)] ) index += len(tmp) compartment.points = self.N for key, val in self.volfrac.items(): self.volfrac[key] = val*np.ones(self.N) """ Solver setup below self.pdewolver is the FEM solver for the concentrations self.ode is the ODE solver for the membrane and volume fraction The ODE solve uses LSODA """ # Define the problem and the solver self.equation = sum(self.eqs) self.equation_ = dolfin.action(self.equation, self.functions__) self.J = dolfin.derivative(self.equation_,self.functions__) ffc_options = {"optimize": True, \ "eliminate_zeros": True, \ "precompute_basis_const": True, \ "precompute_ip_const": True, \ "quadrature_degree": 2} self.problem = dolfin.NonlinearVariationalProblem(self.equation_, self.functions__, None, self.J, form_compiler_parameters=ffc_options) self.pdesolver = dolfin.NonlinearVariationalSolver(self.problem) self.pdesolver.parameters['newton_solver']['absolute_tolerance'] = 1e-9 self.pdesolver.parameters['newton_solver']['relative_tolerance'] = 1e-9 """ ODE integrator here. Add ability to customize the parameters in the future """ self.t = 0.0 self.odesolver = ode(self.ode_rhs) # self.odesolver.set_integrator('lsoda', nsteps=3000, first_step=1e-6, max_step=5e-3 ) self.odesolver.set_initial_value(self.getInternalVars(),self.t) self.isAssembled = True
def Res(du): return L(du) - rho * omega**2 * r**2 # Galerkin Least Square stabilization term stb_gls = L(tu) * tau * Res(du) * df.dx # Weak form dres = r * sigma_r(du) * epsilon_r(tu) * df.dx dres = dres + sigma_theta(du) * tu * df.dx dres = dres - Fc * tu * df.dx dres = dres + 1e9 * stb_gls # residual res = df.action(dres, u) # solve df.solve(res == 0, u, bc) # displacement df.File(save_path + 'displacement.pvd') << u # 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
def add_lhs_dep(form, dep, x): add_rhs_dep(dolfin.action(-form, x), dep, x) return
def comp_axisymmetric_dirichlet(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 cell_markers, facet_markers = define_markers(mesh, Rext, Rint) # rename x[0], x[1] by x, y x, y = df.SpatialCoordinate(mesh) dim = mesh.topology().dim() coord = mesh.coordinates() # Create mesh and define function space V = df.FunctionSpace(mesh, "CG", 1) # Define boundary condition (homogeneous BC) u0 = df.Constant(0.0) if bc == 'CC': bc = [df.DirichletBC(V, u0, facet_markers, i) for i in [1, 2]] elif bc == 'CF': bc = df.DirichletBC(V, u0, facet_markers, 2) # Define variational problem du = df.TrialFunction(V) tu = df.TestFunction(V) # displacement in radial direction u(x,y) u = df.Function(V, name='displacement') 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)) #define centrifugal force vector form Fc = rho * omega**2 * r**2 # Weak form dres = r * sigma_r(du) * epsilon_r(tu) * df.dx dres = dres + sigma_theta(du) * tu * df.dx dres = dres - Fc * tu * df.dx # residual res = df.action(dres, u) # solve df.solve(res == 0, u, bc) # displacement df.File(save_path + 'displacement.pvd') << u # 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 # save results to h5 rfile = df.HDF5File(mesh.mpi_comm(), save_path + 'results.h5', "w") rfile.write(u, "u") rfile.write(sigma_r_pro, "sigma_r") rfile.write(sigma_theta_pro, "sigma_theta") rfile.write(von_stress_pro, "von_mises_stress") rfile.close() ''' # Load solution U = df.Function(V) Sig_r = df.Function(V) Sig_theta = df.Function(V) Vm_stress = df.Function(V) input_file = df.HDF5File(mesh.mpi_comm(), save_path + 'results.h5', "r") input_file.read(U, "u") input_file.read(Sig_r, "sigma_r") input_file.read(Sig_theta, "sigma_theta") input_file.read(Vm_stress, "von_mises_stress") input_file.close() ''' return
def comp_full_model_heat_dirichlet(mat_obj, mesh_obj, bc, omega, save_path): # ====== # Parameters # ====== E = mat_obj.E rho = mat_obj.rho nu = mat_obj.nu mesh = mesh_obj.create() Rext = mesh_obj.Rext Rint = mesh_obj.Rint G = 1 # FAKE # ====== # Thermal load # ====== alpha = 1 T = 1 # ====== # Thickness profile # ====== h = 1 omega_velo = 1 #Fake # ====== # markers # ====== cell_markers, facet_markers = define_markers(mesh, Rext, Rint) # rename x[0], x[1] by x, y x, y = df.SpatialCoordinate(mesh) dim = mesh.topology().dim() coord = mesh.coordinates() # ====== # Create function space # ====== V = df.FunctionSpace(mesh, "CG", 1) degree = 1 fi_ele = FiniteElement("CG", mesh.ufl_cell(), degree) # CG: Continuous Galerkin vec_ele = VectorElement("CG", mesh.ufl_cell(), degree) total_ele = MixedElement([fi_ele, fi_ele]) W = df.FunctionSpace(mesh, total_ele) # ====== # Define boundary condition # ====== if bc == 'CC': u_Dbc = [ df.DirichletBC(W.sub(0), df.Constant(0.0), facet_markers, bc) for bc in [1, 2] ] v_Dbc = [ df.DirichletBC(W.sub(1), df.Constant(0.0), facet_markers, bc) for bc in [1, 2] ] elif bc == 'CF': u_Dbc = [ df.DirichletBC(W.sub(0), df.Constant(0.0), facet_markers, bc) for bc in [2] ] v_Dbc = [ df.DirichletBC(W.sub(1), df.Constant(0.0), facet_markers, bc) for bc in [2] ] Dbc = u_Dbc + v_Dbc # ====== # Define functions # ====== dunks = df.TrialFunction(W) tunks = df.TestFunction(W) unks = df.Function(W, name='displacement') # u(x,y): displacement in radial direction # v(x,y): displacement in tangential direction (du, dv) = df.split(dunks) (tu, tv) = df.split(tunks) (u, v) = df.split(unks) # ====== # Define variable # ====== 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) # ====== # Define week form # ====== def d_dr(du): return 1.0 / r * (x * df.Dx(du, 0) + y * df.Dx(du, 1)) def d_dtheta(du): return -y * df.Dx(du, 0) + x * df.Dx(du, 1) # strain radial def epsilon_r(du): return d_dr(du) # strain circumferential def epsilon_theta(du, dv): return du / r + 1.0 / r * d_dtheta(dv) # shear srain component def gamma_rtheta(du, dv): return d_dr(dv) - dv / r + 1.0 / r * d_dtheta(du) epsilon_r(du) epsilon_theta(du, dv) gamma_rtheta(du, dv) ''' S = [[1.0/E, -nu/E, 0.0], [-nu/E, 1.0/E, 0.0], [0.0, 0.0, 1.0/G]] C = df.inv(df.as_matrix(S)) eps_vector = df.as_vector([epsilon_r(du), epsilon_theta(du, dv), gamma_rtheta(du, dv)]) sig_vector = dot(C, eps_vector) ''' def sigma_r(du, dv): return E / (1.0 - nu**2) * ((epsilon_r(du) - alpha * T) + nu * (epsilon_theta(du, dv) - alpha * T)) def sigma_theta(du, dv): return E / (1.0 - nu**2) * ((epsilon_theta(du, dv) - alpha * T) + nu * (epsilon_r(du) - alpha * T)) def tau_rtheta(du, dv): return G * gamma_rtheta(du, dv) # week form dF_sigma = -sigma_r(du, dv) * h * r * d_dr(tu) * dx dF_sigma = dF_sigma - tau_rtheta(du, dv) * h * d_dtheta(tu) * dx dF_sigma = dF_sigma - sigma_theta(du, dv) * h * tu * dx dF_sigma = dF_sigma + rho * omega**2 * r**2 * h * tu * dx dF_tau = -tau_rtheta(du, dv) * h * r * d_dr(tv) * dx dF_tau = dF_tau - sigma_theta(du, dv) * h * d_dtheta(tv) * dx dF_tau = dF_tau + tau_rtheta(du, dv) * h * tv * dx dF_tau = dF_tau + rho * omega_velo * r**2 * h * tv * dx dF = dF_sigma + dF_tau # residual F = df.action(dF, unks) # solve df.solve(F == 0, unks, Dbc) # splits solution _u, _v = unks.split(True) # displacement df.File(save_path + 'u.pvd') << _u df.File(save_path + 'v.pvd') << _v # ====== # Analyze # ====== # compute stresses sigma_r_pro = df.project(sigma_r(_u, _v), 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), 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, _v), sigma_theta(_u, _v)), V) von_stress_pro.rename('von Mises Stress [Pa]', 'von Mises Stress [Pa]') df.File(save_path + 'von_mises_stress.pvd') << von_stress_pro tau_rtheta_pro = df.project(tau_rtheta(_u, _v), V) tau_rtheta_pro.rename('tau_rtheta [Pa]', 'tau_rtheta [Pa]') df.File(save_path + 'tau_rtheta.pvd') << tau_rtheta_pro # save results to h5 rfile = df.HDF5File(mesh.mpi_comm(), save_path + 'results.h5', "w") rfile.write(_u, "u") rfile.write(_v, "v") rfile.write(sigma_r_pro, "sigma_r") rfile.write(sigma_theta_pro, "sigma_theta") rfile.write(von_stress_pro, "von_mises_stress") rfile.write(tau_rtheta_pro, "tau_rtheta_pro") rfile.close()
def test_prb88_184422(): mu0 = 4 * np.pi * 1e-7 Ms = 8.6e5 A = 16e-12 D = 3.6e-3 K = 510e3 mesh = CuboidMesh(nx=100, dx=1, unit_length=1e-9) sim = Sim(mesh) sim.driver.set_tols(rtol=1e-10, atol=1e-14) sim.driver.alpha = 0.5 sim.driver.gamma = 2.211e5 sim.Ms = Ms sim.do_precession = False sim.set_m((0, 0, 1)) sim.add(UniformExchange(A)) sim.add(DMI(-D, type='interfacial')) sim.add(UniaxialAnisotropy(K, axis=(0, 0, 1))) sim.relax(dt=1e-13, stopping_dmdt=0.01, max_steps=5000, save_m_steps=None, save_vtk_steps=50) m = sim.spin mx, my, mz = np.split(m, 3) x_array = np.linspace(-49.5, 49.5, 100) #plt.plot(x_array, mx) #plt.plot(x_array, my) #plt.plot(x_array, mz) mesh = df.IntervalMesh(100, -50, 50) Delta = np.sqrt(A / K) xi = 2 * A / D Delta_s = Delta * 1e9 V = df.FunctionSpace(mesh, "Lagrange", 1) u = df.TrialFunction(V) v = df.TestFunction(V) u_ = df.Function(V) F = -df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx - \ (0.5 / Delta_s**2) * df.sin(2 * u) * v * df.dx F = df.action(F, u_) J = df.derivative(F, u_, u) # the boundary condition is from equation (8) theta0 = np.arcsin(Delta / xi) ss = 'x[0]<0? %g: %g ' % (-theta0, theta0) u0 = df.Expression(ss) def u0_boundary(x, on_boundary): return on_boundary bc = df.DirichletBC(V, u0, u0_boundary) problem = df.NonlinearVariationalProblem(F, u_, bcs=bc, J=J) solver = df.NonlinearVariationalSolver(problem) solver.solve() u_array = u_.vector().array() mx_df = [] for x in x_array: mx_df.append(u_(x)) #plt.plot(x_array, mx_df) assert abs(np.max(mx - mx_df)) < 0.05
def steepest_descent(): o_u = [File("output/u_mesh%d.pvd" % i) for i in range(solver.N)] search = moola.linesearch.ArmijoLineSearch(start_stp=1) outmesh = File("output/steepest.pvd") extra_opts = 0 r_step = 8 max_it = 3 * r_step opts = 0 rel_tol = 1e-4 solver.solve() solver.eval_J() plot(solver.multimesh.part(1), color=colors[0], linewidth=0.75, zorder=0) b_mesh = BoundaryMesh(solver.multimesh.part(1), "exterior", True) plot(b_mesh, color=colors[0], linestyle="None", markersize=1, marker=markers[0], label="Iteration {}".format(0), zorder=1) J_it = [solver.J] J_i = J_it[0] i = 1 while i <= max_it: outmesh << solver.multimesh.part(1) for k in range(solver.N): o_u[k] << solver.u.part(k) print("-" * 10) print("It: {0:1d}, J: {1:.5f}".format(i, J_it[-1])) solver.recompute_dJ() solver.generate_mesh_deformation() #solver.generate_H1_deformation() dJ_i = 0 for j in range(1, solver.N): dJ_i += assemble( action(solver.dJ_form[j - 1], solver.deformation[j - 1])) print("Gradient at current iteration {0:.2e}".format(dJ_i)) def J_steepest(step): solver.update_multimesh(step) solver.solve() solver.eval_J() solver.get_checkpoint() return float(solver.J) def dJ0_steepest(): return float(J_it[-1]), dJ_i def increase_opt_number(): solver.vfac *= 2 solver.bfac *= 2 if opts < extra_opts: return True else: print("{0:d} optimizations done, exiting".format(opts + 1)) return False try: step_a = search.search(J_steepest, None, dJ0_steepest()) print( "Linesearch found decreasing step: {0:.2e}".format(step_a)) # Backup in case step is too large backup_coordinates = [ solver.multimesh.part(k).coordinates().copy() for k in range(1, solver.N) ] solver.update_multimesh(step_a) solver.set_checkpoint() solver.solve() solver.eval_J() J_it.append(solver.J) J_i = J_it[-1] if J_i > 0: if i % r_step == 0: print("Increasing volume and barycenter penalty") solver.vfac *= 2 solver.bfac *= 2 solver.eval_J() J_it.append(solver.J) if i % r_step == 0: b_mesh = BoundaryMesh(solver.multimesh.part(1), "exterior", True) plot(b_mesh, color=colors[i // r_step], linestyle="None", markersize=1, marker=markers[i // r_step], label="Iteration {}".format(i), zorder=i // r_step + 2) i += 1 search.start_stp = 1 else: # If Armjio linesearch returns an unfeasible # functional value, literally deforming too much. # We know that J in our problem has to be positive # Decrease initial stepsize and retry search.start_stp = 0.5 * step_a for k in range(1, solver.N): solver.multimesh.part( k).coordinates()[:] = backup_coordinates[k - 1] solver.multimesh.build() for key in solver.cover_points.keys(): solver.multimesh.auto_cover(key, solver.cover_points[key]) solver.set_checkpoint() solver.solve() solver.eval_J() J_it[-1] = solver.J rel_reduction = abs(J_it[-1] - J_it[-2]) / abs(J_it[-2]) if rel_reduction < rel_tol and solver.move_norm < rel_tol: raise ValueError( "Relative reduction less than {0:1e1}".format(rel_tol)) except Warning: print("Linesearch could not find descent direction") print("Restart with stricter penalty") print("*" * 15) if not increase_opt_number(): break else: # Reset linesearch opts += 1 # In new optimization run, the deformed geometry # should not have a higher functional value than the first # iteration J_i = J_it[0] except ValueError: print("Stopping criteria met") print("abs((J_k-J_k-1)/J_k)={0:.2e}<{1:.2e}".format( rel_reduction, rel_tol)) print("L^2(Gamma)(s)={0:.2e}<{1:.2e}".format( solver.move_norm, rel_tol)) print("Increase volume and barycenter penalty") print("*" * 15) if not increase_opt_number(): break else: opts += 1 solver.solve() solver.eval_J() print("V_r {0:.2e}, Bx_r {1:.2e}, By_r {2:.2e}".format( float(solver.Voloff / solver.Vol0), float(solver.bxoff / solver.bx0), float(solver.byoff / solver.by0))) J_i = solver.J # Old solution with new penalization print("V_r {0:.2e}, Bx_r {1:.2e}, By_r {2:.2e}".format( float(solver.Voloff / solver.Vol0) * 100, float(solver.bxoff / solver.bx0) * 100, float(solver.byoff / solver.by0) * 100)) plot(solver.multimesh.part(1), zorder=2, color=colors[i // r_step], linewidth=1) plt.legend(prop={'size': 10}, markerscale=2) manager = plt.get_current_fig_manager() plt.tight_layout() manager.resize(*manager.window.maxsize()) plt.axis("off") plt.savefig("StokesRugbyMeshes.png", dpi=300) import os os.system("convert StokesRugbyMeshes.png -trim StokesRugbyMeshes.png")
def test_prb88_184422(): mu0 = 4 * np.pi * 1e-7 Ms = 8.6e5 A = 16e-12 D = 3.6e-3 K = 510e3 mesh = CuboidMesh(nx=100, dx=1, unit_length=1e-9) sim = Sim(mesh) sim.driver.set_tols(rtol=1e-10, atol=1e-14) sim.driver.alpha = 0.5 sim.driver.gamma = 2.211e5 sim.Ms = Ms sim.do_precession = False sim.set_m((0, 0, 1)) sim.add(UniformExchange(A=A)) sim.add(DMI(-D, type='interfacial')) sim.add(UniaxialAnisotropy(K, axis=(0, 0, 1))) sim.relax(dt=1e-13, stopping_dmdt=0.01, max_steps=5000, save_m_steps=None, save_vtk_steps=50) m = sim.spin mx, my, mz = np.split(m, 3) x_array = np.linspace(-49.5, 49.5, 100) #plt.plot(x_array, mx) #plt.plot(x_array, my) #plt.plot(x_array, mz) mesh = df.IntervalMesh(100, -50, 50) Delta = np.sqrt(A / K) xi = 2 * A / D Delta_s = Delta * 1e9 V = df.FunctionSpace(mesh, "Lagrange", 1) u = df.TrialFunction(V) v = df.TestFunction(V) u_ = df.Function(V) F = -df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx - \ (0.5 / Delta_s**2) * df.sin(2 * u) * v * df.dx F = df.action(F, u_) J = df.derivative(F, u_, u) # the boundary condition is from equation (8) theta0 = np.arcsin(Delta / xi) ss = 'x[0]<0? %g: %g ' % (-theta0, theta0) u0 = df.Expression(ss) def u0_boundary(x, on_boundary): return on_boundary bc = df.DirichletBC(V, u0, u0_boundary) problem = df.NonlinearVariationalProblem(F, u_, bcs=bc, J=J) solver = df.NonlinearVariationalSolver(problem) solver.solve() u_array = u_.vector().array() mx_df = [] for x in x_array: mx_df.append(u_(x)) #plt.plot(x_array, mx_df) assert abs(np.max(mx - mx_df)) < 0.05
def __init__(self, f_solves_a, f_solves_b, a_map): if not isinstance(f_solves_a, list): raise InvalidArgumentException("f_solves_a must be a list of AssignmentSolver s or EquationSolver s") for f_solve in f_solves_a: if not isinstance(f_solve, (AssignmentSolver, EquationSolver)): raise InvalidArgumentException("f_solves_a must be a list of AssignmentSolver s or EquationSolver s") if not isinstance(f_solves_b, list): raise InvalidArgumentException("f_solves_b must be a list of AssignmentSolver s or EquationSolver s") for f_solve in f_solves_b: if not isinstance(f_solve, (AssignmentSolver, EquationSolver)): raise InvalidArgumentException("f_solves_b must be a list of AssignmentSolver s or EquationSolver s") if not isinstance(a_map, AdjointVariableMap): raise InvalidArgumentException("a_map must be an AdjointVariableMap") # Reverse causality f_solves_a = copy.copy(f_solves_a); f_solves_a.reverse() f_solves_b = copy.copy(f_solves_b); f_solves_b.reverse() la_a_forms = [] la_x = [] la_L_forms = [] la_L_as = [] la_bcs = [] la_solver_parameters = [] la_pre_assembly_parameters = [] la_keys = {} # Create an adjoint solve for each forward solve in f_solves_a, and add # the adjoint LHS for f_solve in f_solves_a: f_x = f_solve.x() a_x = a_map[f_x] a_space = a_x.function_space() assert(not a_x in la_keys) if isinstance(f_solve, AssignmentSolver): la_a_forms.append(None) la_bcs.append([]) la_solver_parameters.append(None) la_pre_assembly_parameters.append(dolfin.parameters["timestepping"]["pre_assembly"].copy()) else: assert(isinstance(f_solve, EquationSolver)) f_a = f_solve.tangent_linear()[0] f_a_rank = form_rank(f_a) if f_a_rank == 2: a_test, a_trial = dolfin.TestFunction(a_space), dolfin.TrialFunction(a_space) a_a = adjoint(f_a, adjoint_arguments = (a_test, a_trial)) la_a_forms.append(a_a) la_bcs.append(f_solve.hbcs()) la_solver_parameters.append(copy.deepcopy(f_solve.adjoint_solver_parameters())) else: assert(f_a_rank == 1) a_a = f_a la_a_forms.append(a_a) la_bcs.append(f_solve.hbcs()) la_solver_parameters.append(None) la_pre_assembly_parameters.append(f_solve.pre_assembly_parameters().copy()) la_x.append(a_x) la_L_forms.append(None) la_L_as.append([]) la_keys[a_x] = len(la_x) - 1 # Add adjoint RHS terms corresponding to terms in each forward solve in # f_solves_a and f_solves_b for f_solve in f_solves_a + f_solves_b: f_x = f_solve.x() a_dep = a_map[f_x] if isinstance(f_solve, AssignmentSolver): f_rhs = f_solve.rhs() if isinstance(f_rhs, ufl.core.expr.Expr): # Adjoin an expression assignment RHS for f_dep in ufl.algorithms.extract_coefficients(f_rhs): if isinstance(f_dep, dolfin.Function): a_x = a_map[f_dep] a_rhs = differentiate_expr(f_rhs, f_dep) * a_dep if a_x in la_keys and not isinstance(a_rhs, ufl.constantvalue.Zero): la_L_as[la_keys[a_x]].append(a_rhs) else: # Adjoin a linear combination assignment RHS for alpha, f_dep in f_rhs: a_x = a_map[f_dep] if a_x in la_keys: la_L_as[la_keys[a_x]].append((alpha, a_dep)) else: # Adjoin an equation RHS assert(isinstance(f_solve, EquationSolver)) a_trial = dolfin.TrialFunction(a_dep.function_space()) f_a_od = f_solve.tangent_linear()[1] for f_dep in f_a_od: a_x = a_map[f_dep] if a_x in la_keys: a_test = dolfin.TestFunction(a_x.function_space()) a_key = la_keys[a_x] a_form = -dolfin.action(adjoint(f_a_od[f_dep], adjoint_arguments = (a_test, a_trial)), a_dep) if la_L_forms[a_key] is None: la_L_forms[a_key] = a_form else: la_L_forms[a_key] += a_form self.__a_map = a_map self.__a_a_forms = la_a_forms self.__a_x = la_x self.__a_L_forms = la_L_forms self.__a_L_as = la_L_as self.__a_bcs = la_bcs self.__a_solver_parameters = la_solver_parameters self.__a_pre_assembly_parameters = la_pre_assembly_parameters self.__a_keys = la_keys self.__functional = None self.reassemble() return
def comp_axisymmetric_heat_dirichlet(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 G = 1 # FAKE # ====== # Thermal load # ====== alpha = 1 T = 1 # ====== # Thickness profile # ====== h = 1 # ====== # markers # ====== cell_markers, facet_markers = define_markers(mesh, Rext, Rint) # rename x[0], x[1] by x, y x, y = df.SpatialCoordinate(mesh) dim = mesh.topology().dim() coord = mesh.coordinates() # ====== # Create function space # ====== # Create mesh and define function space V = df.FunctionSpace(mesh, "CG", 1) # Define boundary condition (homogeneous BC) u0 = df.Constant(0.0) if bc == 'CC': bc = [df.DirichletBC(V, u0, facet_markers, i) for i in [1, 2]] elif bc == 'CF': bc = df.DirichletBC(V, u0, facet_markers, 2) # Define variational problem du = df.TrialFunction(V) tu = df.TestFunction(V) # displacement in radial direction u(x,y) u = df.Function(V, name='displacement') 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) # ====== # Define week form # ====== def d_dr(du): return 1.0 / r * (x * df.Dx(du, 0) + y * df.Dx(du, 1)) def d_dtheta(du): return -y * df.Dx(du, 0) + x * df.Dx(du, 1) # strain radial def epsilon_r(du): return d_dr(du) # strain circumferential def epsilon_theta(du): return du / r def sigma_r(du): return E / (1.0 - nu**2) * ((epsilon_r(du) - alpha * T) + nu * (epsilon_theta(du) - alpha * T)) def sigma_theta(du): return E / (1.0 - nu**2) * ((epsilon_theta(du) - alpha * T) + nu * (epsilon_r(du) - alpha * T)) # week form dF = -sigma_r(du) * r * h * epsilon_r(tu) * df.dx dF = -dF + sigma_theta(du) * h * tu * df.dx dF = dF + rho * omega**2 * r**2 * h * tu * df.dx # residual F = df.action(dF, u) # solve df.solve(F == 0, u, bc) # displacement df.File(save_path + 'u.pvd') << _u # ====== # Analyze # ====== # 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 # save results to h5 rfile = df.HDF5File(mesh.mpi_comm(), save_path + 'results.h5', "w") rfile.write(u, "u") rfile.write(sigma_r_pro, "sigma_r") rfile.write(sigma_theta_pro, "sigma_theta") rfile.write(von_stress_pro, "von_mises_stress") rfile.close()