def runNextStep(self): self.coupled_problem = df.NonlinearVariationalProblem(self.R, self.U, bcs=[self.dbc0, self.dbc1, self.dbc3], J=self.J) self.coupled_problem.set_bounds(self.l_bound, self.u_bound) self.coupled_solver = df.NonlinearVariationalSolver(self.coupled_problem) # Optimizations in fenics optimizations set_solver_options(self.coupled_solver) try: self.coupled_solver.solve(set_solver_options()) except: self.coupled_solver.parameters['snes_solver']['error_on_nonconvergence'] = False self.assigner.assign(self.U, [self.zero_sol, self.zero_sol, self.H0]) self.coupled_solver.solve() self.coupled_solver.parameters['snes_solver']['error_on_nonconvergence'] = True self.assigner_inv.assign([self.un, self.u2n, self.H0], self.U) self.times.append(self.t) self.BB.append(df.project(self.strs.B).compute_vertex_values()) self.HH.append(self.strs.H0.compute_vertex_values()) self.TD.append(df.project(self.strs.tau_d_plot).compute_vertex_values()) self.TB.append(df.project(self.strs.tau_b_plot).compute_vertex_values()) self.TX.append(df.project(self.strs.tau_xx_plot).compute_vertex_values()) self.TY.append(df.project(self.strs.tau_xy_plot).compute_vertex_values()) self.TZ.append(df.project(self.strs.tau_xz_plot).compute_vertex_values()) self.us.append(df.project(self.strs.u(0)).compute_vertex_values()) self.ub.append(df.project(self.strs.u(1)).compute_vertex_values()) self.t += self.dtFloat return self.BB[-1], self.HH[-1], self.TD[-1], self.TB[-1], self.TX[-1], self.TY[-1], self.TZ[-1], self.us[-1], \ self.ub[-1]
def setup_NSPFEC(w_NSPFEC, w_1NSPFEC, bcs_NSPFEC, trial_func_NSPFEC, v, q, psi, h, b, U, u_, p_, phi_, g_, c_, V_, u_1, p_1, phi_1, g_1, c_1, V_1, M_, nu_, veps_, rho_, K_, rho_e_, M_1, nu_1, veps_1, rho_1, K_1, rho_e_1, dbeta, dveps, drho, per_tau, sigma_bar, eps, grav, z, enable_NS, enable_PF, enable_EC, use_iterative_solvers): """ The full problem of electrohydrodynamics in two pahase. Note that it is possioble to trun off the dirffent parts at will. """ F_imp = NSPFEC_action(u_, u_1, phi_, phi_1, c_, c_1, u_, p_, phi_, g_, c_, V_, v, q, psi, h, b, U, rho_, M_, nu_, rho_e_, K_, veps_, drho, grav, sigma_bar, eps, dveps, dbeta, z, per_tau, enable_NS, enable_PF, enable_EC) F_exp = NSPFEC_action(u_, u_1, phi_, phi_1, c_, c_1, u_1, p_1, phi_1, g_1, c_1, V_1, v, q, psi, h, b, U, rho_1, M_1, nu_1, rho_e_1, K_1, veps_1, drho, grav, sigma_bar, eps, dveps, dbeta, z, per_tau, enable_NS, enable_PF, enable_EC) F = 0.5 * (F_imp + F_exp) J = df.derivative(F, w_NSPFEC) problem_NSPFEC = df.NonlinearVariationalProblem(F, w_NSPFEC, bcs_NSPFEC, J) solver_NSPFEC = df.NonlinearVariationalSolver(problem_NSPFEC) if use_iterative_solvers: solver_NSPFEC.parameters['newton_solver']['linear_solver'] = 'gmres' solver_NSPFEC.parameters['newton_solver']['preconditioner'] = 'ilu' return solver_NSPFEC
def equilibrium_EC(w_, test_functions, solutes, permittivity, dx, ds, normal, dirichlet_bcs, neumann_bcs, boundary_to_mark, use_iterative_solvers, V_lagrange, **namespace): """ Electrochemistry equilibrium solver. Nonlinear! """ num_solutes = len(solutes) cV = df.split(w_["EC"]) c, V = cV[:num_solutes], cV[num_solutes] if V_lagrange: V0 = cV[-1] b = test_functions["EC"][:num_solutes] U = test_functions["EC"][num_solutes] if V_lagrange: U0 = test_functions["EC"][-1] z = [] # Charge z[species] K = [] # Diffusivity K[species] for solute in solutes: z.append(solute[1]) K.append(solute[2]) rho_e = sum([c_e*z_e for c_e, z_e in zip(c, z)]) veps = permittivity[0] F_c = [] for ci, bi, Ki, zi in zip(c, b, K, z): grad_g_ci = df.grad(alpha_c(ci) + zi*V) F_ci = Ki*max_value(ci, 0.)*df.dot(grad_g_ci, df.grad(bi))*dx F_c.append(F_ci) F_V = veps*df.dot(df.grad(V), df.grad(U))*dx for boundary_name, sigma_e in neumann_bcs["V"].iteritems(): F_V += -sigma_e*U*ds(boundary_to_mark[boundary_name]) if rho_e != 0: F_V += -rho_e*U*dx if V_lagrange: F_V += veps*V0*U*dx + veps*V*U0*dx F = sum(F_c) + F_V J = df.derivative(F, w_["EC"]) problem = df.NonlinearVariationalProblem(F, w_["EC"], dirichlet_bcs["EC"], J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"]["relative_tolerance"] = 1e-7 if use_iterative_solvers: solver.parameters["newton_solver"]["linear_solver"] = "bicgstab" if not V_lagrange: solver.parameters["newton_solver"]["preconditioner"] = "hypre_amg" solver.solve()
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 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 get_solver(self, bcs): df.parameters["form_compiler"]["quadrature_degree"] = 2 v = df.TestFunction(self.W) F = df.inner(self.eps(v), (1.0 - omega(self.kappa())) * self.sigma()) * df.dx J = df.derivative(F, self.d) problem = df.NonlinearVariationalProblem(F, self.d, bcs, J=J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["nonlinear_solver"] = "snes" solver.parameters["symmetric"] = True solver.parameters["snes_solver"]["error_on_nonconvergence"] = False solver.parameters["snes_solver"]["line_search"] = "bt" solver.parameters["snes_solver"]["linear_solver"] = "mumps" solver.parameters["snes_solver"]["maximum_iterations"] = 10 solver.parameters["snes_solver"]["report"] = False return solver
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 solve_system(self, rhs, factor, u0, t): """ Dolfin's linear solver for (M-factor*A)u = rhs Args: rhs (dtype_f): right-hand side for the nonlinear system factor (float): abbrev. for the node-to-node stepsize (or any other factor required) u0 (dtype_u): initial guess for the iterative solver (not used here so far) t (float): current time Returns: dtype_u: solution as mesh """ sol = self.dtype_u(self.V) self.w.assign(sol.values) # fixme: is this really necessary to do each time? q1, q2 = df.TestFunctions(self.V) w1, w2 = df.split(self.w) r1, r2 = df.split(rhs.values) F1 = w1 * q1 * df.dx - factor * self.F1 - r1 * q1 * df.dx F2 = w2 * q2 * df.dx - factor * self.F2 - r2 * q2 * df.dx F = F1 + F2 du = df.TrialFunction(self.V) J = df.derivative(F, self.w, du) problem = df.NonlinearVariationalProblem(F, self.w, [], J) solver = df.NonlinearVariationalSolver(problem) prm = solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-09 prm['newton_solver']['relative_tolerance'] = 1E-08 prm['newton_solver']['maximum_iterations'] = 100 prm['newton_solver']['relaxation_parameter'] = 1.0 solver.solve() sol.values.assign(self.w) return sol
def setup_PFEC(w_PF, phi, g, psi, h, dx, ds, dirichlet_bcs_PF, neumann_bcs, boundary_to_mark, phi_1, u_1, M_, M_1, c_1, V_1, rho_1, dt, sigma_bar, eps, drho, dbeta, dveps, grav, enable_NS, enable_EC, use_iterative_solvers, **namespace): """ Set up phase field subproblem. """ # Projected velocity (for energy stability) if enable_NS: u_proj = u_1 #- dt*phi_1*df.grad(g)/rho_1 F_phi = (1. / dt * (phi - phi_1) * psi * dx + M_1 * df.dot(df.grad(g), df.grad(psi)) * dx) if enable_NS: F_phi += -phi_1 * df.dot(u_proj, df.grad(psi)) * dx F_g = (g * h * dx - sigma_bar * eps * df.dot(df.grad(phi), df.grad(h)) * dx - sigma_bar / eps * (diff_pf_potential_c(phi) - diff_pf_potential_e(phi_1)) * h * dx) # Add gravity # F_g += drho * df.dot(grav, x) * h * dx if enable_EC: F_g += (-sum( [dbeta_i * ci_1 * h * dx for dbeta_i, ci_1 in zip(dbeta, c_1)]) + 0.5 * dveps * df.dot(df.grad(V_1), df.grad(V_1)) * h * dx) F = F_phi + F_g # a, L = df.lhs(F), df.rhs(F) J = df.derivative(F, w_PF) problem = df.NonlinearVariationalProblem(F, w_PF, dirichlet_bcs_PF, J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"]["relative_tolerance"] = 1e-5 if use_iterative_solvers: solver.parameters["newton_solver"][ "linear_solver"] = "bicgstab" # "gmres" solver.parameters["newton_solver"]["preconditioner"] = "jacobi" #"amg" # solver.parameters["preconditioner"] = "hypre_euclid" return solver
def solve_system(self, rhs, factor, u0, t): """ Dolfin's weak solver for (M-dtA)u = rhs Args: rhs (dtype_f): right-hand side for the nonlinear system factor (float): abbrev. for the node-to-node stepsize (or any other factor required) u0 (dtype_u_: initial guess for the iterative solver (not used here so far) t (float): current time Returns: dtype_u: solution as mesh """ sol = self.dtype_u(self.V) self.g.t = t self.w.assign(sol.values) v = df.TestFunction(self.V) F = self.w * v * df.dx - factor * self.a_K - rhs.values * v * df.dx du = df.TrialFunction(self.V) J = df.derivative(F, self.w, du) problem = df.NonlinearVariationalProblem(F, self.w, self.bc, J) solver = df.NonlinearVariationalSolver(problem) prm = solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-12 prm['newton_solver']['relative_tolerance'] = 1E-12 prm['newton_solver']['maximum_iterations'] = 25 prm['newton_solver']['relaxation_parameter'] = 1.0 # df.set_log_level(df.PROGRESS) solver.solve() sol.values.assign(self.w) return sol
def inbuilt_newton_solver(self): V = self.my_function_space_cls.V F = self.my_var_prob_cls.F self.u = self.my_var_prob_cls.u du = df.TrialFunction(V) #TrialFunctions --> wrong, without 's' Jac = df.derivative(F, self.u, du) #user given solver parameters abs_tol = self.my_input_cls['newton_abs_tol'] rel_tol = self.my_input_cls['newton_rel_tol'] max_itr = self.my_input_cls['newton_max_itr'] step_size = self.my_input_cls['newton_relaxation_parameter'] problem = df.NonlinearVariationalProblem(F, self.u, [], Jac) solver = df.NonlinearVariationalSolver(problem) solver.parameters['newton_solver']['linear_solver'] = 'mumps' solver.parameters['newton_solver']['absolute_tolerance'] = abs_tol solver.parameters['newton_solver']['relative_tolerance'] = rel_tol solver.parameters['newton_solver']['maximum_iterations'] = max_itr solver.parameters['newton_solver']['relaxation_parameter'] = step_size #df.solve(F == 0, self.u, [], J=Jac, solver_parameters={'newton_solver' : {'linear_solver' : 'mumps'}}) solver.solve()
def stefan_form_cao(): # Temperature transforming model (Cao,1991) (T, bcs, theta, _theta, theta_) = stefan_function_spaces() theta_k = dolfin.project(theta_analytic, T, solver_type="cg", preconditioner_type="hypre_amg") q_form, q_form_k, bc_form = stefan_boundary_values(theta_, bcs) # Cao formulation source term def s(theta, theta0=prm.theta_m, eps=em.EPS): return dolfin.conditional( abs(theta - theta0) < eps, prm.cp_m * eps + prm.L_m / 2, dolfin.conditional(theta > theta0, prm.cp_s * eps + prm.L_m, prm.cp_s * eps)) # Fully implicit time discretization scheme F = k_eff(theta, deg='C0') * dolfin.inner( dolfin.grad(theta), dolfin.grad(theta_)) * dx + prm.rho / dt * ( c_p_eff(theta, deg='disC') * (theta - prm.theta_m) + s(theta) - c_p_eff(theta_k, deg='disC') * (theta_k - prm.theta_m) - s(theta_k)) * theta_ * dx - sum(q_form) # Full THETA time dicretization scheme # F = prm.rho/dt*(c_p_eff(theta,deg='disC')*(theta - prm.theta_m) + s(theta) - c_p_eff(theta_k,deg='disC')*(theta_k - prm.theta_m) - s(theta_k))*theta_*dx + (THETA*(k_eff(theta,deg='C0')*dolfin.inner(dolfin.grad(theta),dolfin.grad(theta_))*dx - sum(q_form)) + (1-THETA)*(k_eff(theta_k,deg='C0')*dolfin.inner(dolfin.grad(theta_k),dolfin.grad(theta_))*dx - sum(q_form_k))) problem = dolfin.NonlinearVariationalProblem( F, theta, bcs=bc_form, J=dolfin.derivative(F, theta)) solver = dolfin.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"] = NEWTON_PARAMS return solver, theta, theta_k
def stefan_form_ehc(): # Define functions and spaces: (T, bcs, theta, _theta, theta_) = stefan_function_spaces() # Set initial condition: theta_k = dolfin.project(theta_analytic, T, solver_type="cg", preconditioner_type="hypre_amg") # Set boundary terms q_form, q_form_k, bc_form = stefan_boundary_values(theta_, bcs) # Partial THETA time discretization scheme: F = (k_eff(theta, deg='C0') * dolfin.inner( dolfin.grad(theta), dolfin.grad(theta_)) * dx + prm.rho / dt * (THETA * c_p_eff(theta, deg='C0') + (1 - THETA) * c_p_eff(theta_k, deg='C0')) * (dolfin.inner(theta, theta_) - dolfin.inner(theta_k, theta_)) * dx - sum(q_form)) # Full THETA time discretization scheme: # F = (THETA*(k_eff(theta, deg = 'C0')*dolfin.inner(dolfin.grad(theta), dolfin.grad(theta_))*dx + # prm.rho/dt*c_p_eff(theta,deg='C0')*(dolfin.inner(theta,theta_)-dolfin.inner(theta_k,theta_))*dx - sum(q_form)) + # (1-THETA)*(k_eff(theta_k, deg = 'C0')*dolfin.inner(dolfin.grad(theta_k), dolfin.grad(theta_))*dx + # prm.rho/dt*c_p_eff(theta_k,deg='C0')*(dolfin.inner(theta, theta_) - dolfin.inner(theta_k,theta_))*dx - sum(q_form_k))) problem = dolfin.NonlinearVariationalProblem( F, theta, bcs=bc_form, J=dolfin.derivative(F, theta)) solver = dolfin.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"] = NEWTON_PARAMS return solver, theta, theta_k
def equilibrium_EC(w_, x_, test_functions, solutes, permittivity, mesh, dx, ds, normal, dirichlet_bcs, neumann_bcs, boundary_to_mark, use_iterative_solvers, c_lagrange, V_lagrange, **namespace): """ Electrochemistry equilibrium solver. Nonlinear! """ num_solutes = len(solutes) cV = df.split(w_["EC"]) c, V = cV[:num_solutes], cV[num_solutes] if c_lagrange: c0, V0 = cV[num_solutes + 1:2 * num_solutes + 1], cV[2 * num_solutes + 1] if V_lagrange: V0 = cV[-1] b = test_functions["EC"][:num_solutes] U = test_functions["EC"][num_solutes] if c_lagrange: b0, U0 = cV[num_solutes + 1:2 * num_solutes + 1], cV[2 * num_solutes + 1] if V_lagrange: U0 = test_functions["EC"][-1] phi = x_["phi"] q = [] sum_zx = sum([solute[1] * xj for solute, xj in zip(solutes, composition)]) for solute, xj in zip(solutes, composition): q.append(-xj * Q / (area * sum_zx)) z = [] # Charge z[species] K = [] # Diffusivity K[species] beta = [] for solute in solutes: z.append(solute[1]) K.append(ramp(phi, solute[2:4])) beta.append(ramp(phi, solute[4:6])) rho_e = sum([c_e * z_e for c_e, z_e in zip(c, z)]) veps = ramp(phi, permittivity) F_c = [] for ci, bi, c0i, b0i, solute, qi, betai, Ki in zip(c, b, c0, b0, solutes, q, beta, K): zi = solute[1] F_ci = Ki * (df.dot( df.nabla_grad(bi), df.nabla_grad(ci) + df.nabla_grad(betai) + zi * ci * df.nabla_grad(V))) * dx if c_lagrange: F_ci += b0i * (ci - df.Constant(qi)) * dx + c0i * bi * dx F_V = veps * df.dot(df.nabla_grad(U), df.nabla_grad(V)) * dx for boundary_name, sigma_e in neumann_bcs["V"].items(): F_V += -sigma_e * U * ds(boundary_to_mark[boundary_name]) if rho_e != 0: F_V += -rho_e * U * dx if V_lagrange: F_V += V0 * U * dx + V * U0 * dx F = sum(F_c) + F_V J = df.derivative(F, w_["EC"]) problem = df.NonlinearVariationalProblem(F, w_["EC"], dirichlet_bcs["EC"], J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"]["relative_tolerance"] = 1e-7 if use_iterative_solvers: solver.parameters["newton_solver"]["linear_solver"] = "bicgstab" if not V_lagrange: solver.parameters["newton_solver"]["preconditioner"] = "hypre_amg" solver.solve()
def __init__(self, fileName, timeEnd, timeStep, average=False): fc.set_log_active(False) self.times = [] self.BB = [] self.HH = [] self.TD = [] self.TB = [] self.TX = [] self.TY = [] self.TZ = [] self.us = [] self.ub = [] ########################################################## ################ MESH ################# ########################################################## # TODO: Probably do not have to save then open mesh self.mesh = df.Mesh() self.inFile = fc.HDF5File(self.mesh.mpi_comm(), fileName, "r") self.inFile.read(self.mesh, "/mesh", False) ######################################################### ################# FUNCTION SPACES ##################### ######################################################### self.E_Q = df.FiniteElement("CG", self.mesh.ufl_cell(), 1) self.Q = df.FunctionSpace(self.mesh, self.E_Q) self.E_V = df.MixedElement(self.E_Q, self.E_Q, self.E_Q) self.V = df.FunctionSpace(self.mesh, self.E_V) self.assigner_inv = fc.FunctionAssigner([self.Q, self.Q, self.Q], self.V) self.assigner = fc.FunctionAssigner(self.V, [self.Q, self.Q, self.Q]) self.U = df.Function(self.V) self.dU = df.TrialFunction(self.V) self.Phi = df.TestFunction(self.V) self.u, self.u2, self.H = df.split(self.U) self.phi, self.phi1, self.xsi = df.split(self.Phi) self.un = df.Function(self.Q) self.u2n = df.Function(self.Q) self.zero_sol = df.Function(self.Q) self.Bhat = df.Function(self.Q) self.H0 = df.Function(self.Q) self.A = df.Function(self.Q) if average: self.inFile.read(self.Bhat.vector(), "/bedAvg", True) self.inFile.read(self.A.vector(), "/smbAvg", True) self.inFile.read(self.H0.vector(), "/thicknessAvg", True) else: self.inFile.read(self.Bhat.vector(), "/bed", True) self.inFile.read(self.A.vector(), "/smb", True) self.inFile.read(self.H0.vector(), "/thickness", True) self.Hmid = theta * self.H + (1 - theta) * self.H0 self.B = softplus(self.Bhat, -rho / rho_w * self.Hmid, alpha=0.2) # Is not the bed, it is the lower surface self.S = self.B + self.Hmid self.width = df.interpolate(Width(degree=2), self.Q) self.strs = Stresses(self.U, self.Hmid, self.H0, self.H, self.width, self.B, self.S, self.Phi) self.R = -(self.strs.tau_xx + self.strs.tau_xz + self.strs.tau_b + self.strs.tau_d + self.strs.tau_xy) * df.dx ############################################################################# ######################## MASS CONSERVATION ################################ ############################################################################# self.h = df.CellSize(self.mesh) self.D = self.h * abs(self.U[0]) / 2. self.area = self.Hmid * self.width self.mesh_min = self.mesh.coordinates().min() self.mesh_max = self.mesh.coordinates().max() # Define boundaries self.ocean = df.FacetFunctionSizet(self.mesh, 0) self.ds = fc.ds(subdomain_data=self.ocean) # THIS DS IS FROM FENICS! border integral for f in df.facets(self.mesh): if df.near(f.midpoint().x(), self.mesh_max): self.ocean[f] = 1 if df.near(f.midpoint().x(), self.mesh_min): self.ocean[f] = 2 self.R += ((self.H - self.H0) / dt * self.xsi \ - self.xsi.dx(0) * self.U[0] * self.Hmid \ + self.D * self.xsi.dx(0) * self.Hmid.dx(0) \ - (self.A - self.U[0] * self.H / self.width * self.width.dx(0)) \ * self.xsi) * df.dx + self.U[0] * self.area * self.xsi * self.ds(1) \ - self.U[0] * self.area * self.xsi * self.ds(0) ##################################################################### ######################### SOLVER SETUP ########################### ##################################################################### # Bounds self.l_thick_bound = df.project(Constant(thklim), self.Q) self.u_thick_bound = df.project(Constant(1e4), self.Q) self.l_v_bound = df.project(-10000.0, self.Q) self.u_v_bound = df.project(10000.0, self.Q) self.l_bound = df.Function(self.V) self.u_bound = df.Function(self.V) self.assigner.assign(self.l_bound, [self.l_v_bound] * 2 + [self.l_thick_bound]) self.assigner.assign(self.u_bound, [self.u_v_bound] * 2 + [self.u_thick_bound]) # This should set the velocity at the divide (left) to zero self.dbc0 = df.DirichletBC(self.V.sub(0), 0, lambda x, o: df.near(x[0], self.mesh_min) and o) # Set the velocity on the right terminus to zero self.dbc1 = df.DirichletBC(self.V.sub(0), 0, lambda x, o: df.near(x[0], self.mesh_max) and o) # overkill? self.dbc2 = df.DirichletBC(self.V.sub(1), 0, lambda x, o: df.near(x[0], self.mesh_max) and o) # set the thickness on the right edge to thklim self.dbc3 = df.DirichletBC(self.V.sub(2), thklim, lambda x, o: df.near(x[0], self.mesh_max) and o) # Define variational solver for the mass-momentum coupled problem self.J = df.derivative(self.R, self.U, self.dU) self.coupled_problem = df.NonlinearVariationalProblem(self.R, self.U, bcs=[self.dbc0, self.dbc1, self.dbc3], \ J=self.J) self.coupled_problem.set_bounds(self.l_bound, self.u_bound) self.coupled_solver = df.NonlinearVariationalSolver(self.coupled_problem) # Acquire the optimizations in fenics_optimizations set_solver_options(self.coupled_solver) self.t = 0 self.timeEnd = float(timeEnd) self.dtFloat = float(timeStep) self.inFile.close()
def _setup_problem(self): """ Method setting up solver objects of the stationary problem. """ assert hasattr(self, "_mesh") assert hasattr(self, "_boundary_markers") self._setup_function_spaces() self._setup_boundary_conditions() # creating test function self._v = dlfn.TestFunction(self._Vh) self._u = dlfn.TrialFunction(self._Vh) # solution self._solution = dlfn.Function(self._Vh) # volume element self._dV = dlfn.Measure("dx", domain=self._mesh) self._dA = dlfn.Measure("ds", domain=self._mesh, subdomain_data=self._boundary_markers) # setup the parameters for the elastic law self._elastic_law.set_parameters(self._mesh, self._C) # virtual work if self._elastic_law.linearity_type == "Linear": self._dw_int = self._elastic_law.dw_int(self._u, self._v) * self._dV elif self._elastic_law.linearity_type == "Nonlinear": self._dw_int = self._elastic_law.dw_int(self._solution, self._v) * self._dV # virtual work of external forces self._dw_ext = dlfn.dot(self._null_vector, self._v) * self._dV # add body force term if hasattr(self, "_body_force"): assert hasattr(self, "_D"), "Dimensionless parameter related to" + \ "the body forces is not specified." self._dw_ext += self._D * dot(self._body_force, self._v) * self._dV # add boundary tractions if hasattr(self, "_traction_bcs"): for bc in self._traction_bcs: # unpack values if len(bc) == 3: bc_type, bndry_id, traction = bc elif len(bc) == 4: bc_type, bndry_id, component_index, traction = bc if bc_type is TractionBCType.constant: assert isinstance(traction, (tuple, list)) const_function = dlfn.Constant(traction) self._dw_ext += dot(const_function, self._v) * self._dA(bndry_id) elif bc_type is TractionBCType.constant_component: assert isinstance(traction, float) const_function = dlfn.Constant(traction) self._dw_ext += const_function * self._v[ component_index] * self._dA(bndry_id) elif bc_type is TractionBCType.function: assert isinstance(traction, dlfn.Expression) self._dw_ext += dot(traction, self._v) * self._dA(bndry_id) elif bc_type is TractionBCType.function_component: assert isinstance(traction, dlfn.Expression) self._dw_ext += traction * self._v[ component_index] * self._dA(bndry_id) if self._elastic_law.linearity_type == "Linear": # linear variational problem self._problem = dlfn.LinearVariationalProblem( self._dw_int, self._dw_ext, self._solution, self._dirichlet_bcs) # setup linear variational solver self._solver = dlfn.LinearVariationalSolver(self._problem) elif self._elastic_law.linearity_type == "Nonlinear": self._Form = self._dw_int - self._dw_ext self._J_newton = dlfn.derivative(self._Form, self._solution) self._problem = dlfn.NonlinearVariationalProblem( self._Form, self._solution, self._dirichlet_bcs, J=self._J_newton) # setup linear variational solver self._solver = dlfn.NonlinearVariationalSolver(self._problem)
J = df.derivative(R, U, dU) ##################################################################### ###################### Variational Solvers ######################## ##################################################################### # Define variational problem subject to no Dirichlet BCs, but with a # thickness bound, plus form compiler parameters for efficiency. mass_problem = df.NonlinearVariationalProblem( R, U, bcs=[], J=J, form_compiler_parameters=ffc_options) mass_problem.set_bounds(l_bound, u_bound) # Create an instance of vinewtonrsls, PETSc's variational inequality # solver. Not clear that this is needed, given that the ice should never be # negative by design. mass_solver = df.NonlinearVariationalSolver(mass_problem) mass_solver.parameters['nonlinear_solver'] = 'snes' mass_solver.parameters['snes_solver']['method'] = 'vinewtonrsls' mass_solver.parameters['snes_solver']['relative_tolerance'] = 1e-3 mass_solver.parameters['snes_solver']['absolute_tolerance'] = 1e-3 mass_solver.parameters['snes_solver']['error_on_nonconvergence'] = True mass_solver.parameters['snes_solver']['linear_solver'] = 'mumps' mass_solver.parameters['snes_solver']['maximum_iterations'] = 10 mass_solver.parameters['snes_solver']['report'] = False ##################################################################### ############### INITIALIZE PLOTTING AND STORAGE ##################### ##################################################################### # Basic animation utilities if PLOT:
def solve_nonlinear(self, inputs, outputs): pde_problem = self.options['pde_problem'] state_name = self.options['state_name'] problem_type = self.options['problem_type'] visualization = self.options['visualization'] state_function = pde_problem.states_dict[state_name]['function'] for argument_name, argument_function in iteritems( self.argument_functions_dict): density_func = argument_function self.itr = self.itr + 1 state_function = pde_problem.states_dict[state_name]['function'] residual_form = pde_problem.states_dict[state_name]['residual_form'] self._set_values(inputs, outputs) self.derivative_form = df.derivative(residual_form, state_function) df.set_log_active(True) if problem_type == 'linear_problem': if state_name == 'density': print('this is a variational density filter') df.solve(residual_form == 0, state_function, J=self.derivative_form, solver_parameters={ "newton_solver": { "maximum_iterations": 1, "error_on_nonconvergence": False } }) else: df.solve(residual_form == 0, state_function, bcs=pde_problem.bcs_list, J=self.derivative_form, solver_parameters={ "newton_solver": { "maximum_iterations": 1, "error_on_nonconvergence": False } }) elif problem_type == 'nonlinear_problem': state_function.vector().set_local( np.zeros((state_function.function_space().dim()))) problem = df.NonlinearVariationalProblem(residual_form, state_function, pde_problem.bcs_list, self.derivative_form) solver = df.NonlinearVariationalSolver(problem) solver.parameters['nonlinear_solver'] = 'snes' solver.parameters["snes_solver"]["relative_tolerance"] = 5e-100 solver.parameters["snes_solver"]["absolute_tolerance"] = 5e-50 solver.parameters["snes_solver"]["line_search"] = 'bt' solver.parameters["snes_solver"][ "linear_solver"] = 'mumps' # "cg" "gmres" solver.parameters["snes_solver"]["maximum_iterations"] = 500 solver.parameters["snes_solver"]["relative_tolerance"] = 5e-100 solver.parameters["snes_solver"]["absolute_tolerance"] = 5e-50 # solver.parameters["snes_solver"]["linear_solver_"]["maximum_iterations"]=1000 solver.parameters["snes_solver"]["error_on_nonconvergence"] = False solver.solve() elif problem_type == 'nonlinear_problem_load_stepping': num_steps = 4 state_function.vector().set_local( np.zeros((state_function.function_space().dim()))) for i in range(num_steps): v = df.TestFunction(state_function.function_space()) if i < (num_steps - 1): residual_form = get_residual_form( state_function, v, density_func, density_func.function_space, tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1 / num_steps * (i + 1))), 'False') else: residual_form = get_residual_form( state_function, v, density_func, density_func.function_space, tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1 / num_steps * (i + 1))), 'vol') problem = df.NonlinearVariationalProblem( residual_form, state_function, pde_problem.bcs_list, self.derivative_form) solver = df.NonlinearVariationalSolver(problem) solver.parameters['nonlinear_solver'] = 'snes' solver.parameters["snes_solver"]["line_search"] = 'bt' solver.parameters["snes_solver"][ "linear_solver"] = 'mumps' # "cg" "gmres" solver.parameters["snes_solver"]["maximum_iterations"] = 500 solver.parameters["snes_solver"]["relative_tolerance"] = 1e-15 solver.parameters["snes_solver"]["absolute_tolerance"] = 1e-15 # solver.parameters["snes_solver"]["linear_solver_"]["maximum_iterations"]=1000 solver.parameters["snes_solver"][ "error_on_nonconvergence"] = False solver.solve() # option to store the visualization results if (visualization == 'True') and (self.itr % 50 == 0): for argument_name, argument_function in iteritems( self.argument_functions_dict): if argument_name == 'density': df.File('solutions_iterations_40ramp/{}_{}.pvd'.format( argument_name, self.itr)) << df.project( argument_function / (1 + 8. * (1. - argument_function)), argument_function.function_space()) else: df.File('solutions_iterations_40ramp/{}_{}.pvd'.format( argument_name, self.itr)) << argument_function df.File('solutions_iterations_40ramp/{}_{}.pvd'.format( state_name, self.itr)) << state_function self.L = -residual_form outputs[state_name] = state_function.vector().get_local() self._set_values(inputs, outputs)
def __init__(self, V, viscosity=1e-2, penalty=1e5): ''' Parameters ---------- V : dolfin.FunctionSpace Function space for the distance function. viscosity: float or dolfin.Constant Stabilization for the unique solution of the distance problem. penalty: float or dolfin.Constant Penalty for weakly enforcing the zero-distance boundary conditions. ''' if not isinstance(V, dolfin.FunctionSpace): raise TypeError('Parameter `V` must be a `dolfin.FunctionSpace`') if not isinstance(viscosity, Constant): if not isinstance(viscosity, (float, int)): raise TypeError('`Parameter `viscosity`') viscosity = Constant(viscosity) if not isinstance(penalty, Constant): if not isinstance(penalty, (float, int)): raise TypeError('Parameter `penalty`') penalty = Constant(penalty) self._viscosity = viscosity self._penalty = penalty mesh = V.mesh() xs = mesh.coordinates() l0 = (xs.max(0) - xs.min(0)).min() self._d = d = Function(V) self._Q = dolfin.FunctionSpace(mesh, 'DG', 0) self._mf = dolfin.MeshFunction('size_t', mesh, mesh.geometric_dimension()) self._dx_penalty = dx(subdomain_id=1, subdomain_data=self._mf, domain=mesh) v0 = dolfin.TestFunction(V) v1 = dolfin.TrialFunction(V) target_gradient = Constant(1.0) scaled_penalty = penalty / mesh.hmax() lhs_F0 = l0*dot(grad(v0), grad(v1))*dx \ + scaled_penalty*v0*v1*self._dx_penalty rhs_F0 = v0 * target_gradient * dx problem = dolfin.LinearVariationalProblem(lhs_F0, rhs_F0, d) self._linear_solver = dolfin.LinearVariationalSolver(problem) self._linear_solver.parameters["symmetric"] = True F = v0*(grad(d)**2-target_gradient)*dx \ + viscosity*l0*dot(grad(v0), grad(d))*dx \ + scaled_penalty*v0*d*self._dx_penalty J = dolfin.derivative(F, d, v1) problem = dolfin.NonlinearVariationalProblem(F, d, bcs=None, J=J) self._nonlinear_solver = dolfin.NonlinearVariationalSolver(problem) self._nonlinear_solver.parameters['nonlinear_solver'] = 'newton' self._nonlinear_solver.parameters['symmetric'] = False self._solve_initdist_problem = self._linear_solver.solve self._solve_distance_problem = self._nonlinear_solver.solve
def step(self, t0: float, t1: float) -> None: """Solve on the given time step (`t0`, `t1`). End users are recommended to use solve instead. Arguments: t0: Start time. t1: End time. """ timer = df.Timer("ODE step") # Extract time mesh k_n = df.Constant(t1 - t0) # Extract previous solution(s) v_, s_ = split_function(self.vs_, self._num_states + 1) # Set-up current variables self.vs.assign(self.vs_) # Start with good guess v, s = split_function(self.vs, self._num_states + 1) w, r = split_function(df.TestFunction(self.VS), self._num_states + 1) # Define equation based on cell model Dt_v = (v - v_) / k_n Dt_s = (s - s_) / k_n theta = self._parameters["theta"] # Set time (propagates to time-dependent variables defined via self.time) t = t0 + theta * (t1 - t0) self.time.assign(t) v_mid = theta * v + (1.0 - theta) * v_ s_mid = theta * s + (1.0 - theta) * s_ if isinstance(self._cell_model, MultiCellModel): model = self._cell_model mesh = model.mesh() dy = df.Measure("dx", domain=mesh, subdomain_data=model.markers()) if self._I_s is None: self._I_s = df.Constant(0) rhs = self._I_s * w * dy() n = model.num_states() # Extract number of global states # Collect contributions to lhs by iterating over the different cell models domains = self._cell_model.keys() lhs_list = list() for k, model_k in enumerate(model.models()): n_k = model_k.num_states( ) # Extract number of local (non-trivial) states # Extract right components of coefficients and test functions () is not the same as (1,) if n_k == 1: s_mid_k = s_mid[0] r_k = r[0] Dt_s_k = Dt_s[0] else: s_mid_k = df.as_vector(tuple(s_mid[j] for j in range(n_k))) r_k = df.as_vector(tuple(r[j] for j in range(n_k))) Dt_s_k = df.as_vector(tuple(Dt_s[j] for j in range(n_k))) i_k = domains[k] # Extract domain index of cell model k # Extract right currents and ion channel expressions F_theta_k = self._F(v_mid, s_mid_k, time=self.time, index=i_k) I_theta_k = -self._I_ion( v_mid, s_mid_k, time=self.time, index=i_k) # Variational contribution over the relevant domain a_k = ((Dt_v - I_theta_k) * w + df.inner(Dt_s_k, r_k) - df.inner(F_theta_k, r_k)) * dy(i_k) # Add s_trivial = 0 on Omega_{i_k} in variational form: a_k += sum(s[j] * r[j] for j in range(n_k, n)) * dy(i_k) lhs_list.append(a_k) lhs = sum(lhs_list) else: dz, rhs = rhs_with_markerwise_field(self._I_s, self._mesh, w) # Evaluate currents at averaged v and s. Note sign for I_theta F_theta = self._F(v_mid, s_mid, time=self.time) I_theta = -self._I_ion(v_mid, s_mid, time=self.time) lhs = (Dt_v - I_theta) * w * dz + df.inner(Dt_s - F_theta, r) * dz # Set-up system of equations G = lhs - rhs # Solve system pde = df.NonlinearVariationalProblem(G, self.vs, J=df.derivative(G, self.vs)) solver = df.NonlinearVariationalSolver(pde) solver_parameters = self._parameters["nonlinear_variational_solver"] solver_parameters["nonlinear_solver"] = "snes" solver_parameters["snes_solver"]["absolute_tolerance"] = 1e-13 solver_parameters["snes_solver"]["relative_tolerance"] = 1e-13 # Tested on Cressman solver_parameters["snes_solver"]["linear_solver"] = "bicgstab" solver_parameters["snes_solver"]["preconditioner"] = "jacobi" solver.parameters.update(solver_parameters) solver.solve() timer.stop()
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 NSPFEC_action(u_, u_1, phi_, phi_1, c_, c_1, u, p, phi, g, c, V, v, q, psi, h, b, U, rho, M, nu, rho_e, K, veps, drho, grav, sigma_bar, eps, dveps, dbeta, z, per_tau, enable_NS, enable_PF, enable_EC): # The setup of the Navier-Stokes part of F F = [] if enable_NS: F_NS = (per_tau * rho * df.dot(u_ - u_1, v) * df.dx + df.inner( df.grad(u), df.outer(rho * u - drho * M * df.grad(g), v)) * df.dx + 2 * nu * df.inner(df.sym(df.grad(u)), df.grad(v)) * df.dx - p * df.div(v) * df.dx + df.div(u) * q * df.dx - df.dot(rho * grav, v) * df.dx) if enable_PF: F_NS += -sigma_bar * eps * df.inner( df.outer(df.grad(phi), df.grad(phi)), df.grad(v)) * df.dx if enable_EC and rho_e != 0: F_NS += rho_e * df.dot(df.grad(V), v) * df.dx if enable_PF and enable_EC: F_NS += dveps * df.dot(df.grad(phi), v) * df.dot( df.grad(V), df.grad(V)) * df.dx F.append(F_NS) # The setup of the Phase feild equations if enable_PF: F_PF_phi = (per_tau * (phi_ - phi_1) * psi * df.dx + M * df.dot(df.grad(g), df.grad(psi)) * df.dx) if enable_NS: F_PF_phi += df.dot(u, df.grad(phi)) * psi * df.dx F_PF_g = (g * h * df.dx - sigma_bar * eps * df.dot(df.grad(phi), df.grad(h)) * df.dx - sigma_bar / eps * diff_pf_potential(phi) * h * df.dx) if enable_EC: F_PF_g += (-sum( [dbeta_i * ci * h * df.dx for dbeta_i, ci in zip(dbeta, c)]) + dveps * df.dot(df.grad(V), df.grad(V)) * h * df.dx) F_PF = F_PF_phi + F_PF_g F.append(F_PF) # The setup of the Electrochemistry if enable_EC: F_E_c = [] for ci, ci_, ci_1, bi, Ki, zi in zip(c, c_, c_1, b, K, z): F_E_ci = (per_tau * (ci_ - ci_1) * bi * df.dx + Ki * df.dot(df.grad(ci), df.grad(bi)) * df.dx) if zi != 0: F_E_ci += Ki * zi * ci * df.dot(df.grad(V), df.grad(bi)) * df.dx if enable_NS: F_E_ci += df.dot(u, df.grad(ci)) * bi * df.dx F_E_c.append(F_E_ci) F_E_V = veps * df.dot(df.grad(V), df.grad(U)) * df.dx if rho_e != 0: F_E_V += -rho_e * U * df.dx F_E = sum(F_E_c) + F_E_V F.append(F_E) F = sum(F) J = df.derivative(F, w_NSPFEC) problem_NSPFEC = df.NonlinearVariationalProblem(F, w_NSPFEC, bcs_NSPFEC, J) solver_NSPFEC = df.NonlinearVariationalSolver(problem_NSPFEC) if use_iterative_solvers: solver_NSPFEC.parameters['newton_solver']['linear_solver'] = 'gmres' solver_NSPFEC.parameters['newton_solver']['preconditioner'] = 'ilu' return solver_NSPFEC
def __init__(self, J, U, u, m, bcs, dx_m=None, dims_m=None, use_nonlinear_solver=False): ''' Parameters ---------- J : ufl.Form Objective functional to maximize, e.g. linear-elastic strain energy. U : ufl.Form Linear-elastic strain energy. u : dolfin.Function Displacement field. m : dolfin.Function Vector-valued "body force" like traction field. bcs : (list of) dolfin.DirichletBC('s) Dirichlet boundary conditions. dx_m : dolfin.Measure or None (optional) "Body force" integration measure. Can be of cell type or exterior facet type; the default is cell type. Note, the integration measure can be defined on a subdomain (not necessarily on the whole domain). kappa : float or None (optional) Diffusion-like constant for smoothing the solution (`m`) increment. Notes ----- If the "body force" integration measure `dx_m` concerns cells (as opposed to exterior facets), the gradient smoothing constant `kappa` can be `None`. Usually, `kappa` will need to be some small positive value if `dx_m` concerns exterior facets. ''' if not isinstance(J, ufl_form_t): raise TypeError('Parameter `J`') if not isinstance(U, ufl_form_t): raise TypeError('Parameter `U`') if not isinstance(u, Function): raise TypeError('Parameter `u`') if not isinstance(m, Function): raise TypeError('Parameter `m`') if len(u) != len(m): raise ValueError( 'Functions `u` and `m` must live in the same dimension space') if bcs is None: bcs = () elif not isinstance(bcs, (list, tuple)): bcs = (bcs, ) if not all(isinstance(bc, DirichletBC) for bc in bcs): raise TypeError('Parameter `bcs` must contain ' 'homogenized `DirichletBC`(\'s)') if dims_m is not None: if not isinstance(bcs, (list, tuple, range)): dims_m = (dims_m, ) if not all(isinstance(dim_i, int) for dim_i in dims_m): raise TypeError('Parameter `dims_m`') if not all(0 <= dim_i < len(m) for dim_i in dims_m): raise ValueError('Parameter `dims_m`') if dx_m is None: dx_m = dx elif not isinstance(dx_m, dolfin.Measure): raise TypeError('Parameter `dx_m`') bcs_zro = [] for bc in bcs: bc_zro = DirichletBC(bc) bc_zro.homogenize() bcs_zro.append(bc_zro) V_u = u.function_space() V_m = m.function_space() v0_u = dolfin.TestFunction(V_u) v0_m = dolfin.TestFunction(V_m) v1_u = dolfin.TrialFunction(V_u) v1_m = dolfin.TrialFunction(V_m) self._u = u self._m = m self._z = z = Function(V_u) # Adjoint solution self._J = J dJ_u = derivative(J, u, v0_u) self._dJ_m = derivative(J, m, v0_m) dU_u = derivative(U, u, v0_u) # Internal force d2U_uu = a = derivative(dU_u, u, v1_u) # Stiffness if dims_m is None: dW_u = L = dot(v0_u, m) * dx_m else: dW_u = L = sum(v0_u[i] * m[i] for i in dims_m) * dx_m self._ufl_norm_m = dolfin.sqrt(m**2) * dx_m # equiv. L1-norm self._assembled_adj_dW_um = assemble(dot(v0_m, v1_u) * dx_m) self._dimdofs_V_m = tuple( np.array(V_m_sub_i.dofmap().dofs()) for V_m_sub_i in V_m.split()) if use_nonlinear_solver: self._equilibrium_solver = dolfin.NonlinearVariationalSolver( dolfin.NonlinearVariationalProblem(dU_u - dW_u, u, bcs, d2U_uu)) self._adjoint_solver = dolfin.LinearVariationalSolver( dolfin.LinearVariationalProblem(d2U_uu, dJ_u, z, bcs_zro)) # NOTE: `d2U_uu` is equivalent to `adjoint(d2U_uu)` due to symmetry self._equilibrium_solver.parameters["symmetric"] = True self._adjoint_solver.parameters["symmetric"] = True else: self._equilibrium_solver = LinearEquilibriumSolver(a, L, u, bcs) self._adjoint_solver = LinearAdjointSolver(None, dJ_u, z, bcs_zro) self._adjoint_solver._solver = self._equilibrium_solver.solver self._equilibrium_solver.parameters['symmetric'] = True # NOTE: `a` is equivalent to `adjoint(a)` due to symmetry; however, # the LU factorization can be reused in the adjoint solver. if dx_m.integral_type() == 'cell': kappa = None else: # Compute scale factor for `kappa` based on domain size mesh = V_m.mesh() xs = mesh.coordinates() domain_volume = assemble(1.0 * dx(mesh)) domain_length = (xs.max(0) - xs.min(0)).max() scale_factor = domain_volume / domain_length kappa = Constant(scale_factor * SMOOTHING_SOLVER_KAPPA) self._smoothing_solver = SmoothingSolver(V_m, kappa)
def _setup_implicit_problem(self): assert hasattr(self, "_parameters") assert hasattr(self, "_mesh") assert hasattr(self, "_Wh") assert hasattr(self, "_coefficients") assert hasattr(self, "_one") assert hasattr(self, "_omega") assert hasattr(self, "_v0") assert hasattr(self, "_v00") assert hasattr(self, "_T0") assert hasattr(self, "_T00") print " setup implicit problem..." #======================================================================= # retrieve imex coefficients a, c = self._imex_alpha, self._imex_gamma #======================================================================= # trial and test function (del_v, del_p, del_T) = dlfn.TestFunctions(self._Wh) v, p, T = dlfn.split(self._sol) # volume element dV = dlfn.Measure("dx", domain=self._mesh) # reference to time step timestep = self._timestep #======================================================================= from dolfin import dot, grad # 1) momentum equation momentum_eqn = ( dot((a[0] * v + a[1] * self._v0 + a[2] * self._v00) / timestep, del_v) + dot(dot(grad(v), v), del_v) + self._coefficients[1] * a_op(c[0] * v + c[1] * self._v0 + c[2] * self._v00, del_v) - b_op(del_v, p) - b_op(v, del_p)) * dV # 2) momentum equation: coriolis term if self._parameters.rotation is True: assert self._coefficients[0] != 0.0 print " adding rotation to the model..." # add Coriolis term if self._space_dim == 2: momentum_eqn += self._coefficients[0] * (-v[1] * del_v[0] + v[0] * del_v[1]) * dV elif self._space_dim == 3: assert hasattr(self, "_rotation_vector") assert isinstance(self._rotation_vector, (dlfn.Constant, dlfn.Expression)) from dolfin import cross momentum_eqn += self._coefficients[0] * dot( cross(self._rotation_vector, v), del_v) * dV # 3) momentum equation: coriolis term if self._parameters.buoyancy is True: assert self._coefficients[2] != 0.0 assert hasattr(self, "_gravity") and isinstance( self._gravity, (dlfn.Expression, dlfn.Constant)) print " adding buoyancy to the model..." # add buoyancy term momentum_eqn += self._coefficients[2] * T * dot( self._gravity, del_v) * dV #======================================================================= # 4) energy equation energy_eqn = ( (a[0] * T + a[1] * self._T0 + a[2] * self._T00) / timestep * del_T + dot(v, grad(T)) * del_T + self._coefficients[3] * a_op(c[0] * T + c[1] * self._T0 + c[2] * self._T00, del_T)) * dV #======================================================================= # full problem self._eqn = momentum_eqn + energy_eqn if not hasattr(self, "_dirichlet_bcs"): self._setup_boundary_conditons() self._jacobian = dlfn.derivative(self._eqn, self._sol) problem = dlfn.NonlinearVariationalProblem(self._eqn, self._sol, J=self._jacobian, bcs=self._dirichlet_bcs) self._solver = dlfn.NonlinearVariationalSolver(problem) prm = self._solver.parameters prm["newton_solver"]["absolute_tolerance"] = 1e-6 prm["newton_solver"]["relative_tolerance"] = 1e-9 prm["newton_solver"]["maximum_iterations"] = 10
def setup_EC(w_EC, c, V, V0, b, U, U0, rho_e, grad_g_c, c_reg, g_c, dx, ds, normal, dirichlet_bcs_EC, neumann_bcs, boundary_to_mark, c_1, u_1, K, veps, rho_, rho_1, dt, enable_NS, solutes, use_iterative_solvers, nonlinear_EC, V_lagrange, p_lagrange, q_rhs, reactions, beta, **namespace): """ Set up electrochemistry subproblem. """ if enable_NS: # Projected velocity u_star = u_1 - dt/rho_1*sum([ci_1*grad_g_ci for ci_1, grad_g_ci in zip(c_1, grad_g_c)]) F_c = [] for ci, ci_1, bi, Ki, grad_g_ci, solute, ci_reg in zip( c, c_1, b, K, grad_g_c, solutes, c_reg): F_ci = (1./dt*(ci-ci_1)*bi*dx + Ki*ci_reg*df.dot(grad_g_ci, df.grad(bi))*dx) if enable_NS: F_ci += - ci_1*df.dot(u_star, df.grad(bi))*dx if solute[0] in q_rhs: F_ci += - q_rhs[solute[0]]*bi*dx if enable_NS: for boundary_name, value in neumann_bcs[solute[0]].iteritems(): # F_ci += df.dot(u_1, normal)*bi*ci_1*ds( # boundary_to_mark[boundary_name]) pass F_c.append(F_ci) for reaction_constant, nu in reactions: g_less = [] g_more = [] for nui, ci_1, betai in zip(nu, c_1, beta): if nui < 0: g_less.append(-nui*(df.ln(ci_1)+betai)) elif nui > 0: g_more.append(nui*(df.ln(ci_1)+betai)) g_less = sum(g_less) g_more = sum(g_more) C = reaction_constant*( df.exp(g_less) - df.exp(g_more))/(g_less - g_more) R = C*sum([nui*g_ci for nui, g_ci in zip(nu, g_c)]) for nui, bi in zip(nu, b): if nui != 0: F_c.append(nui*R*bi*dx) F_V = veps*df.dot(df.grad(V), df.grad(U))*dx for boundary_name, sigma_e in neumann_bcs["V"].iteritems(): F_V += -sigma_e*U*ds(boundary_to_mark[boundary_name]) if rho_e != 0: F_V += -rho_e*U*dx if V_lagrange: F_V += veps*V0*U*dx + veps*V*U0*dx if "V" in q_rhs: F_V += q_rhs["V"]*U*dx F = sum(F_c) + F_V if nonlinear_EC: J = df.derivative(F, w_EC) problem = df.NonlinearVariationalProblem(F, w_EC, dirichlet_bcs_EC, J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"]["relative_tolerance"] = 1e-7 if use_iterative_solvers: solver.parameters["newton_solver"]["linear_solver"] = "bicgstab" if not V_lagrange: solver.parameters["newton_solver"]["preconditioner"] = "hypre_amg" else: a, L = df.lhs(F), df.rhs(F) problem = df.LinearVariationalProblem(a, L, w_EC, dirichlet_bcs_EC) solver = df.LinearVariationalSolver(problem) if use_iterative_solvers: solver.parameters["linear_solver"] = "bicgstab" solver.parameters["preconditioner"] = "hypre_amg" return solver
def solve_nonlinear(self, inputs, outputs): pde_problem = self.options['pde_problem'] state_name = self.options['state_name'] problem_type = self.options['problem_type'] visualization = self.options['visualization'] state_function = pde_problem.states_dict[state_name]['function'] for argument_name, argument_function in iteritems( self.argument_functions_dict): density_func = argument_function mesh = state_function.function_space().mesh() sub_domains = df.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) upper_edge = TractionBoundary() upper_edge.mark(sub_domains, 6) dss = df.Measure('ds')(subdomain_data=sub_domains) tractionBC = dss(6) self.itr = self.itr + 1 state_function = pde_problem.states_dict[state_name]['function'] residual_form = get_residual_form( state_function, df.TestFunction(state_function.function_space()), density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1)), int(self.itr)) self._set_values(inputs, outputs) self.derivative_form = df.derivative(residual_form, state_function) df.set_log_level(df.LogLevel.ERROR) df.set_log_active(True) # df.solve(residual_form==0, state_function, bcs=pde_problem.bcs_list, J=self.derivative_form) if problem_type == 'linear_problem': df.solve(residual_form == 0, state_function, bcs=pde_problem.bcs_list, J=self.derivative_form, solver_parameters={ "newton_solver": { "maximum_iterations": 60, "error_on_nonconvergence": False } }) elif problem_type == 'nonlinear_problem': problem = df.NonlinearVariationalProblem(residual_form, state_function, pde_problem.bcs_list, self.derivative_form) solver = df.NonlinearVariationalSolver(problem) solver.parameters['nonlinear_solver'] = 'snes' solver.parameters["snes_solver"]["line_search"] = 'bt' solver.parameters["snes_solver"][ "linear_solver"] = 'mumps' # "cg" "gmres" solver.parameters["snes_solver"]["maximum_iterations"] = 500 solver.parameters["snes_solver"]["relative_tolerance"] = 5e-13 solver.parameters["snes_solver"]["absolute_tolerance"] = 5e-13 # solver.parameters["snes_solver"]["linear_solver_"]["maximum_iterations"]=1000 solver.parameters["snes_solver"]["error_on_nonconvergence"] = False solver.solve() elif problem_type == 'nonlinear_problem_load_stepping': num_steps = 3 state_function.vector().set_local( np.zeros((state_function.function_space().dim()))) for i in range(num_steps): v = df.TestFunction(state_function.function_space()) if i < (num_steps - 1): residual_form = get_residual_form( state_function, v, density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1 / num_steps * (i + 1))), int(self.itr)) else: residual_form = get_residual_form( state_function, v, density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1 / num_steps * (i + 1))), int(self.itr)) problem = df.NonlinearVariationalProblem( residual_form, state_function, pde_problem.bcs_list, self.derivative_form) solver = df.NonlinearVariationalSolver(problem) solver.parameters['nonlinear_solver'] = 'snes' solver.parameters["snes_solver"]["line_search"] = 'bt' solver.parameters["snes_solver"][ "linear_solver"] = 'mumps' # "cg" "gmres" solver.parameters["snes_solver"]["maximum_iterations"] = 500 solver.parameters["snes_solver"]["relative_tolerance"] = 1e-15 solver.parameters["snes_solver"]["absolute_tolerance"] = 1e-15 # solver.parameters["snes_solver"]["linear_solver_"]["maximum_iterations"]=1000 solver.parameters["snes_solver"][ "error_on_nonconvergence"] = False solver.solve() # option to store the visualization results if visualization == 'True': for argument_name, argument_function in iteritems( self.argument_functions_dict): df.File('solutions_iterations_3d/{}_{}.pvd'.format( argument_name, self.itr)) << argument_function self.L = -residual_form self.itr = self.itr + 1 outputs[state_name] = state_function.vector().get_local()
def setup_NSPFEC(w_NSPFEC, w_1NSPFEC, dirichlet_bcs_NSPFEC, neumann_bcs, boundary_to_mark, dx, ds, normal, v, q, q0, psi, h, b, U, u_, p_, p0_, phi_, g_, c_, V_, u_1, p_1, p0_1, phi_1, g_1, c_1, V_1, M_, nu_, veps_, rho_, K_, beta_, rho_e_, dbeta, dveps, drho, per_tau, sigma_bar, eps, grav, z, solutes, enable_NS, enable_PF, enable_EC, use_iterative_solvers, p_lagrange, q_rhs): """ The full problem of electrohydrodynamics in two phases. Note that it is possible to turn off the different parts at will. """ # Setup of the Navier-Stokes part of F mom_ = rho_*u_ if enable_PF: mom_ += -M_*drho * df.nabla_grad(g_) F = [] if enable_NS: F_NS = (per_tau * rho_ * df.dot(u_ - u_1, v) * dx + df.inner(df.nabla_grad(u_), df.outer(mom_, v)) * dx + 2*nu_*df.inner(df.sym(df.nabla_grad(u_)), df.sym(df.nabla_grad(v))) * dx - p_ * df.div(v) * dx - df.div(u_) * q * dx - df.dot(rho_ * grav, v) * dx) # if enable_PF: # F_NS += - sigma_bar*eps*df.inner( # df.outer(df.grad(phi_), # df.grad(phi_)), df.grad(v)) * dx # if enable_EC and rho_e_ != 0: # F_NS += rho_e_*df.dot(df.grad(V_), v) * dx # if enable_PF and enable_EC: # F_NS += dveps*df.dot( # df.grad(phi_), v)*df.dot(df.grad(V_), # df.grad(V_)) * dx if enable_PF: F_NS += phi_*df.dot(df.grad(g_), v) * dx if enable_EC: for ci_, dbetai, solute in zip(c_, dbeta, solutes): zi = solute[1] F_NS += df.dot(df.grad(ci_), v) * dx \ + ci_*dbetai*df.dot(df.grad(phi_), v) * dx \ + zi*ci_*df.dot(df.grad(V_), v) * dx # Slip boundary condition for boundary_name, slip_length in neumann_bcs["u"].items(): F_NS += 1./slip_length * \ df.dot(u_, v) * ds(boundary_to_mark[boundary_name]) # Pressure boundary condition for boundary_name, pressure in neumann_bcs["p"].items(): F_NS += pressure * df.inner( normal, v) * ds(boundary_to_mark[boundary_name]) # Lagrange pressure if p_lagrange: F_NS += (p_*q0 + q*p0_)*dx # RHS source terms if "u" in q_rhs: F_NS += -df.dot(q_rhs["u"], v)*dx F.append(F_NS) # Setup of the phase-field equations if enable_PF: phi_1_flt = unit_interval_filter(phi_1) F_PF_phi = (per_tau*(phi_-phi_1_flt)*psi*df.dx + M_*df.dot(df.grad(g_), df.grad(psi)) * dx) if enable_NS: F_PF_phi += df.dot(u_, df.grad(phi_)) * psi * dx F_PF_g = (g_ * h * dx - sigma_bar*eps*df.dot(df.grad(phi_), df.grad(h)) * dx - sigma_bar/eps*diff_pf_potential(phi_) * h * dx) if enable_EC: F_PF_g += (-sum([dbeta_i * ci_ * h * dx for dbeta_i, ci_ in zip(dbeta, c_)]) + dveps * df.dot(df.grad(V_), df.grad(V_)) * h * dx) # Contact angle boundary condtions for boundary_name, costheta in neumann_bcs["phi"].items(): fw_prime = diff_pf_contact(phi_) F_PF_g += sigma_bar * costheta * fw_prime * h * ds( boundary_to_mark[boundary_name]) # RHS source terms if "phi" in q_rhs: F_PF_phi += -q_rhs["phi"]*psi*dx F_PF = F_PF_phi + F_PF_g F.append(F_PF) # Setup of the electrochemistry if enable_EC: F_E_c = [] for ci_, ci_1, bi, Ki_, zi, dbetai, solute in zip( c_, c_1, b, K_, z, dbeta, solutes): ci_1_flt = max_value(ci_1, 0.) F_E_ci = (per_tau*(ci_-ci_1_flt)*bi*df.dx + Ki_*df.dot(df.grad(ci_), df.grad(bi))*df.dx) if zi != 0: F_E_ci += Ki_*zi*ci_*df.dot(df.grad(V_), df.grad(bi))*df.dx if enable_NS: F_E_ci += df.dot(u_, df.grad(ci_))*bi*df.dx if enable_PF: F_E_ci += Ki_*ci_*dbetai*df.dot(df.grad(phi_), df.grad(bi)) * dx if solute[0] in q_rhs: F_E_ci += - q_rhs[solute[0]] * bi * dx F_E_c.append(F_E_ci) F_E_V = veps_*df.dot(df.grad(V_), df.grad(U))*df.dx if rho_e_ != 0: F_E_V += -rho_e_*U*df.dx # Surface charge boundary condition for boundary_name, sigma_e in neumann_bcs["V"].items(): F_E_V += -sigma_e*U*ds(boundary_to_mark[boundary_name]) # RHS source terms if "V" in q_rhs: F_E_V += q_rhs["V"]*U*dx F_E = sum(F_E_c) + F_E_V F.append(F_E) F = sum(F) J = df.derivative(F, w_NSPFEC) problem_NSPFEC = df.NonlinearVariationalProblem(F, w_NSPFEC, dirichlet_bcs_NSPFEC, J) solver_NSPFEC = df.NonlinearVariationalSolver(problem_NSPFEC) if use_iterative_solvers: solver_NSPFEC.parameters['newton_solver']['linear_solver'] = 'gmres' solver_NSPFEC.parameters['newton_solver']['preconditioner'] = 'ilu' return solver_NSPFEC
def solver(interval, dt=0.1, theta=1): t0, t1 = interval mesh = get_mesh(10) cell_function = get_cell_function(mesh) model = get_models(cell_function) num_global_states = model.num_states() # Create time keepers and time step const_dt = df.Constant(dt) current_time = df.Constant(0) t = t0 + theta*(t1 - t0) current_time.assign(t) # Create stimulus stimulus = df.Constant(0) # Make shared function pace mixed_vector_function_space = df.VectorFunctionSpace( mesh, "DG", 0, dim=num_global_states + 1 ) # Create previous solution and assign initial conditions previous_solution = df.Function(mixed_vector_function_space) # _model = xb.cellmodels.Cressman() # previous_solution.assign(_model.initial_conditions()) # Initial condition previous_solution.assign(model.initial_conditions()) # Initial condition v_previous, s_previous = splat(previous_solution, num_global_states + 1) # Create current solution current_solution = df.Function(mixed_vector_function_space) v_current, s_current = splat(current_solution, num_global_states + 1) # Create test functions test_functions = df.TestFunction(mixed_vector_function_space) test_v, test_s = splat(test_functions, num_global_states + 1) # Crate time derivatives Dt_v = (v_current - v_previous)/const_dt Dt_s = (s_current - s_previous)/const_dt # Create midpoint evaluations following theta rule v_mid = theta*v_current + (1.0 - theta)*v_previous s_mid = theta*s_current + (1.0 - theta)*s_previous if isinstance(model, xb.MultiCellModel): # model = xb.cellmodels.Cressman() # dy = df.Measure("dx", domain=mesh) # F_theta = model.F(v_mid, s_mid, time=current_time) # I_theta = -model.I(v_mid, s_mid, time=current_time) # lhs = (Dt_v - I_theta)*test_v # lhs += df.inner(Dt_s - F_theta, test_s) # lhs *= dy() dy = df.Measure("dx", domain=mesh, subdomain_data=model.markers()) domain_indices = model.keys() lhs_list = list() for k, model_k in enumerate(model.models()): domain_index_k = domain_indices[k] F_theta = model.F(v_mid, s_mid, time=current_time, index=domain_index_k) I_theta = -model.I(v_mid, s_mid, time=current_time, index=domain_index_k) a = (Dt_v - I_theta)*test_v a += df.inner(Dt_s - F_theta, test_s) a *= dy(domain_index_k) lhs_list.append(a) # Sum the form lhs = sum(lhs_list) else: # Evaluate currents at averaged v and s. Note sign for I_theta model = xb.cellmodels.Cressman() dy = df.Measure("dx", domain=mesh) F_theta = model.F(v_mid, s_mid, time=current_time) I_theta = -model.I(v_mid, s_mid, time=current_time) lhs = (Dt_v - I_theta)*test_v lhs += df.inner(Dt_s - F_theta, test_s) lhs *= dy() rhs = stimulus*test_v*dy() G = lhs - rhs # Solve system current_solution.assign(previous_solution) pde = df.NonlinearVariationalProblem( G, current_solution, J=df.derivative(G, current_solution) ) solver = df.NonlinearVariationalSolver(pde) solver.solve()
F_nu = geo_map.form(nu_*eta + geo_map.gab[i, j]*psi_.dx(i)*eta.dx(j)) F_nuhat = geo_map.form(nuhat_*etahat + geo_map.Kab[i, j]*psi_.dx(i)*etahat.dx(j)) F = F_psi + F_mu + F_nu + F_nuhat # a = df.lhs(F) # L = df.rhs(F) J = df.derivative(F, u_, du=u) # SOLVER # problem = df.LinearVariationalProblem(a, L, u_) # solver = df.LinearVariationalSolver(problem) problem = df.NonlinearVariationalProblem(F, u_, J=J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"]["absolute_tolerance"] = 1e-8 solver.parameters["newton_solver"]["relative_tolerance"] = 1e-6 solver.parameters["newton_solver"]["maximum_iterations"] = 16 # solver.parameters["newton_solver"]["linear_solver"] = "gmres" # solver.parameters["newton_solver"]["preconditioner"] = "default" # solver.parameters["newton_solver"]["krylov_solver"]["nonzero_initial_guess"] = True # solver.parameters["newton_solver"]["krylov_solver"]["absolute_tolerance"] = 1e-8 # solver.parameters["newton_solver"]["krylov_solver"]["monitor_convergence"] = False # solver.parameters["newton_solver"]["krylov_solver"]["maximum_iterations"] = 1000 # solver.parameters["linear_solver"] = "gmres" # solver.parameters["preconditioner"] = "jacobi" df.parameters["form_compiler"]["optimize"] = True df.parameters["form_compiler"]["cpp_optimize"] = True
def equilibrium_solver(F, u, bcs, bcs_set_values, bcs_values, **kwargs): '''Nonlinear solver for the hyper-elastic equilibrium problem. F : dolfin.Form Variational form of equilibrium, i.e. F(u;v)==0 forall v. Usually `F` is obtained by taking the derivative of the potential energy `W`, e.g. `F = dolfin.derivative(W, u)` u : dolfin.Function Displacement function (or a mixed field function). bcs : (sequence of) dolfin.DirichletBC's Dirichlet boundary conditions. bcs_set_values : function Called with elements of `bcs_values`. bcs_values : numpy.ndarray (2D) Sequence of displacement values. umin: dolfin.Expression, dolfin.Function, dolfin.GenericVector Enfores displacement lower bound: `u >= umin`. umax: dolfin.Expression, dolfin.Function, dolfin.GenericVector Enfores displacement upper bound: `u <= umax`. ''' if not isinstance(bcs_values, np.ndarray) or bcs_values.ndim != 2: raise TypeError('Parameter `bcs_values` must be a 2D `numpy.ndarray`') try: bcs_set_values(bcs_values[-1]) except: logger.error('Unable to set Dirichlet boundary conditions') raise dFdu = dolfin.derivative(F, u) nonlinear_problem = dolfin.NonlinearVariationalProblem(F, u, bcs, dFdu) nonlinear_solver = dolfin.NonlinearVariationalSolver(nonlinear_problem) update_parameters(nonlinear_solver.parameters, config.parameters_nonlinear_solver) umin = kwargs.get('umin') umax = kwargs.get('umax') if umax is not None or umin is not None: V = u.function_space() if isinstance(umin, dolfin.Function): umin = umin.vector() elif isinstance(umin, dolfin.Expression): umin = dolfin.interpolate(umin, V).vector() elif umin is None: umin = dolfin.Function(V).vector() umin[:] = -np.inf elif not isinstance(umin, dolfin.GenericVector) or umin.size() != V.dim(): raise TypeError("Key-word argument `umin` must be an instance of: " "`dolfin.Function`, `dolfin.Expression`, or `dolfin.GenericVector` " "(with the correct dimension).") if isinstance(umax, dolfin.Function): umax = umax.vector() elif isinstance(umax, dolfin.Expression): umax = dolfin.interpolate(umax, V).vector() elif umax is None: umax = dolfin.Function(V).vector() umax[:] = np.inf elif not isinstance(umax, dolfin.GenericVector) or umax.size() != V.dim(): raise TypeError("Key-word argument `umax` must be an instance of: " "`dolfin.Function`, `dolfin.Expression`, or `dolfin.GenericVector` " "(with the correct dimension).") if not (config.parameters_nonlinear_solver['nonlinear_solver'] == 'snes' and config.parameters_nonlinear_solver['snes_solver']['method'] == 'vinewtonrsls'): logger.warning("Require \"snes\" solver and method called \"vinewtonrsls\" " "to impose displacement field bounds `umin` and `umax`.") nonlinear_problem.set_bounds(umin, umax) def equilibrium_solve(incremental=False): if incremental: nonlocal bcs_values u.vector()[:] = 0.0 u_arr_backup = None try: for i, values_i in enumerate(bcs_values): logger.info(f'Solving for load {values_i}') bcs_set_values(values_i) nonlinear_solver.solve() u_arr_backup = u.vector().get_local() except RuntimeError: logger.error('Could not solve equilibrium problem for load ' f'{values_i}; assuming previous load value.') if u_arr_backup is None: raise RuntimeError('Previous load value is not available') u.vector()[:] = u_arr_backup bcs_values = bcs_values[:i] else: try: nonlinear_solver.solve() except RuntimeError: logger.error('Could not solve equilibrium problem; ' 'Trying to re-load incrementally.') equilibrium_solve(incremental=True) return equilibrium_solve