def solve_thermal(self): """ Solve the thermal diffusion problem. Both ice and solution. """ ### Solve heat equation alphalog_i = dolfin.project(dolfin.Expression('astar*exp(-2.*x[0])',degree=1,astar=self.astar_i),self.ice_V) # Set up the variational form for the current mesh location F_i = (self.u_i-self.u0_i)*self.v_i*dolfin.dx + self.dt*dolfin.inner(dolfin.grad(self.u_i), dolfin.grad(alphalog_i*self.v_i))*dolfin.dx a_i = dolfin.lhs(F_i) L_i = dolfin.rhs(F_i) # Solve ice temperature dolfin.solve(a_i==L_i,self.T_i,[self.bc_inf,self.bc_iWall]) # Update previous profile to current self.u0_i.assign(self.T_i) diff_ratio = (self.ks*const.rhoi*const.ci)/(const.ki*self.rhos*self.cs) alphalog_s = dolfin.project(dolfin.Expression('astar*exp(-2.*x[0])',degree=1,astar=self.astar_i),self.sol_V) # Set up the variational form for the current mesh location F_s = (self.u_s-self.u0_s)*self.v_s*dolfin.dx + self.dt*dolfin.inner(dolfin.grad(self.u_s), dolfin.grad(alphalog_s*diff_ratio*self.v_s))*dolfin.dx #- self.dt*(self.Q_sol*self.t0/abs(self.T_inf)/(const.rhoi*const.ci))*self.v_s*dolfin.dx #TODO: check this solution source term # TODO: Center heat flux #F_s -= (self.Q_center/(self.ks*diff_ratio*2.*np.pi*abs(self.T_inf)))*self.v_s*self.sds(2) a_s = dolfin.lhs(F_s) L_s = dolfin.rhs(F_s) # Solve solution temperature dolfin.solve(a_s==L_s,self.T_s,self.bc_sWall) # Update previous profile to current self.u0_s.assign(self.T_s)
def __init__(self, t_end=None, func=None): Problem_verification.__init__(self, t_end, func) self.u0_expr = dol.Constant(1) self.V = dol.FunctionSpace(dol.UnitIntervalMesh(1), 'DG', 0) # rhs self.f1 = dol.Expression('pow(t, 2)', t=0, degree=2) self.f2 = dol.Expression('pow(t, 2)', t=0, degree=2) Problem_FE.__init__(self) # CN, higher order F = (dol.inner( self.v, self.utrial - self.uold + self.dt * 0.5 * (self.uold + self.utrial)) * dol.dx - 0.5 * self.dt * dol.inner(self.f1 + self.f2, self.v) * dol.dx) prob = dol.LinearVariationalProblem(dol.lhs(F), dol.rhs(F), self.unew) self.solver = dol.LinearVariationalSolver(prob) # IE, lower order Flow = (dol.inner( self.v, self.utrial - self.uold + self.dt * self.utrial) * dol.dx - self.dt * dol.inner(self.f2, self.v) * dol.dx) problow = dol.LinearVariationalProblem(dol.lhs(Flow), dol.rhs(Flow), self.ulow) self.solver_low = dol.LinearVariationalSolver(problow)
def solve_initial_pressure(w_NSp, p, q, u, v, bcs_NSp, M_, g_, phi_, rho_, rho_e_, V_, drho, sigma_bar, eps, grav, dveps, enable_PF, enable_EC): V = u.function_space() grad_p = df.TrialFunction(V) grad_p_out = df.Function(V) F_grad_p = (df.dot(grad_p, v) * df.dx - rho_ * df.dot(grav, v) * df.dx) if enable_PF: F_grad_p += -drho * M_ * df.inner(df.grad(u), df.outer(df.grad(g_), v)) * df.dx F_grad_p += -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_grad_p += rho_e_ * df.dot(df.grad(V_), v) * df.dx if enable_PF and enable_EC: F_grad_p += dveps * df.dot(df.grad(phi_), v) * df.dot( df.grad(V_), df.grad(V_)) * df.dx info_red("Solving initial grad_p...") df.solve(df.lhs(F_grad_p) == df.rhs(F_grad_p), grad_p_out) F_p = (df.dot(df.grad(q), df.grad(p)) * df.dx - df.dot(df.grad(q), grad_p_out) * df.dx) info_red("Solving initial p...") df.solve(df.lhs(F_p) == df.rhs(F_p), w_NSp, bcs_NSp)
def setup_NSu(w_NSu, u, v, dx, ds, normal, dirichlet_bcs_NSu, neumann_bcs, boundary_to_mark, u_, p_, u_1, p_1, rho_, rho_1, mu_, c_1, grad_g_c_, dt, grav, enable_EC, trial_functions, use_iterative_solvers, mesh, density_per_concentration, viscosity_per_concentration, K, **namespace): """ Set up the Navier-Stokes velocity subproblem. """ solvers = dict() mom_1 = rho_1 * u_1 if enable_EC and density_per_concentration is not None: for drhodci, ci_1, grad_g_ci_, Ki in zip(density_per_concentration, c_1, grad_g_c_, K): if drhodci > 0.: mom_1 += -drhodci * Ki * ci_1 * grad_g_ci_ F_predict = ( 1. / dt * rho_1 * df.dot(u - u_1, v) * dx + df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx + 2 * mu_ * df.inner(df.sym(df.nabla_grad(u)), df.sym(df.nabla_grad(v))) * dx + 0.5 * (1. / dt * (rho_ - rho_1) * df.dot(u, v) - df.inner(mom_1, df.grad(df.dot(u, v)))) * dx - p_1 * df.div(v) * dx - rho_ * df.dot(grav, v) * dx) for boundary_name, pressure in neumann_bcs["p"].iteritems(): F_predict += pressure * df.inner(normal, v) * ds( boundary_to_mark[boundary_name]) if enable_EC: F_predict += sum([ ci_1 * df.dot(grad_g_ci_, v) * dx for ci_1, grad_g_ci_ in zip(c_1, grad_g_c_) ]) a_predict, L_predict = df.lhs(F_predict), df.rhs(F_predict) # if not use_iterative_solvers: problem_predict = df.LinearVariationalProblem(a_predict, L_predict, w_NSu, dirichlet_bcs_NSu) solvers["predict"] = df.LinearVariationalSolver(problem_predict) if use_iterative_solvers: solvers["predict"].parameters["linear_solver"] = "bicgstab" solvers["predict"].parameters["preconditioner"] = "amg" F_correct = (rho_ * df.inner(u - u_, v) * dx - dt * (p_ - p_1) * df.div(v) * dx) a_correct, L_correct = df.lhs(F_correct), df.rhs(F_correct) problem_correct = df.LinearVariationalProblem(a_correct, L_correct, w_NSu, dirichlet_bcs_NSu) solvers["correct"] = df.LinearVariationalSolver(problem_correct) if use_iterative_solvers: solvers["correct"].parameters["linear_solver"] = "bicgstab" solvers["correct"].parameters["preconditioner"] = "amg" #else: # solver = df.LUSolver("mumps") # # solver.set_operator(A) # return solver, a, L, dirichlet_bcs_NS return solvers
def __init__(self, t_end = None, func = None, para_stiff = None, adjoint = False): Problem_Basic.__init__(self, t_end = t_end, func = func, para_stiff = para_stiff) self.k = dol.Constant(self.k) self.u0_expr = dol.Constant(self.u0) # initial value mesh = dol.UnitIntervalMesh(1) R_elem = dol.FiniteElement("R", mesh.ufl_cell(), 0) V_elem = dol.MixedElement([R_elem, R_elem]) self.V = dol.FunctionSpace(mesh, V_elem) if adjoint: self.z0_expr = dol.Constant(np.array([0., 0.])) # initial value adj Problem_FE.__init__(self, adjoint) (self.v1 , self.v2) = dol.split(self.v) (self.u1trial, self.u2trial) = dol.split(self.utrial) (self.u1old , self.u2old) = dol.split(self.uold) (self.u1low , self.u2low) = dol.split(self.ulow) ## Crank nicolson weak formulation F = (dol.inner(self.v1, self.u1trial - self.u1old + self.dt * (0.5 * (self.u1old + self.u1trial) - 0.5 * (self.u2old + self.u2trial)))*dol.dx + dol.inner(self.v2, self.u2trial - self.u2old - self.k * self.dt * 0.5 * (self.u2old + self.u2trial))*dol.dx) prob = dol.LinearVariationalProblem(dol.lhs(F), dol.rhs(F), self.unew) self.solver = dol.LinearVariationalSolver(prob) ## Implicit Euler weak formulation for error estimation Flow = (dol.inner(self.v1, self.u1trial - self.u1old + self.dt * (self.u1trial - self.u2trial))*dol.dx + dol.inner(self.v2, self.u2trial - self.u2old - self.k * self.dt * self.u2trial)*dol.dx) problow = dol.LinearVariationalProblem(dol.lhs(Flow), dol.rhs(Flow), self.ulow) self.solver_low = dol.LinearVariationalSolver(problow) if adjoint: (self.z1old , self.z2old) = dol.split(self.zold) (self.z1trial, self.z2trial) = dol.split(self.ztrial) if self.func not in [1, 2]: raise ValueError('DWR not (yet) implemented for this functional') adj_src = dol.Function(self.V) if self.func == 1: adj_src.interpolate(dol.Constant((1, 0))) elif self.func == 2: adj_src.interpolate(dol.Constant((0, 1))) src1, src2 = dol.split(adj_src) Fadj = (dol.inner(self.z1trial - self.z1old + 0.5 * self.dt * (-self.z1trial - self.z1old + 2*src1), self.v1)*dol.dx + dol.inner(self.z2trial - self.z2old + 0.5 * self.dt * ( self.z1trial + self.z1old + self.k*(self.z2trial + self.z2old) + 2*src2), self.v2)*dol.dx) prob_adj = dol.LinearVariationalProblem(dol.lhs(Fadj), dol.rhs(Fadj), self.znew) self.solver_adj = dol.LinearVariationalSolver(prob_adj)
def solveFwd(self, state, x): """ Solve the possibly nonlinear forward problem: Given :math:`m`, find :math:`u` such that .. math:: \\delta_p F(u, m, p;\\hat{p}) = 0,\\quad \\forall \\hat{p}.""" if self.solver is None: self.solver = self._createLUSolver() if self.is_fwd_linear: u = dl.TrialFunction(self.Vh[STATE]) m = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) p = dl.TestFunction(self.Vh[ADJOINT]) res_form = self.varf_handler(u, m, p) A_form = dl.lhs(res_form) b_form = dl.rhs(res_form) A, b = dl.assemble_system(A_form, b_form, bcs=self.bc) self.solver.set_operator(A) self.solver.solve(state, b) else: u = vector2Function(x[STATE], self.Vh[STATE]) m = vector2Function(x[PARAMETER], self.Vh[PARAMETER]) p = dl.TestFunction(self.Vh[ADJOINT]) res_form = self.varf_handler(u, m, p) dl.solve(res_form == 0, u, self.bc) state.zero() state.axpy(1., u.vector())
def stokes(self): P2 = VectorElement("CG", self.mesh.ufl_cell(), 2) P1 = FiniteElement("CG", self.mesh.ufl_cell(), 1) TH = P2 * P1 VQ = FunctionSpace(self.mesh, TH) mf = self.mf self.no_slip = Constant((0., 0)) self.topflow = Expression(("-x[0] * (x[0] - 1.0) * 6.0 * m", "0.0"), m=self.U_m, degree=2) bc0 = DirichletBC(VQ.sub(0), self.topflow, mf, self.bc_dict["top"]) bc1 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["left"]) bc2 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["bottom"]) bc3 = DirichletBC(VQ.sub(0), self.no_slip, mf, self.bc_dict["right"]) # bc4 = DirichletBC(VQ.sub(1), Constant(0), mf, self.bc_dict["top"]) bcs = [bc0, bc1, bc2, bc3] vup = TestFunction(VQ) up = TrialFunction(VQ) # the solution will be in here: up_ = Function(VQ) u, p = split(up) # Trial vu, vp = split(vup) # Test u_, p_ = split(up_) # Function holding the solution F = self.mu*inner(grad(vu), grad(u))*dx - inner(div(vu), p)*dx \ - inner(vp, div(u))*dx + dot(self.g*self.rho, vu)*dx solve(lhs(F) == rhs(F), up_, bcs=bcs) self.u_.assign(project(u_, self.V)) self.p_.assign(project(p_, self.Q)) return
def EvaluateImpl(self, inputs): """ """ m = dl.Function(self.V) m.vector().set_local(inputs[0]) p_n = dl.interpolate(m, self.V) p_nm1 = dl.interpolate(m, self.V) p_trial = self.p_trial v = self.v F = (self.c**2) * (self.dt**2) * dl.inner( dl.grad(p_trial), dl.grad(v) ) * dl.dx - 2. * p_n * v * dl.dx + p_trial * v * dl.dx + p_nm1 * v * dl.dx a, L = dl.lhs(F), dl.rhs(F) # Time-stepping p = dl.Function(self.V) t = 0 for n in range(self.numSteps): # Update current timtime t += self.dt # Compute solution dl.solve(a == L, p) # Update previous solution p_nm1.assign(p_n) p_n.assign(p) out = p.vector().array()[:] self.outputs = [out]
def stokes(self): P2 = df.VectorElement("CG", self.mesh.ufl_cell(), 2) P1 = df.FiniteElement("CG", self.mesh.ufl_cell(), 1) TH = P2 * P1 VQ = df.FunctionSpace(self.mesh, TH) mf = self.mf self.no_slip = df.Constant((0., 0)) U0_str = "4.*U_m*x[1]*(.41-x[1])/(.41*.41)" U0 = df.Expression((U0_str, "0"), U_m=self.U_m, degree=2) bc0 = df.DirichletBC(VQ.sub(0), df.Constant((0, 0)), mf, self.bc_dict["obstacle"]) bc1 = df.DirichletBC(VQ.sub(0), df.Constant((0, 0)), mf, self.bc_dict["channel_walls"]) bc2 = df.DirichletBC(VQ.sub(0), U0, mf, self.bc_dict["inlet"]) bc3 = df.DirichletBC(VQ.sub(1), df.Constant(0), mf, self.bc_dict["outlet"]) bcs = [bc0, bc1, bc2, bc3] vup = df.TestFunction(VQ) up = df.TrialFunction(VQ) up_ = df.Function(VQ) u, p = df.split(up) # Trial vu, vp = df.split(vup) # Test u_, p_ = df.split(up_) # Function holding the solution inner, grad, dx, div = df.inner, df.grad, df.dx, df.div F = self.mu*inner(grad(vu), grad(u))*dx - inner(div(vu), p)*dx \ - inner(vp, div(u))*dx df.solve(df.lhs(F) == df.rhs(F), up_, bcs=bcs) self.u_.assign(df.project(u_, self.V)) self.p_.assign(df.project(p_, self.Q)) return
def setup_EC(w_EC, c, V, b, U, rho_e, dx, ds, dirichlet_bcs, neumann_bcs, boundary_to_mark, c_1, u_1, K_, veps_, phi_, per_tau, z, dbeta, enable_NS, enable_PF, use_iterative_solvers): """ Set up electrochemistry subproblem. """ 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 += -V*U*dx F = F_V a, L = df.lhs(F), df.rhs(F) problem = df.LinearVariationalProblem(a, L, w_EC, dirichlet_bcs) solver = df.LinearVariationalSolver(problem) for ci, ci_1, bi, Ki_, zi, dbetai in zip(c, c_1, b, K_, z, dbeta): ??
def solve_petsc(self): """ Solves the linear problem using PETSc interface, and manipulates with PETSc matrices. :return: list[state vectors] """ form = self.forms._rhs_forms( shift=self.frequency) + self.forms._lhs_forms() w = dolf.Function(self.forms.function_space) lhs_matrix = dolf.PETScMatrix() lhs_matrix = dolf.assemble(dolf.lhs(form), tensor=lhs_matrix) for bc in self.forms.dirichlet_boundary_conditions(): bc.apply(lhs_matrix) lhs_matrix = lhs_matrix.mat() averaged_boundary_terms = self.forms.boundary_averaged_velocity() if averaged_boundary_terms: lhs_matrix.axpy(-1.0, averaged_boundary_terms) solver = self.create_ksp_solver(lhs_matrix) rhs_vector = dolf.assemble(dolf.rhs(form)) for bc in self.forms.dirichlet_boundary_conditions(): bc.apply(rhs_vector) solver.solve( dolf.as_backend_type(rhs_vector).vec(), dolf.as_backend_type(w.vector()).vec(), ) state = w.split(True) return state
def test_lhs_rhs_simple(): """Test taking lhs/rhs of DOLFIN specific forms (constants without cell). """ mesh = RectangleMesh.create(MPI.comm_world, [Point(0, 0), Point(2, 1)], [3, 5], CellType.Type.triangle) V = FunctionSpace(mesh, "CG", 1) f = 2.0 g = 3.0 v = TestFunction(V) u = TrialFunction(V) F = inner(g * grad(f * v), grad(u)) * dx + f * v * dx a, L = system(F) Fl = lhs(F) Fr = rhs(F) assert (Fr) a0 = inner(grad(v), grad(u)) * dx n = assemble(a).norm("frobenius") # noqa nl = assemble(Fl).norm("frobenius") # noqa n0 = 6.0 * assemble(a0).norm("frobenius") # noqa assert round(n - n0, 7) == 0 assert round(n - nl, 7) == 0
def __init__(self, domain): rho, mu, dt, g = domain.rho, domain.mu, domain.dt, domain.g u, u_1, vu = domain.u, domain.u_1, domain.vu p_1 = domain.p_1 n = FacetNormal(domain.mesh) acceleration = rho * inner((u - u_1) / dt, vu) * dx pressure = inner(p_1, div(vu)) * dx - dot(p_1 * n, vu) * ds body_force = dot(g*rho, vu)*dx \ + dot(Constant((0.0, 0.0)), vu) * ds # diffusion = (-inner(mu * (grad(u_1) + grad(u_1).T), grad(vu))*dx # + dot(mu * (grad(u_1) + grad(u_1).T)*n, vu)*ds) # just fine # diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx) # just fine # just fine, but horribly slow in combination with ??? -> not reproducable diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu)) * dx + dot(mu * (grad(u) + grad(u).T) * n, vu) * ds) # convection = rho*dot(dot(u, nabla_grad(u_1)), vu) * dx # no vortices convection = rho * dot(dot(u_1, nabla_grad(u)), vu) * dx # stabilization = -gamma*psi_p*p_1 # convection = dot(div(rho * outer(u_1, u_1)), vu) * dx # not stable! # convection = rho * dot(dot(u_1, nabla_grad(u_1)), vu) * dx # just fine F_impl = -acceleration - convection + diffusion + pressure + body_force self.a, self.L = lhs(F_impl), rhs(F_impl) self.domain = domain self.A = assemble(self.a) [bc.apply(self.A) for bc in domain.bcu] return
def __init__(self, parameters, domain): rho = Constant(parameters["density [kg/m3]"]) mu = Constant(parameters["viscosity [Pa*s]"]) dt = Constant(parameters["dt [s]"]) u, u_1, u_k, vu = domain.u, domain.u_1, domain.u_k, domain.vu p_1 = domain.p_1 n = FacetNormal(domain.mesh) acceleration = rho*inner((u-u_1)/dt, vu) * dx convection = dot(div(rho*outer(u_k, u)), vu) * dx convection = rho*dot(dot(u_k, nabla_grad(u)), vu) * dx pressure = (inner(p_1, div(vu))*dx - dot(p_1*n, vu)*ds) diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx) # good # diffusion = (-inner(mu * (grad(u) + grad(u).T), grad(vu))*dx # + dot(mu * (grad(u) + grad(u).T)*n, vu)*ds) # very slow! # F_impl = acceleration + convection + pressure + diffusion # dot(u_1, nabla_grad(u_1)) works # dot(u, nabla_grad(u_1)) does not change! u_mid = (u + u_1) / 2.0 F_impl = rho*dot((u - u_1) / dt, vu)*dx \ + rho*dot(dot(u_1, nabla_grad(u_1)), vu)*dx \ + inner(sigma(u_mid, p_1, mu), epsilon(vu))*dx \ + dot(p_1*n, vu)*ds - dot(mu*nabla_grad(u_mid)*n, vu)*ds self.a, self.L = lhs(F_impl), rhs(F_impl) self.domain = domain self.A = assemble(self.a) [bc.apply(self.A) for bc in domain.bcu] return
def setup_NS(w_NS, u, p, v, q, p0, q0, dx, ds, normal, dirichlet_bcs_NS, neumann_bcs, boundary_to_mark, u_1, rho_, rho_1, mu_, c_1, grad_g_c_, dt, grav, enable_EC, trial_functions, use_iterative_solvers, p_lagrange, mesh, q_rhs, density_per_concentration, K, **namespace): """ Set up the Navier-Stokes subproblem. """ mom_1 = rho_1 * u_1 if enable_EC and density_per_concentration is not None: for drhodci, ci_1, grad_g_ci_, Ki in zip( density_per_concentration, c_1, grad_g_c_, K): if drhodci > 0.: mom_1 += -drhodci*Ki*ci_1*grad_g_ci_ F = (1./dt * rho_1 * df.dot(u - u_1, v) * dx + df.inner(df.nabla_grad(u), df.outer(mom_1, v)) * dx + 2*mu_*df.inner(df.sym(df.nabla_grad(u)), df.sym(df.nabla_grad(v))) * dx + 0.5*( 1./dt * (rho_ - rho_1) * df.inner(u, v) - df.inner(mom_1, df.nabla_grad(df.dot(u, v)))) * dx - p * df.div(v) * dx - q * df.div(u) * dx - rho_ * df.dot(grav, v) * dx) for boundary_name, pressure in neumann_bcs["p"].iteritems(): F += pressure * df.inner( normal, v) * ds(boundary_to_mark[boundary_name]) if enable_EC: F += sum([ci_1*df.dot(grad_g_ci_, v)*dx for ci_1, grad_g_ci_ in zip(c_1, grad_g_c_)]) if p_lagrange: F += (p*q0 + q*p0)*dx if "u" in q_rhs: F += -df.dot(q_rhs["u"], v)*dx a, L = df.lhs(F), df.rhs(F) if not use_iterative_solvers: problem = df.LinearVariationalProblem(a, L, w_NS, dirichlet_bcs_NS) solver = df.LinearVariationalSolver(problem) else: solver = df.LUSolver("mumps") # solver.set_operator(A) return solver, a, L, dirichlet_bcs_NS return solver
def solve(self): super(backwardEuler, self).solve() # Array for storing the stage values X = [self.u.copy(deepcopy=True)] # Get the variational linear/nonlinear variational forms # and embed them in respective solver class if self.linear: l = self.getLinearVariationalForms(X) p = [linearStage(d.lhs(l[0]), d.rhs(l[0]), self.bcs, self.solver)] else: l = self.getNonlinearVariationalForms(X) a = [d.derivative(l[0], X[0], self.U)] p = [nonlinearStage(a[0], l[0], self.bcs)] # Initialize save/plot of function(s) self.figureHandling(Init=True) # Time stepping loop while True: timestepStart = time.time() # Update time dependent functions for i in range(len(self.tdfButcher)): for j in range(0, 1): self.tdfButcher[i][j].t = self.t + self.dt # Update time dependent functions on boundary for F in self.tdfBC: F.t = self.t + self.dt # Solve for implicit stages if self.linear: p[0].solve(X[0].vector()) else: self.solver.solve(p[0], X[0].vector()) # Constant step size integration self.u.vector()[:] = X[0].vector()[:] self.t += self.dt self.nAcc += 1 if self.parameters['verbose']: self.printProgress(self.estimateRuntime) # Update / save plots self.figureHandling(Update=True) # Break if this is final time step if self.breakTimeLoop: terminateReason = "Success" break self.timestepTimer = time.time() - timestepStart self.verifyStepsize() super(backwardEuler, self).terminateTimeLoop(terminateReason)
def create_rhs(self): self.L = self.create_bc() if self.moment_order == 3: self.L += self.source_term() if self.stab_type == 'gls': self.L += df.rhs(self.apply_stabilization()) if self.problem_type == 'nonlinear': self.L += self.add_nonlinearity() self.F = self.a - self.L
def get_system(self, t): kappa.t = t f.t = t n = FacetNormal(self.V.mesh()) u = TrialFunction(self.V) v = TestFunction(self.V) F = inner(kappa * grad(u), grad(v / self.rho_cp)) * dx \ - inner(kappa * grad(u), n) * v / self.rho_cp * ds \ - f * v / self.rho_cp * dx return assemble(lhs(F)), assemble(rhs(F))
def __init__(self, t_end=None, func=None): Problem_verification.__init__(self, t_end, func) self.u0_expr = dol.Constant(1) self.V = dol.FunctionSpace(dol.UnitIntervalMesh(1), 'DG', 0) Problem_FE.__init__(self) # CN, higher order F = dol.inner( self.v, self.utrial - self.uold + self.dt * 0.5 * (self.uold + self.utrial)) * dol.dx prob = dol.LinearVariationalProblem(dol.lhs(F), dol.rhs(F), self.unew) self.solver = dol.LinearVariationalSolver(prob) # IE, lower order Flow = dol.inner( self.v, self.utrial - self.uold + self.dt * self.utrial) * dol.dx problow = dol.LinearVariationalProblem(dol.lhs(Flow), dol.rhs(Flow), self.ulow) self.solver_low = dol.LinearVariationalSolver(problow)
def navier_stokes_IPCS(mesh, dt, parameter): """ fenics code: weak form of the problem. """ mu, rho, nu = parameter V = VectorFunctionSpace(mesh, 'P', 2) Q = FunctionSpace(mesh, 'P', 1) bc0 = DirichletBC(V, Constant((0, 0)), cylinderwall) bc1 = DirichletBC(V, Constant((0, 0)), topandbottom) bc2 = DirichletBC(V, U0, inlet) bc3 = DirichletBC(Q, Constant(1), outlet) bcs = [bc0, bc1, bc2, bc3] # ds is needed to compute drag and lift. Not used here. ASD1 = AutoSubDomain(topandbottom) ASD2 = AutoSubDomain(cylinderwall) mf = MeshFunction("size_t", mesh, 1) mf.set_all(0) ASD1.mark(mf, 1) ASD2.mark(mf, 2) ds_ = ds(subdomain_data=mf, domain=mesh) vu, vp = TestFunction(V), TestFunction(Q) # for integration u_, p_ = Function(V), Function(Q) # for the solution u_1, p_1 = Function(V), Function(Q) # for the prev. solution u, p = TrialFunction(V), TrialFunction(Q) # unknown! bcu = [bcs[0], bcs[1], bcs[2]] bcp = [bcs[3]] n = FacetNormal(mesh) u_mid = (u + u_1) / 2.0 F1 = rho*dot((u - u_1) / dt, vu)*dx \ + rho*dot(dot(u_1, nabla_grad(u_1)), vu)*dx \ + inner(sigma(u_mid, p_1, mu), epsilon(vu))*dx \ + dot(p_1*n, vu)*ds - dot(mu*nabla_grad(u_mid)*n, vu)*ds a1 = lhs(F1) L1 = rhs(F1) # Define variational problem for step 2 a2 = dot(nabla_grad(p), nabla_grad(vp)) * dx L2 = dot(nabla_grad(p_1), nabla_grad(vp)) * dx - ( rho / dt) * div(u_) * vp * dx # rho missing in FEniCS tutorial # Define variational problem for step 3 a3 = dot(u, vu) * dx L3 = dot(u_, vu) * dx - dt * dot(nabla_grad(p_ - p_1), vu) * dx # Assemble matrices A1 = assemble(a1) A2 = assemble(a2) A3 = assemble(a3) # Apply boundary conditions to matrices [bc.apply(A1) for bc in bcu] [bc.apply(A2) for bc in bcp] return u_, p_, u_1, p_1, L1, A1, L2, A2, L3, A3, bcu, bcp
def solve(self): form = self.forms._rhs_forms( shift=self.frequency) + self.forms._lhs_forms() w = dolf.Function(self.forms.function_space) dolf.solve( dolf.lhs(form) == dolf.rhs(form), w, self.forms.dirichlet_boundary_conditions(), solver_parameters={"linear_solver": "mumps"}, ) state = w.split(True) return state
def soln_fwd(self): """ Solve the forward equation. F = 0 """ # 5. Solve (non)linear variational problem # df.solve(self.F==0,self.states_fwd,self.ess_bc,J=self.dFdstates) # self.states_fwd = df.Function(self.W) df.solve(df.lhs(self.F)==df.rhs(self.F),self.states_fwd,self.ess_bc) # df.solve(self.a==self.L,self.states_fwd,self.ess_bc) self.soln_count[0] += 1 u_fwd, l_fwd = df.split(self.states_fwd) return u_fwd, l_fwd
def rhs(form): """ Wrapper for the DOLFIN rhs function. Correctly handles QForm s. """ if not isinstance(form, ufl.form.Form): raise InvalidArgumentException("form must be a Form") nform = dolfin.rhs(form) if isinstance(form, QForm): return QForm(nform, quadrature_degree = form_quadrature_degree(form)) else: return nform
def matrix_optimisation(form): """ Attempt to convert a linear form into the action of a bi-linear form. Return a (bi-linear Form, Function) pair on success, and None on failure. """ if not isinstance(form, ufl.form.Form): raise InvalidArgumentException("form must be a Form") # Find the test function args = ufl.algorithms.extract_arguments(form) if not len(args) == 1: # This is not a linear form return None # Look for a single non-static Function dependency tcs = extract_non_static_coefficients(form) if not len(tcs) == 1: # Found too many non-static coefficients return None elif not isinstance(tcs[0], dolfin.Function): # The only non-static coefficient is not a Function return None # Found a single non-static Function dependency fn = tcs[0] # Look for a static bi-linear form whose action can be used to construct # the linear form mat_form = derivative( form, fn, # Hack to work around an obscure FEniCS bug expand=dolfin.MPI.size(dolfin.mpi_comm_world()) == 1 or (not is_r0_function_space(args[0].function_space()) and not is_r0_function(fn))) if n_non_static_coefficients(mat_form) > 0: # The form is non-linear return None try: rhs_form = dolfin.rhs( dolfin.replace(form, {fn: dolfin.TrialFunction(fn.function_space())})) except ufl.log.UFLException: # The form might be inhomogeneous return None if not is_empty_form(rhs_form): # The form might be inhomogeneous return None # Success return mat_form, fn
def __init__(self, domain): rho, mu, dt = domain.rho, domain.mu, domain.dt u, u_1, p_1, vu = domain.u, domain.u_1, domain.p_1, domain.vu n = FacetNormal(domain.mesh) acceleration = rho * inner((u - u_1) / dt, vu) * dx diffusion = (-inner(mu * (grad(u_1) + grad(u_1).T), grad(vu)) * dx + dot(mu * (grad(u_1) + grad(u_1).T) * n, vu) * ds) pressure = inner(p_1, div(vu)) * dx - dot(p_1 * n, vu) * ds convection = rho * dot(dot(u_1, nabla_grad(u_1)), vu) * dx F_impl = -acceleration - convection + diffusion + pressure self.a, self.L = lhs(F_impl), rhs(F_impl) self.domain = domain self.A = assemble(self.a) [bc.apply(self.A) for bc in domain.bcu] return
def setup_NSp(w_NSp, p, q, dirichlet_bcs_NSp, dt, u_, p_1, rho_0, use_iterative_solvers, **namespace): """ Set up Navier-Stokes pressure subproblem. """ F = (df.dot(df.nabla_grad(p - p_1), df.nabla_grad(q)) * df.dx + 1. / dt * rho_0 * df.div(u_) * q * df.dx) a, L = df.lhs(F), df.rhs(F) problem = df.LinearVariationalProblem(a, L, w_NSp, dirichlet_bcs_NSp) solver = df.LinearVariationalSolver(problem) if use_iterative_solvers: solver.parameters["linear_solver"] = "bicgstab" solver.parameters["preconditioner"] = "amg" return solver
def setup_NSp(w_NSp, p, q, dx, ds, dirichlet_bcs_NSp, neumann_bcs, boundary_to_mark, u_, u_1, p_, p_1, rho_, dt, rho_min, use_iterative_solvers, **namespace): F = (df.dot(df.nabla_grad(p - p_1), df.nabla_grad(q)) * df.dx + 1. / dt * rho_min * df.div(u_) * q * df.dx) a, L = df.lhs(F), df.rhs(F) problem = df.LinearVariationalProblem(a, L, w_NSp, dirichlet_bcs_NSp) solver = df.LinearVariationalSolver(problem) if use_iterative_solvers: solver.parameters["linear_solver"] = "gmres" solver.parameters["preconditioner"] = "hypre_amg" # "amg" # solver.parameters["preconditioner"] = "hypre_euclid" return solver
def setup_EC(w_EC, c, V, b, U, rho_e, dx, ds, dirichlet_bcs, neumann_bcs, boundary_to_mark, c_1, u_1, K_, veps_, phi_, solutes, per_tau, z, dbeta, enable_NS, enable_PF, use_iterative_solvers, q_rhs): """ Set up electrochemistry subproblem. """ F_c = [] for ci, ci_1, bi, Ki_, zi, dbetai, solute in zip(c, c_1, b, K_, z, dbeta, solutes): F_ci = (per_tau*(ci-ci_1)*bi*dx + Ki_*df.dot(df.nabla_grad(ci), df.nabla_grad(bi))*dx) if zi != 0: F_ci += Ki_*zi*ci_1*df.dot(df.nabla_grad(V), df.nabla_grad(bi))*dx if enable_PF: F_ci += Ki_*ci*dbetai*df.dot(df.nabla_grad(phi_), df.nabla_grad(bi))*dx if enable_NS: # F_ci += df.div(ci*u_1)*bi*dx F_ci += - ci*df.dot(u_1, df.grad(bi))*dx if solute[0] in q_rhs: F_ci += - q_rhs[solute[0]]*bi*dx F_c.append(F_ci) F_V = veps_*df.dot(df.nabla_grad(V), df.nabla_grad(U))*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" in q_rhs: F_V += q_rhs["V"]*U*dx F = sum(F_c) + F_V a, L = df.lhs(F), df.rhs(F) problem = df.LinearVariationalProblem(a, L, w_EC, dirichlet_bcs) solver = df.LinearVariationalSolver(problem) if use_iterative_solvers: solver.parameters["linear_solver"] = "gmres" # solver.parameters["preconditioner"] = "hypre_euclid" return solver
def EvaluateImpl(self, inputs): """ """ numObs = self.numObs numSteps = self.numSteps # Each output = np.zeros((numObs * numSteps)) m = dl.Function(self.V) m.vector().set_local(inputs[0]) p_n = dl.Function(self.V) p_nm1 = dl.Function(self.V) p_n.assign(m) p_nm1.assign(m) p_trial = self.p_trial v = self.v F = (self.c**2) * (self.dt**2) * dl.inner( dl.grad(p_trial), dl.grad(v) ) * dl.dx - 2. * p_n * v * dl.dx + p_trial * v * dl.dx + p_nm1 * v * dl.dx a, L = dl.lhs(F), dl.rhs(F) # Time-stepping p = dl.Function(self.V) t = 0 output[0:numObs] = self.ObservationOperator(p_nm1) output[numObs:2 * numObs] = self.ObservationOperator(p_n) for n in range(2, self.numSteps): # Update current timtime t += self.dt # Compute solution dl.solve(a == L, p) # nb.plot(p) # plt.title("p") # plt.show() output[n * numObs:(n + 1) * numObs] = self.ObservationOperator(p) # Update previous solution p_nm1.assign(p_n) p_n.assign(p) self.outputs = [output]
def algo_fvs_to_cell_averages(self, mesh_util, bcdata, fv_adjacent_cells_function, target_unit=None): '''Algorithm for turning BC data into cell averages. Parameters ---------- mesh_util: :py:class:`.mesh_util.MeshUtil` Mesh utilities and data. bcdata: dict Mapping `{expr: {(facet_value, sign), ...}}`. target_unit: optional Unit to ``expr`` to in the ``bcdict`` argument. fv_adjacent_cells_function: :py:class:`dolfin.Function` DG0 function containing ones and zeros; ones iff the cell is adjacent to a BC. ''' mu = mesh_util dless = mu.unit_registry('dimensionless') DG0 = mu.space.DG0 dx = mu.dx u = dolfin.TrialFunction(DG0) v = dolfin.TestFunction(DG0) form = DelayedForm() for expr, fvss in bcdata.items(): expr = dless * expr.object if target_unit is None: target_unit = expr.units expr_ = expr.m_as(target_unit) for fv, sign in fvss: # TODO: figure out what to do with the sign - relevant # for internal boundary conditions form += mu.ds(subdomain_id=fv) * v('+') * (u('+') - expr_) if target_unit is None: target_unit = dless form += dx * u * v * (1.0 - fv_adjacent_cells_function) form = form.delete_units().to_ufl().m u = dolfin.Function(DG0) dolfin.solve(dolfin.lhs(form) == dolfin.rhs(form), u, []) return target_unit * u
def setup_PF(w_PF, phi, g, psi, h, dx, ds, dirichlet_bcs, neumann_bcs, boundary_to_mark, phi_1, u_1, M_1, c_1, V_1, per_tau, sigma_bar, eps, dbeta, dveps, enable_NS, enable_EC, use_iterative_solvers, q_rhs): """ Set up phase field subproblem. """ F_phi = (per_tau*(phi-unit_interval_filter(phi_1))*psi*dx + M_1*df.dot(df.grad(g), df.grad(psi))*dx) if enable_NS: F_phi += -phi*df.dot(u_1, df.grad(psi))*dx # F_phi += df.div(phi*u_1)*psi*dx F_g = (g*h*dx - sigma_bar*eps*df.dot(df.nabla_grad(phi), df.nabla_grad(h))*dx - sigma_bar/eps*( diff_pf_potential_linearised(phi, unit_interval_filter( phi_1))*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.nabla_grad(V_1), df.nabla_grad(V_1))*h*dx) for boundary_name, costheta in neumann_bcs["phi"].items(): fw_prime = diff_pf_contact_linearised(phi, unit_interval_filter(phi_1)) # Should be just surface tension! F_g += sigma_bar*costheta*fw_prime*h*ds(boundary_to_mark[boundary_name]) if "phi" in q_rhs: F_phi += -q_rhs["phi"]*psi*dx F = F_phi + F_g a, L = df.lhs(F), df.rhs(F) problem = df.LinearVariationalProblem(a, L, w_PF) solver = df.LinearVariationalSolver(problem) if use_iterative_solvers: solver.parameters["linear_solver"] = "gmres" # solver.parameters["preconditioner"] = "hypre_euclid" 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 __init__( self, Q, kappa, rho, cp, convection, source, dirichlet_bcs=None, neumann_bcs=None, robin_bcs=None, my_dx=dx, my_ds=ds, stabilization=None, ): super(Heat, self).__init__() self.Q = Q dirichlet_bcs = dirichlet_bcs or [] neumann_bcs = neumann_bcs or {} robin_bcs = robin_bcs or {} self.convection = convection u = TrialFunction(Q) v = TestFunction(Q) # If there are sharp temperature gradients, numerical oscillations may # occur. This happens because the resulting matrix is not an M-matrix, # caused by the fact that A1 puts positive elements in places other # than the main diagonal. To prevent that, it is suggested by # Großmann/Roos to use a vertex-centered discretization for the mass # matrix part. # Check # https://bitbucket.org/fenics-project/ffc/issues/145/uflacs-error-for-vertex-quadrature-scheme # self.M = assemble( u * v * dx, form_compiler_parameters={ "representation": "quadrature", "quadrature_rule": "vertex", }, ) mesh = Q.mesh() r = SpatialCoordinate(mesh)[0] self.F0 = F( u, v, kappa, rho, cp, convection, source, r, neumann_bcs, robin_bcs, my_dx, my_ds, stabilization, ) self.dirichlet_bcs = dirichlet_bcs self.A, self.b = assemble_system(-lhs(self.F0), rhs(self.F0)) return
def get_system(self, t): # Don't use assemble_system()! See bugs # <https://bitbucket.org/fenics-project/dolfin/issue/257/system_assembler-bilinear-and-linear-forms>, # <https://bitbucket.org/fenics-project/dolfin/issue/78/systemassembler-problem-with-subdomains-on>. return assemble(lhs(self.F0)), assemble(rhs(self.F0))
def stokes_solve(up_out, mu, u_bcs, p_bcs, f, my_dx=dx): # Some initial sanity checks. assert mu > 0.0 WP = up_out.function_space() # Translate the boundary conditions into the product space. new_bcs = helpers.dbcs_to_productspace(WP, [u_bcs, p_bcs]) # TODO define p*=-1 and reverse sign in the end to get symmetric system? # Define variational problem (u, p) = TrialFunctions(WP) (v, q) = TestFunctions(WP) mesh = WP.mesh() r = SpatialCoordinate(mesh)[0] # build system f = F(u, p, v, q, f, r, mu, my_dx) a = lhs(f) L = rhs(f) A, b = assemble_system(a, L, new_bcs) mode = "lu" assert mode == "lu" solve(A, up_out.vector(), b, "lu") # TODO Krylov solver for Stokes # assert mode == 'gmres' # # For preconditioners for the Stokes system, see # # # # Fast iterative solvers for discrete Stokes equations; # # J. Peters, V. Reichelt, A. Reusken. # # # prec = mu * inner(r * grad(u), grad(v)) * 2 * pi * my_dx \ # - p * q * 2 * pi * r * my_dx # P, _ = assemble_system(prec, L, new_bcs) # solver = KrylovSolver('tfqmr', 'hypre_amg') # # solver = KrylovSolver('gmres', 'hypre_amg') # solver.set_operators(A, P) # solver.parameters['monitor_convergence'] = verbose # solver.parameters['report'] = verbose # solver.parameters['absolute_tolerance'] = 0.0 # solver.parameters['relative_tolerance'] = tol # solver.parameters['maximum_iterations'] = maxiter # # Solve # solver.solve(up_out.vector(), b) # elif mode == 'fieldsplit': # # For an assortment of preconditioners, see # # # # Performance and analysis of saddle point preconditioners # # for the discrete steady-state Navier-Stokes equations; # # H.C. Elman, D.J. Silvester, A.J. Wathen; # # Numer. Math. (2002) 90: 665-688; # # <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.3554>. # # # # Set up field split. # W = SubSpace(WP, 0) # P = SubSpace(WP, 1) # u_dofs = W.dofmap().dofs() # p_dofs = P.dofmap().dofs() # prec = PETScPreconditioner() # prec.set_fieldsplit([u_dofs, p_dofs], ['u', 'p']) # PETScOptions.set('pc_type', 'fieldsplit') # PETScOptions.set('pc_fieldsplit_type', 'additive') # PETScOptions.set('fieldsplit_u_pc_type', 'lu') # PETScOptions.set('fieldsplit_p_pc_type', 'jacobi') # # Create Krylov solver with custom preconditioner. # solver = PETScKrylovSolver('gmres', prec) # solver.set_operator(A) return
# Elasticity parameters: E, nu = 10., 0.3 mu, lambda_param = E / (2. * (1.+nu)), E * nu / ((1. + nu) * (1.-2. * nu)) # Stress tensor: # + usually of form \sigma_{ij} = \lambda e_{kk}\delta_{ij} + 2\mu e_{ij}, # + or = \lambda Tr(e_{ij})I + 2\mu e_{ij}, for e_{ij} the strain tensor. sigma = lambda_param*d.tr(d.grad(u)) * d.Identity(w.cell().d) + 2 * mu * d.sym(d.grad(u)) # Governing balance equation: F = d.inner(sigma, d.grad(w)) * d.dx - d.dot(b,w)*d.dx # Extract the bi- and linear forms from F: a = d.lhs(F) L = d.rhs(F) # Dirichlet BC on entire boundary: c = d.Constant((0.,0.,0.)) bc = d.DirichletBC(V, c, d.DomainBoundary()) ## Testing some new boundary definitions: def bzo_boundary(r_vec, on_boundary): # NB: input r_vec is a position vector r,theta,z = cart_to_cyl(x) # NB: check the function cart_to_cyl can take non-tuple collecs. return d.near(r,bzo_radius) ## Testing some differing-boundary BCs: bzo = d.DirichletBC(V, u_bzo, bzo_boundary) ybco = d.DirichletBC(V, u_ybco, ybco_boundary)