def _init_forms(self): u = self.state v = self.state_test F = dolfin.variable(DeformationGradient(u)) J = Jacobian(F) dx = self.geometry.dx # Add penalty term internal_energy = self.material.strain_energy(F) \ + self.kappa * (J * dolfin.ln(J) - J + 1) self._virtual_work \ = dolfin.derivative(internal_energy * dx, self.state, self.state_test) self._virtual_work += self._external_work(u, v) self._jacobian \ = dolfin.derivative(self._virtual_work, self.state, dolfin.TrialFunction(self.state_space)) self._set_dirichlet_bc()
def solver_setup(F_fluid_linear, F_fluid_nonlinear, F_solid_linear, F_solid_nonlinear, DVP, dvp_, up_sol, compiler_parameters, **namespace): """ Pre-assemble the system of equations for the Jacobian matrix for the Newton solver """ F_lin = F_fluid_linear + F_solid_linear F_nonlin = F_solid_nonlinear + F_fluid_nonlinear F = F_lin + F_nonlin chi = TrialFunction(DVP) J_linear = derivative(F_lin, dvp_["n"], chi) J_nonlinear = derivative(F_nonlin, dvp_["n"], chi) A_pre = assemble(J_linear, form_compiler_parameters=compiler_parameters, keep_diagonal=True) A = Matrix(A_pre) b = None # Option not available in FEniCS 2018.1.0 # up_sol.parameters['reuse_factorization'] = True return dict(F=F, J_nonlinear=J_nonlinear, A_pre=A_pre, A=A, b=b, up_sol=up_sol)
def define_ufl_stress_work_diff(self): """ Define the UFL object corresponding to the Gateaux derivative of the stress tensor term in the weak form. The function exits if it has already been defined. """ if hasattr(self, 'ufl_stress_work_diff'): return None if self.displacement != 0: # Derivative of stress term w.r.t. to displacement. self.ufl_stress_work_du = dlf.derivative(self.ufl_stress_work, self.displacement, self.trial_vector) else: self.ufl_stress_work_du = 0 if self.velocity != 0: self.ufl_stress_work_dv = dlf.derivative(self.ufl_stress_work, self.velocity, self.trial_vector) else: self.ufl_stress_work_dv = 0 if self.pressure != 0: self.ufl_stress_work_dp = dlf.derivative(self.ufl_stress_work, self.pressure, self.trial_scalar) else: self.ufl_stress_work_dp = 0 return None
def Jacobian(self, x, x_test, x_trial, sigma, m, x0, xl, true_derivative=False): """ Returns the weak form of the Jacobian matrix. INPUTS: - x: the state at which evaluate the Jacobian - x_test: the test function - x_trial: the trial function - sigma: the inverse of the time-step - m: the uncertain parameter - x0: the state at the previous time step - xl: the auxiliary state to compute the Picard Jacobian (if None then xl is a copy of x) - true_derivative: if true compute the true Jacobian, if false compute the Picard Jacobian """ if x0 is None: x0 = vector2Function(x.vector(), self.Vh) if xl is None: xl = vector2Function(x.vector(), self.Vh) r = self.residual(x, x_test, sigma, m, x0, xl, true_derivative) if true_derivative: return dl.derivative(r, x, x_trial) + dl.derivative(r, xl, x_trial) else: return dl.derivative(r, x, x_trial)
def _init_forms(self): logger.debug("Initialize forms mechanics problem") # Displacement and hydrostatic_pressure u, p = dolfin.split(self.state) v, q = dolfin.split(self.state_test) # Some mechanical quantities F = dolfin.variable(kinematics.DeformationGradient(u)) J = kinematics.Jacobian(F) dx = self.geometry.dx internal_energy = (self.material.strain_energy(F, ) + self.material.compressibility(p, J)) self._virtual_work = dolfin.derivative( internal_energy * dx, self.state, self.state_test, ) external_work = self._external_work(u, v) if external_work is not None: self._virtual_work += external_work self._set_dirichlet_bc() self._jacobian = dolfin.derivative( self._virtual_work, self.state, dolfin.TrialFunction(self.state_space), ) self._init_solver()
def stab(self, x, x_test, m, true_derivative): """ The G-LS stabilization """ r_s = self.strong_residual(x, m) r_s_prime = [None, None] if true_derivative: for i in range(2): r_s_prime[i] = dl.derivative(r_s[i], x, x_test) tau = self.all_tau(x, m) else: xl = vector2Function(x.vector(), self.Vh) r_sl = self.strong_residual(xl, m) for i in range(2): r_s_prime[i] = dl.derivative(r_sl[i], xl, x_test) tau = self.all_tau(xl, m) res_stab = ( tau[0]*dl.inner(r_s[0], r_s_prime[0]) + \ tau[1]*dl.inner(r_s[1], r_s_prime[1]) )*dl.dx return res_stab
def _init_forms(self): u, p, pinn = dolfin.split(self.state) v, q, qinn = dolfin.split(self.state_test) F = dolfin.variable(DeformationGradient(u)) J = Jacobian(F) ds = self.geometry.ds dsendo = ds(self.geometry.markers['ENDO']) dx = self.geometry.dx endoarea = dolfin.assemble(dolfin.Constant(1.0) * dsendo) internal_energy = self.material.strain_energy(F) * dx \ + self.material.compressibility(p, J) * dx \ + (pinn * (self._V0/endoarea - self._Vu)) * dsendo self._virtual_work \ = dolfin.derivative(internal_energy, self.state, self.state_test) self._virtual_work += self._external_work(u, v) self._jacobian \ = dolfin.derivative(self._virtual_work, self.state, dolfin.TrialFunction(self.state_space)) self._set_dirichlet_bc()
def _solveTangentProblem(self, dstate, m_hat, x): """ The predictor step for the parameter continuation algorithm. """ state_fun = vector2Function(x[STATE], self.Vh[STATE]) statel_fun = vector2Function(x[STATE], self.Vh[STATE]) param_fun = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) param_hat_fun = vector2Function(m_hat, self.Vh[PARAMETER]) x_test = [ dl.TestFunction(self.Vh[STATE]), dl.TestFunction(self.Vh[PARAMETER]) ] x_trial = [ dl.TrialFunction(self.Vh[STATE]), dl.TrialFunction(self.Vh[PARAMETER]) ] res = self.model.residual(state_fun, x_test[STATE], dl.Constant(0.), param_fun, None, statel_fun, True) Aform = dl.derivative(res, state_fun, x_trial[STATE]) + dl.derivative( res, statel_fun, x_trial[STATE]) b_form = dl.derivative(res, param_fun, param_hat_fun) A, b = dl.assemble_system(Aform, b_form, self.bcs0, form_compiler_parameters=self.fcp) solver = dl.PETScLUSolver() solver.set_operator(A) solver.solve(dstate, -b)
def linearize(self, inputs, outputs, partials): pde_problem = self.options['pde_problem'] state_name = self.options['state_name'] state_function = pde_problem.states_dict[state_name]['function'] residual_form = pde_problem.states_dict[state_name]['residual_form'] self._set_values(inputs, outputs) derivative_form = df.derivative(residual_form, state_function) derivative_assembled = df.assemble(derivative_form) for bc in pde_problem.bcs_list: bc.apply(derivative_assembled) derivative_petsc_sparse = df.as_backend_type( derivative_assembled).mat() derivative_csr = csr_matrix( derivative_petsc_sparse.getValuesCSR()[::-1], shape=derivative_petsc_sparse.size) partials[state_name, state_name] = derivative_csr.tocoo().data for argument_name, argument_function in iteritems( self.argument_functions_dict): derivative_form_arg = df.derivative(residual_form, argument_function) derivative_form_arg_assembled = df.assemble(derivative_form_arg) for bc in pde_problem.bcs_list: bc.apply(derivative_form_arg_assembled) derivative_petsc_sparse_arg = df.as_backend_type( derivative_form_arg_assembled).mat() derivative_csr_arg = csr_matrix( derivative_petsc_sparse_arg.getValuesCSR()[::-1], shape=derivative_petsc_sparse_arg.size) partials[state_name, argument_name] = derivative_csr_arg.tocoo().data
def setLinearizationPoint(self, x): u = vector2Function(x[STATE], self.Vh[STATE]) m = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) x = [u, m] for i in range(2): di_form = dl.derivative(self.qoi_varf(*x), x[i]) for j in range(i, 2): dij_form = dl.derivative(di_form, x[j]) self.L[i, j] = dl.assemble(dij_form)
def setLinearizationPoint(self, x): self.u = vector2Function(x[STATE], self.Vh[STATE]) self.m = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) x = [self.u,self.m] form = self.form(x) for i in range(2): di_form = dl.derivative(form, x[i]) for j in range(2): dij_form = dl.derivative(di_form,x[j] ) self.L[i,j] = dl.assemble(dij_form)
def define_ufl_equations_diff(self): """ Differentiate all of the variational forms with respect to appropriate fields variables and add as member data. """ # Derivatives of velocity integration equation. if self.f1 != 0: self.df1_du = dlf.derivative(self.f1, self.displacement, self.trial_vector) self.df1_dv = dlf.derivative(self.f1, self.velocity, self.trial_vector) else: self.df1_du = 0 self.df1_dv = 0 self.df1_dp = 0 # This is always zero. # Derivatives of momentum equation. if self.displacement != 0: self.df2_du = dlf.derivative(self.f2, self.displacement, self.trial_vector) else: self.df2_du = 0 if self.velocity != 0: self.df2_dv = dlf.derivative(self.f2, self.velocity, self.trial_vector) else: self.df2_dv = 0 if self.pressure != 0: self.df2_dp = dlf.derivative(self.f2, self.pressure, self.trial_scalar) else: self.df2_dp = 0 # Derivatives of incompressibility equation. if self.f3 != 0: if self.displacement != 0: self.df3_du = dlf.derivative(self.f3, self.displacement, self.trial_vector) else: self.df3_du = 0 if self.velocity != 0: self.df3_dv = dlf.derivative(self.f3, self.velocity, self.trial_vector) else: self.df3_dv = 0 self.df3_dp = dlf.derivative(self.f3, self.pressure, self.trial_scalar) else: self.df3_du = 0 self.df3_dv = 0 self.df3_dp = 0 return None
def solve_adjoint(): a = a1 + a2 + a3 + a4 + a5 a = derivative(a, T, TestFunction(V)) a = replace(a, {lmb: TrialFunction(V)}) l = derivative(-J1, T, TestFunction(V)) a = assemble_multimesh(a) L = assemble_multimesh(l) bcs = [ MultiMeshDirichletBC(V, Constant(0), mfs[0], 1, 0), MultiMeshDirichletBC(V, Constant(0), mfs[1], 2, 1) ] [bc.apply(a, L) for bc in bcs] V.lock_inactive_dofs(a, L) solve(a, lmb.vector(), L)
def __init__(self, mesh, parameters=[], isprint=False): self.parameters = {} self.parameters['eps'] = 0.0 self.parameters['k'] = 1.0 self.parameters['correctcost'] = True self.parameters.update(parameters) eps = self.parameters['eps'] k = self.parameters['k'] self.V = FunctionSpace(mesh, 'CG', 1) self.tmp1, self.tmp2 = Function(self.V), Function(self.V) self.VV = VectorFunctionSpace(mesh, 'CG', 1, 2) self.m = Function(self.VV) self.mtest = TestFunction(self.VV) self.mtrial = TrialFunction(self.VV) self.m1, self.m2 = split(self.m) self.mh = Function(self.VV) normg1 = inner(nabla_grad(self.m1), nabla_grad(self.m1)) normg2 = inner(nabla_grad(self.m2), nabla_grad(self.m2)) if self.parameters['correctcost']: meshtmp = UnitSquareMesh(mesh.mpi_comm(), 10, 10) Vtmp = FunctionSpace(meshtmp, 'CG', 1) x = SpatialCoordinate(meshtmp) self.correctioncost = 1. / assemble(sqrt(4.0 * x[0] * x[0]) * dx) print '[NuclearNormformula] Correction cost with factor={}'.format( self.correctioncost) else: self.correctioncost = 1.0 self.cost = 1./np.sqrt(2.0) * Constant(k) * (\ sqrt(normg1 + normg2 + Constant(np.sqrt(eps)) + sqrt((normg1 - normg2)**2 + Constant(eps) + 4.0*inner(nabla_grad(self.m1), nabla_grad(self.m2))**2)) + sqrt(normg1 + normg2 + Constant(np.sqrt(eps)*(1.0+1e-15)) - sqrt((normg1 - normg2)**2 + Constant(eps) + 4.0*inner(nabla_grad(self.m1), nabla_grad(self.m2))**2)))*dx self.grad = derivative(self.cost, self.m, self.mtest) self.hessian = derivative(self.grad, self.m, self.mtrial) M = assemble(inner(self.mtest, self.mtrial) * dx) factM = 1e-2 * k self.sMass = M * factM if isprint: print '[NuclearNormformula] eps={}, k={}'.format(eps, k) self.amgprecond = amg_solver()
def stab(self, x, x_test, m, x0, xl, true_derivative=False): """ The G-LS stabilization """ r_s = self.strong_residual(x, m, xl) r_s_prime = [None, None, None, None] #if true_derivative: # for i in range(4): # r_s_prime[i] = dl.derivative(r_s[i], x, x_test) + dl.derivative(r_s[i], xl, x_test) #else: # for i in range(4): # r_s_prime[i] = dl.derivative(r_s[i], x, x_test) for i in range(4): r_s_prime[i] = dl.derivative(r_s[i], x, x_test) tau = self.all_tau(xl, m) res_stab = ( tau[0]*dl.inner(r_s[0], r_s_prime[0]) + \ tau[1]*dl.inner(r_s[1], r_s_prime[1]) + \ tau[2]*dl.inner(r_s[2], r_s_prime[2]) + \ tau[3]*dl.inner(r_s[3], r_s_prime[3]) )*dl.dx return res_stab
def solve(self, dt): self.u = Function(self.V0) self.w = TestFunction(self.V0) self.du = TrialFunction(self.V0) x = SpatialCoordinate(self.mesh0) L = inner( self.S(), self.eps(self.w) )*dx(degree=4)\ - inner( self.b, self.w )*dx(degree=4)\ - inner( self.h, self.w )*ds(degree=4)\ + inner( 1e-6*self.u, self.w )*ds(degree=4)\ - inner( min_value(x[2]+self.ut[2]+self.u[2], 0) * Constant((0,0,-1.0)), self.w )*ds(degree=4) a = derivative(L, self.u, self.du) problem = NonlinearVariationalProblem(L, self.u, bcs=[], J=a) solver = NonlinearVariationalSolver(problem) solver.solve() self.ut.vector()[:] = self.ut.vector()[:] + self.u.vector()[:] ALE.move(self.mesh, Function(self.V, self.u.vector())) self.v.vector()[:] = self.u.vector()[:] / dt self.n = FacetNormal(self.mesh)
def apply_ijk(self, i, j, k, x, jdir, kdir, out): x_fun = [vector2Function(x[ii], self.Vh[ii]) for ii in range(3)] idir_fun = dl.TestFunction(self.Vh[i]) jdir_fun = vector2Function(jdir, self.Vh[j]) kdir_fun = vector2Function(kdir, self.Vh[k]) res_form = self.varf_handler(*x_fun) form = dl.derivative( dl.derivative(dl.derivative(res_form, x_fun[i], idir_fun), x_fun[j], jdir_fun), x_fun[k], kdir_fun) out.zero() dl.assemble(form, tensor=out) if i in [STATE, ADJOINT]: [bc.apply(out) for bc in self.bc0]
def custom_newton_solver(self): V = self.my_function_space_cls.V F = self.my_var_prob_cls.F #self.u = my_function_space_cls.u du = df.TrialFunction(V) #TrialFunctions --> wrong, without 's' Jac = df.derivative(F, self.u, du) absolute_tol = 1E-5 relative_tol = 9E-2 u_inc = df.Function(V) nIter = 0 relative_residual = 1 CONVERGED = True MAX_ITER = 5000 while relative_residual > relative_tol and nIter < MAX_ITER and CONVERGED: nIter += 1 A, b = df.assemble_system(Jac, -(F), []) df.solve(A, u_inc.vector(), b) #df.solve(F == 0, u_inc.vector(), [], J=Jac, solver_parameters={'newton_solver' : {'linear_solver' : 'mumps'}}) relative_residual = u_inc.vector().norm('l2') #a = df.assemble(F) residual = b.norm('l2') lmbda = 0.8 self.u.vector()[:] += lmbda * u_inc.vector() if residual > 1000: CONVERGED = False print("Did not converge after {} Iterations".format(nIter)) elif residual < absolute_tol: CONVERGED = False print("converged after {} Iterations".format(nIter)) print('{0:2d} {1:3.2E} {2:5e}'.format(nIter, relative_residual, residual))
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 block_derivative(F, u, du): assert isinstance(F, (array, list, BlockForm1)) if isinstance(F, (array, list)): input_type = array (F, block_V, block_form_rank) = _block_form_preprocessing(F) assert block_form_rank == 1 else: input_type = BlockForm1 block_V = F.block_function_spaces() assert len(block_V) == 1 block_V = block_V[0] # Compute the derivative assert len(F) == len(u) == len(du) J = empty((len(F), len(u)), dtype=object) for i in range(len(F)): if not _is_zero(F[i]): for j in range(len(u)): J[i, j] = derivative(F[i], u[j], du[j]) else: J[i, :] = 0 if input_type is array: return J elif input_type is BlockForm1: return BlockForm2(J, block_function_space=[du.block_function_space(), block_V])
def define_ufl_convec_accel_diff(self): """ Define the UFL object corresponding to the Gateaux derivative of the convective acceleration term in the weak form. The function exits if it has already been defined. """ if hasattr(self, 'ufl_convec_accel_dv'): return None # Exit if problem is formulated with respect to Eulerian # coordinates and is not an elastic material. eulerian = self.config['formulation']['domain'] == 'eulerian' lin_elastic = self.config['material']['const_eqn'] == 'lin_elastic' stokes = self.config['material']['const_eqn'] == 'stokes' if (not eulerian) or lin_elastic or stokes: self.ufl_convec_accel_dv = 0 return None self.ufl_convec_accel_dv = dlf.derivative(self.ufl_convec_accel, self.velocity, self.trial_vector) return None
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 assemble_operator_for_derivative_decorator_impl(self, term): residual_term = jacobian_term_to_residual_term.get(term) if residual_term is None: # term was not a jacobian_term return assemble_operator(self, term) else: trial = TrialFunction(self.V) return tuple(derivative(op, self._solution, trial) for op in assemble_operator(self, residual_term))
def derivative(form, u, du = None, expand = True): """ Wrapper for the DOLFIN derivative function. This attempts to select an appropriate du if one is not supplied. Correctly handles QForm s. By default the returned Form is first expanded using ufl.algorithms.expand_derivatives. This can be disabled if the optional expand argument is False. """ if du is None: if isinstance(u, dolfin.Constant): du = dolfin.Constant(1.0) elif isinstance(u, dolfin.Function): rank = form_rank(form) if rank == 0: du = dolfin.TestFunction(u.function_space()) elif rank == 1: du = dolfin.TrialFunction(u.function_space()) der = dolfin.derivative(form, u, du = du) if expand: der = ufl.algorithms.expand_derivatives(der) if isinstance(form, QForm): return QForm(der, quadrature_degree = form.quadrature_degree()) else: return der
def solveAdj(self, adj, x, adj_rhs, tol): """ Solve the linear Adj Problem: Given a, u; find p such that \delta_u F(u,a,p;\hat_u) = 0 \for all \hat_u """ u = vector2Function(x[STATE], self.Vh[STATE]) a = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) p = dl.Function(self.Vh[ADJOINT]) du = dl.TestFunction(self.Vh[STATE]) dp = dl.TrialFunction(self.Vh[ADJOINT]) varf = self.varf_handler(u,a,p) adj_form = dl.derivative( dl.derivative(varf, u, du), p, dp ) Aadj, dummy = dl.assemble_system(adj_form, dl.Constant(0.)*dl.inner(u,du)*dl.dx, self.bc0) solver = dl.PETScLUSolver() solver.set_operator(Aadj) solver.solve(adj, adj_rhs)
def __init__(self, ui, time_step_method, rho, mu, u, p0, dt, bcs, f, my_dx): super(TentativeVelocityProblem, self).__init__() W = ui.function_space() v = TestFunction(W) self.bcs = bcs r = SpatialCoordinate(ui.function_space().mesh())[0] def me(uu, ff): return _momentum_equation(uu, v, p0, ff, rho, mu, my_dx) self.F0 = rho * dot(ui - u[0], v) / dt * 2 * pi * r * my_dx if time_step_method == "forward euler": self.F0 += me(u[0], f[0]) elif time_step_method == "backward euler": self.F0 += me(ui, f[1]) else: assert ( time_step_method == "crank-nicolson" ), "Unknown time stepper '{}'".format( time_step_method ) self.F0 += 0.5 * (me(u[0], f[0]) + me(ui, f[1])) self.jacobian = derivative(self.F0, ui) self.reset_sparsity = True return
def __init__(self, Th, callback_type): # Create mesh and define function space mesh = UnitSquareMesh(Th, Th) self.V = FunctionSpace(mesh, "Lagrange", 1) # Define variational problem du = TrialFunction(self.V) v = TestFunction(self.V) self.u = Function(self.V) self.r = lambda u, g: inner(grad(u), grad(v)) * dx + inner( u + u**3, v) * dx - g * v * dx self.j = lambda u, r: derivative(r, u, du) # Define initial guess self.initial_guess_expression = Expression( "0.1 + 0.9*x[0]*x[1]", element=self.V.ufl_element()) # Define callback function depending on callback type assert callback_type in ("form callbacks", "tensor callbacks") if callback_type == "form callbacks": def callback(arg): return arg elif callback_type == "tensor callbacks": def callback(arg): return assemble(arg) self.callback_type = callback_type self.callback = callback
def get_residual_form(u, v, rho_e, method='RAMP'): df.dx = df.dx(metadata={"quadrature_degree": 4}) # stiffness = rho_e/(1 + 8. * (1. - rho_e)) if method == 'SIMP': stiffness = rho_e**3 else: #RAMP stiffness = rho_e / (1 + 8. * (1. - rho_e)) # print('the value of stiffness is:', rho_e.vector().get_local()) # Kinematics k = 3e1 E = k * stiffness nu = 0.3 mu, lmbda = (E / (2 * (1 + nu))), (E * nu / ((1 + nu) * (1 - 2 * nu))) d = len(u) I = df.Identity(d) # Identity tensor F = I + df.grad(u) # Deformation gradient C = F.T * F # Right Cauchy-Green tensor E_ = 0.5 * (C - I) # Green--Lagrange strain S = 2.0 * mu * E_ + lmbda * df.tr(E_) * df.Identity( d) # stress tensor (C:eps) psi = 0.5 * df.inner(S, E_) # 0.5*eps:C:eps # Total potential energy Pi = psi * df.dx # Solve weak problem obtained by differentiating Pi: res = df.derivative(Pi, u, v) return res
def _external_work(self, u, v): F = dolfin.variable(kinematics.DeformationGradient(u)) N = self.geometry.facet_normal ds = self.geometry.ds dx = self.geometry.dx external_work = [] for neumann in self.bcs.neumann: n = neumann.traction * ufl.cofac(F) * N external_work.append(dolfin.inner(v, n) * ds(neumann.marker)) for robin in self.bcs.robin: external_work.append( dolfin.inner(robin.value * u, v) * ds(robin.marker)) for body_force in self.bcs.body_force: external_work.append( -dolfin.derivative(dolfin.inner(body_force, u) * dx, u, v), ) if len(external_work) > 0: return list_sum(external_work) return None
def grad_param(self, x, g): """Evaluate the gradient with respect to the state. Only the state u and (possibly) the parameter m are accessed. """ u = vector2Function(x[STATE], self.Vh[STATE]) m = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) g.zero() dl.assemble(dl.derivative(self.qoi_varf(u, m), m), tensor=g)
def __init__(self, ui, theta, rho, mu, u, p0, dt, bcs, f0, f1, stabilization=False, dx=dx ): super(TentativeVelocityProblem, self).__init__() W = ui.function_space() v = TestFunction(W) self.bcs = bcs r = Expression('x[0]', degree=1, domain=ui.function_space().mesh()) #self.F0 = rho * dot(3*ui - 4*u[-1] + u[-2], v) / (2*Constant(dt)) \ # * 2*pi*r*dx #self.F0 += momentum_equation(ui, v, # p0, # f1, # rho, mu, # stabilization=stabilization, # dx=dx # ) self.F0 = rho * dot(ui - u[-1], v) / Constant(dt) \ * 2*pi*r*dx if abs(theta) > DOLFIN_EPS: # Implicit terms. if f1 is None: raise RuntimeError('Implicit schemes need right-hand side ' 'at target step (f1).') self.F0 += theta \ * momentum_equation(ui, v, p0, f1, rho, mu, stabilization=stabilization, dx=dx ) if abs(1.0 - theta) > DOLFIN_EPS: # Explicit terms. if f0 is None: raise RuntimeError('Explicit schemes need right-hand side ' 'at current step (f0).') self.F0 += (1.0 - theta) \ * momentum_equation(u[-1], v, p0, f0, rho, mu, stabilization=stabilization, dx=dx ) self.jacobian = derivative(self.F0, ui) self.reset_sparsity = True return
def setLinearizationPoint(self, x): """ Set the values of the state and parameter for the incremental Fwd and Adj solvers """ u = vector2Function(x[STATE], self.Vh[STATE]) a = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) p = vector2Function(x[ADJOINT], self.Vh[ADJOINT]) x_fun = [u, a, p] f_form = self.varf_handler(u, a, p) g_form = [None, None, None] for i in range(3): g_form[i] = dl.derivative(f_form, x_fun[i]) self.A, dummy = dl.assemble_system(dl.derivative(g_form[ADJOINT], u), g_form[ADJOINT], self.bc0) self.At, dummy = dl.assemble_system(dl.derivative(g_form[STATE], p), g_form[STATE], self.bc0) self.C = dl.assemble(dl.derivative(g_form[ADJOINT], a)) self.bc0.zero(self.C) self.Wau = dl.assemble(dl.derivative(g_form[PARAMETER], u)) Wau_t = Transpose(self.Wau) self.bc0.zero(Wau_t) self.Wau = Transpose(Wau_t) self.Wuu = dl.assemble(dl.derivative(g_form[STATE], u)) self.bc0.zero(self.Wuu) Wuu_t = Transpose(self.Wuu) self.bc0.zero(Wuu_t) self.Wuu = Transpose(Wuu_t) self.Waa = dl.assemble(dl.derivative(g_form[PARAMETER], a)) self.solver_fwd_inc.set_operator(self.A) self.solver_adj_inc.set_operator(self.At)
def __init__( self, WPQ, kappa, rho, rho_const, mu, cp, g, extra_force, heat_source, u_bcs, p_bcs, theta_dirichlet_bcs=None, theta_neumann_bcs=None, theta_robin_bcs=None, my_dx=dx, my_ds=ds ): super(StokesHeat, self).__init__() theta_dirichlet_bcs = theta_dirichlet_bcs or {} theta_neumann_bcs = theta_neumann_bcs or {} theta_robin_bcs = theta_robin_bcs or {} # Translate the Dirichlet boundary conditions into the product space. self.dirichlet_bcs = helpers.dbcs_to_productspace( WPQ, [u_bcs, p_bcs, theta_dirichlet_bcs] ) self.uptheta = Function(WPQ) u, p, theta = split(self.uptheta) v, q, zeta = TestFunctions(WPQ) mesh = WPQ.mesh() r = SpatialCoordinate(mesh)[0] # Right-hand side for momentum equation. f = rho(theta) * g # coupling if extra_force is not None: f += as_vector((extra_force[0], extra_force[1], 0.0)) self.stokes_F = stokes.F( u, p, v, q, f, r, mu, my_dx ) self.heat_F = heat.F( theta, zeta, kappa=kappa, rho=rho_const, cp=cp, convection=u, # coupling source=heat_source, r=r, neumann_bcs=theta_neumann_bcs, robin_bcs=theta_robin_bcs, my_dx=my_dx, my_ds=my_ds ) self.F0 = self.stokes_F + self.heat_F self.jacobian = derivative(self.F0, self.uptheta) return
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 solve_system(self,rhs,factor,u0,t): """ Dolfin's linear solver for (M-dtA)u = rhs Args: rhs: right-hand side for the nonlinear system factor: abbrev. for the node-to-node stepsize (or any other factor required) u0: initial guess for the iterative solver (not used here so far) Returns: solution as mesh """ sol = fenics_mesh(self.V) # self.g.t = t self.w.assign(sol.values) 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 # df.set_log_level(df.PROGRESS) solver.solve() sol.values.assign(self.w) return sol
def __init__(self, WP, rho, mu, f, u_bcs, p_bcs, dx, stabilization=None): super(NavierStokesCylindrical, self).__init__() # self.WP = WP # Translate the boundary conditions into the product space. self.bcs = [] for k, bcs in enumerate([u_bcs, p_bcs]): for bc in bcs: space = bc.function_space() C = space.component() if len(C) == 0: self.bcs.append(DirichletBC(self.WP.sub(k), bc.value(), bc.domain_args[0])) elif len(C) == 1: self.bcs.append(DirichletBC(self.WP.sub(k).sub(int(C[0])), bc.value(), bc.domain_args[0])) else: raise RuntimeError('Illegal number of ' 'subspace components.' ) # self.up = Function(self.WP) u, p = self.up.split() v, q = TestFunctions(self.WP) # Momentum equation. self.F0 = momentum_equation(u, v, p, f, rho, mu, stabilization=stabilization, dx=dx ) # div_u = 1/r * div(r*u) r = Expression('x[0]', degree=1, domain=WP.mesh()) self.F0 += (1.0 / r * (r * u[0]).dx(0) + u[1].dx(1)) * q \ * 2 * pi * r * dx self.jacobian = derivative(self.F0, self.up) self.reset_sparsity = True return
def solve_system(self,rhs,factor,u0,t): """ Dolfin's linear solver for (M-dtA)u = rhs Args: rhs: right-hand side for the nonlinear system factor: abbrev. for the node-to-node stepsize (or any other factor required) u0: initial guess for the iterative solver (not used here so far) Returns: solution as mesh """ sol = fenics_mesh(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-8 prm['newton_solver']['relative_tolerance'] = 1E-7 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
m4 = 4.49 m5 = 4.49 m6 = 12.02 m = (m0,m1,m2,m3,m4,m5,m6) parameters = dl.interpolate(dl.Constant(m),parameterV) #Model d = len(u) I = dl.Identity(d) # Identity tensor F = I + dl.grad(u) # Deformation gradient C = F.T*F # Right Cauchy-Green tensor J = dl.det(F) # Jacobian of deformation gradient Cbar = C*(J**(-2.0/3.0)) # Deviatoric Right Cauchy-Green tensor E = dl.Constant(0.5)*(Cbar-I) # Deviatoric Green strain c0,c1,c2,c3,c4,c5,c6 = dl.split(parameters) Q = c1*(E[0,0]**2)+c2*(E[1,1]**2)+c3*(E[2,2]**2) + c4*(dl.Constant(4.0)*(E[1,2]**2)) #+c5*(dl.Constant(4.0)*(E[0,1]**2))#)#+c6*(dl.Constant(4.0)*(E[0,2]**2)) Energy = dl.Constant(0.5)*c0*(dl.exp(Q)-dl.Constant(1.0)) IncompressibilityConstraint = (J-dl.Constant(1.0)) Lagrangian = p*IncompressibilityConstraint*dl.dx + Energy*dl.dx yhat = dl.interpolate(dl.Constant((1,1,1,1)),TaylorHoodV) residual_form = dl.derivative(Lagrangian,y,yhat) residual_form_a = dl.derivative(residual_form, a,atest) residual_form_y = dl.derivative(residual_form, y,ytest) residual_form_ya = dl.assemble(dl.derivative(residual_form_y, a,atrial)) residual_form_ay = dl.assemble(dl.derivative(residual_form_a, y,ytrial)) residual_form_aa = dl.assemble(dl.derivative(residual_form_a, a,atrial)) residual_form_yy = dl.assemble(dl.derivative(residual_form_y, y,ytrial))
# Nonlinear coefficient 1 q1 = ufl.operators.exp(a * u1) # Nonlinear coefficient 2 q2 = ufl.operators.exp(a * u2) for k in range(10): # Two parts of the weak form F1 = (u1.dx(0) * v1.dx(0) + a * u1.dx(0) * q2 * v1) * df.dx F2 = (u2.dx(0) * v2.dx(0) - a * q1 * u2.dx(0) * v2) * df.dx F = F1 + F2 # Compute Jacobian dF = df.derivative(F, u, du) # Assemble matrix and load vector A, b = df.assemble_system(dF, -F, bch) # Compute Newton update df.solve(A, u_inc.vector(), b) # Update solution u.vector()[:] += u_inc.vector() # Evaluate solution ug = u.compute_vertex_values() # partition into u1 and u2 U = np.reshape(ug, (2, nel + 1))
def solve(self, F, u, grad = None, H = None): if grad is None: print "Using Automatic Differentiation to compute the gradient" grad = derivative(F,u) if H is None: print "Using Automatic Differentiation to compute the Hessian" H = derivative(grad, u) rtol = self.parameters["rel_tolerance"] atol = self.parameters["abs_tolerance"] gdu_tol = self.parameters["gdu_tolerance"] max_iter = self.parameters["max_iter"] c_armijo = self.parameters["c_armijo"] max_backtrack = self.parameters["max_backtracking_iter"] prt_level = self.parameters["print_level"] cg_coarsest_tol = self.parameters["cg_coarse_tolerance"] Fn = assemble(F) gn = assemble(grad) g0_norm = gn.norm("l2") gn_norm = g0_norm tol = max(g0_norm*rtol, atol) du = Vector() self.converged = False self.reason = 0 if prt_level > 0: print "{0:3} {1:15} {2:15} {3:15} {4:15} {5:15} {6:5}".format( "It", "Energy", "||g||", "(g,du)", "alpha", "tol_cg", "cg_it") for self.it in range(max_iter): Hn = assemble(H) Hn.init_vector(du,1) solver = PETScKrylovSolver("cg", "petsc_amg") solver.set_operator(Hn) solver.parameters["nonzero_initial_guess"] = False cg_tol = min(cg_coarsest_tol, math.sqrt( gn_norm/g0_norm) ) solver.parameters["relative_tolerance"] = cg_tol lin_it = solver.solve(du,gn) self.total_cg_iter += lin_it du_gn = -du.inner(gn) if(-du_gn < gdu_tol): self.converged=True self.reason = 3 break u_backtrack = u.copy(deepcopy=True) alpha = 1. bk_converged = False #Backtrack for j in range(max_backtrack): u.assign(u_backtrack) u.vector().axpy(-alpha, du) Fnext = assemble(F) if Fnext < Fn + alpha*c_armijo*du_gn: Fn = Fnext bk_converged = True break alpha = alpha/2. if not bk_converged: self.reason = 2 break gn = assemble(grad) gn_norm = gn.norm("l2") if prt_level > 0: print "{0:3d} {1:15f} {2:15f} {3:15f} {4:15f} {5:15f} {6:5d}".format( self.it, Fn, gn_norm, du_gn, alpha, cg_tol, lin_it) if gn_norm < tol: self.converged = True self.reason = 1 break self.final_grad_norm = gn_norm if prt_level > -1: print self.termination_reasons[self.reason] if self.converged: print "Inexact Newton CG converged in ", self.it, \ "nonlinear iterations and ", self.total_cg_iter, "linear iterations." else: print "Inexact Newton CG did NOT converge after ", self.it, \ "nonlinear iterations and ", self.total_cg_iter, "linear iterations." print "Final norm of the gradient", self.final_grad_norm print "Value of the cost functional", Fn
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
a = (H_n - H_o) / dt * w b = D(H_n) * dfn.dot(dfn.grad(H_n), dfn.grad(w)) c = M * w F = (a + b - c) * dfn.dx # <codecell> # F = dfn.action(F, H_coef) # <markdowncell> # Compute the Jacobian matrix. # <codecell> J = dfn.derivative(F, H_n, dH) # <markdowncell> # Setup the boundaries to contain a constant value (we do not want any Von Neuman boundaries) # <codecell> def boundary(h, on_boundary): return on_boundary bc = dfn.DirichletBC(V, dfn.Constant(0.0), boundary) # bc = dfn.DirichletBC(V, M, boundary) # <markdowncell>
def step(self, dt, u1, p1, u, p0, u_bcs, p_bcs, f0=None, f1=None, verbose=True, tol=1.0e-10 ): # Some initial sanity checkups. assert dt > 0.0 # Define trial and test functions ui = Function(self.W) v = TestFunction(self.W) # Create functions # Define coefficients k = Constant(dt) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Compute tentative velocity step: # # F(u) = 0, # F(u) := rho (U0 + (u.\nabla)u) - mu \div(\nabla u) - f = 0. # with Message('Computing tentative velocity'): # TODO higher-order scheme for time integration # # For higher-order schemes, see # # A comparison of time-discretization/linearization approaches # for the incompressible Navier-Stokes equations; # Volker John, Gunar Matthies, Joachim Rang; # Comput. Methods Appl. Mech. Engrg. 195 (2006) 5995-6010; # <http://www.wias-berlin.de/people/john/ELECTRONIC_PAPERS/JMR06.CMAME.pdf>. # F1 = self.rho * inner((ui - u[0])/k, v) * dx if abs(self.theta) > DOLFIN_EPS: # Implicit terms. if f1 is None: raise RuntimeError('Implicit schemes need right-hand side ' 'at target step (f1).') F1 -= self.theta * _rhs_weak(ui, v, f1, self.rho, self.mu) if abs(1.0 - self.theta) > DOLFIN_EPS: # Explicit terms. if f0 is None: raise RuntimeError('Explicit schemes need right-hand side ' 'at current step (f0).') F1 -= (1.0 - self.theta) \ * _rhs_weak(u[0], v, f0, self.rho, self.mu) if p0: F1 += dot(grad(p0), v) * dx #if stabilization: # tau = stab.supg2(V.mesh(), # u_1, # mu/rho, # V.ufl_element().degree() # ) # R = rho*(ui - u_1)/k # if abs(theta) > DOLFIN_EPS: # R -= theta * _rhs_strong(ui, f1, rho, mu) # if abs(1.0-theta) > DOLFIN_EPS: # R -= (1.0-theta) * _rhs_strong(u_1, f0, rho, mu) # if p_1: # R += grad(p_1) # # TODO use u_1 or ui here? # F1 += tau * dot(R, grad(v)*u_1) * dx # Get linearization and solve nonlinear system. # If the scheme is fully explicit (theta=0.0), then the system is # actually linear and only one Newton iteration is performed. J = derivative(F1, ui) # What is a good initial guess for the Newton solve? # Three choices come to mind: # # (1) the previous solution u_1, # (2) the intermediate solution from the previous step ui_1, # (3) the solution of the semilinear system # (u.\nabla(u) -> u_1.\nabla(u)). # # Numerical experiments with the Karman vortex street show that the # order of accuracy is (1), (3), (2). Typical norms would look like # # ||u - u_1 || = 1.726432e-02 # ||u - ui_1|| = 2.720805e+00 # ||u - u_e || = 5.921522e-02 # # Hence, use u_1 as initial guess. ui.assign(u[0]) # Wrap the solution in a try-catch block to make sure we call end() # if necessary. #problem = NonlinearVariationalProblem(F1, ui, u_bcs, J) #solver = NonlinearVariationalSolver(problem) solve( F1 == 0, ui, bcs=u_bcs, J=J, solver_parameters={ #'nonlinear_solver': 'snes', 'nonlinear_solver': 'newton', 'newton_solver': { 'maximum_iterations': 5, 'report': True, 'absolute_tolerance': tol, 'relative_tolerance': 0.0, 'linear_solver': 'iterative', ## The nonlinear term makes the problem generally ## nonsymmetric. #'symmetric': False, # If the nonsymmetry is too strong, e.g., if u_1 is # large, then AMG preconditioning might not work very # well. 'preconditioner': 'ilu', #'preconditioner': 'hypre_amg', 'krylov_solver': {'relative_tolerance': tol, 'absolute_tolerance': 0.0, 'maximum_iterations': 1000, 'monitor_convergence': verbose} }}) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - with Message('Computing pressure correction'): # # The following is based on the update formula # # rho/dt (u_{n+1}-u*) + \nabla phi = 0 # # with # # phi = (p_{n+1} - p*) + chi*mu*div(u*) # # and div(u_{n+1})=0. One derives # # - \nabla^2 phi = rho/dt div(u_{n+1} - u*), # - n.\nabla phi = rho/dt n.(u_{n+1} - u*), # # In its weak form, this is # # \int \grad(phi).\grad(q) # = - rho/dt \int div(u*) q - rho/dt \int_Gamma n.(u_{n+1}-u*) q. # # If Dirichlet boundary conditions are applied to both u* and # u_{n+1} (the latter in the final step), the boundary integral # vanishes. # # Assume that on the boundary # L2 -= inner(n, rho/k (u_bcs - ui)) * q * ds # is zero. This requires the boundary conditions to be set for # ui as well as u_final. # This creates some problems if the boundary conditions are # supposed to remain 'free' for the velocity, i.e., no Dirichlet # conditions in normal direction. In that case, one needs to # specify Dirichlet pressure conditions. # rotational_form = False self._pressure_poisson(p1, p0, self.mu, ui, divu=Constant(self.rho/dt)*div(ui), p_bcs=p_bcs, rotational_form=rotational_form, tol=tol, verbose=verbose ) #plot(p - phi, title='p-phi') #plot(ui, title='u intermediate') #plot(f, title='f') ##plot(ui[1], title='u intermediate[1]') #plot(div(ui), title='div(u intermediate)') #plot(phi, title='phi') #interactive() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Velocity correction. # U = U0 - dt/rho \nabla p. with Message('Computing velocity correction'): u2 = TrialFunction(self.W) a3 = inner(u2, v) * dx if p0: phi = Function(self.P) phi.assign(p1) phi -= p0 else: phi = p1 if rotational_form: phi += self.mu * div(ui) L3 = inner(ui, v) * dx \ - k/self.rho * inner(grad(phi), v) * dx solve(a3 == L3, u1, bcs=u_bcs, solver_parameters={ 'linear_solver': 'iterative', 'symmetric': True, 'preconditioner': 'jacobi', 'krylov_solver': {'relative_tolerance': tol, 'absolute_tolerance': 0.0, 'maximum_iterations': 100, 'monitor_convergence': verbose} }) #u = project(ui - k/rho * grad(phi), V) #print '||u||_div = %e' % norm(u, 'Hdiv0') #uu = TrialFunction(Q) #vv = TestFunction(Q) #div_u = Function(Q) #solve(uu*vv*dx == div(u)*vv*dx, div_u, # #bcs=DirichletBC(Q, 0.0, 'on_boundary') # ) #plot(div_u, title='div(u)') #interactive() return
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