def solve(self, mesh, num=5): """ Solve for num eigenvalues based on the mesh. """ # conforming elements V = FunctionSpace(mesh, "CG", self.degree) u = TrialFunction(V) v = TestFunction(V) # weak formulation a = inner(grad(u), grad(v)) * dx b = u * v * ds A = PETScMatrix() B = PETScMatrix() A = assemble(a, tensor=A) B = assemble(b, tensor=B) # find eigenvalues eigensolver = SLEPcEigenSolver(A, B) eigensolver.parameters["spectral_transform"] = "shift-and-invert" eigensolver.parameters["problem_type"] = "gen_hermitian" eigensolver.parameters["spectrum"] = "smallest real" eigensolver.parameters["spectral_shift"] = 1.0E-10 eigensolver.solve(num + 1) # extract solutions lst = [ eigensolver.get_eigenpair(i) for i in range( 1, eigensolver.get_number_converged())] for k in range(len(lst)): u = Function(V) u.vector()[:] = lst[k][2] lst[k] = (lst[k][0], u) # pair (eigenvalue,eigenfunction) return np.array(lst)
def weak_form(self): from bempp.api.assembly.discrete_boundary_operator import SparseDiscreteBoundaryOperator if self._sparse_mat is not None: return SparseDiscreteBoundaryOperator(self._sparse_mat) backend = parameters['linear_algebra_backend'] if backend not in ['PETSc', 'uBLAS']: parameters['linear_algebra_backend'] = 'PETSc' if parameters['linear_algebra_backend'] == 'PETSc': A = as_backend_type(assemble(self._fenics_weak_form)).mat() (indptr, indices, data) = A.getValuesCSR() self._sparse_mat = csr_matrix((data, indices, indptr), shape=A.size) elif parameters['linear_algebra_backend'] == 'uBLAS': self._sparse_mat = assemble(self._fenics_weak_form).sparray() else: raise ValueError( "This should not happen! Backend type is '{0}'. " + "Default backend should have been set to 'PETSc'.".format( parameters['linear_algebra_backend'])) parameters['linear_algebra_backend'] = backend return SparseDiscreteBoundaryOperator(self._sparse_mat)
def M_inv_diag(self, domain = "all"): """ Returns the inverse lumped mass matrix for the vector function space. The result ist cached. .. note:: This method requires the PETSc Backend to be enabled. *Returns* :class:`dolfin.Matrix` the matrix """ if not self._M_inv_diag.has_key(domain): v = TestFunction(self.VectorFunctionSpace()) u = TrialFunction(self.VectorFunctionSpace()) mass_form = inner(v, u) * self.dx(domain) mass_action_form = action(mass_form, Constant((1.0, 1.0, 1.0))) diag = assemble(mass_action_form) as_backend_type(diag).vec().reciprocal() result = assemble(inner(v, u) * dP) result.zero() result.set_diagonal(diag) self._M_inv_diag[domain] = result return self._M_inv_diag[domain]
def transpose_operators(operators): out = [None, None] for i in range(2): op = operators[i] if op is None: out[i] = None elif isinstance(op, dolfin.cpp.GenericMatrix): out[i] = op.__class__() dolfin.assemble(dolfin.adjoint(op.form), tensor=out[i]) if hasattr(op, 'bcs'): adjoint_bcs = [utils.homogenize(bc) for bc in op.bcs if isinstance(bc, dolfin.cpp.DirichletBC)] + [bc for bc in op.bcs if not isinstance(bc, dolfin.DirichletBC)] [bc.apply(out[i]) for bc in adjoint_bcs] elif isinstance(op, dolfin.Form) or isinstance(op, ufl.form.Form): out[i] = dolfin.adjoint(op) if hasattr(op, 'bcs'): out[i].bcs = [utils.homogenize(bc) for bc in op.bcs if isinstance(bc, dolfin.cpp.DirichletBC)] + [bc for bc in op.bcs if not isinstance(bc, dolfin.DirichletBC)] elif isinstance(op, AdjointKrylovMatrix): pass else: print "op.__class__: ", op.__class__ raise libadjoint.exceptions.LibadjointErrorNotImplemented("Don't know how to transpose anything else!") return out
def test_krylov_solver_norm_type(): """Check setting of norm type used in testing for convergence by PETScKrylovSolver """ norm_type = (PETScKrylovSolver.norm_type.default_norm, PETScKrylovSolver.norm_type.natural, PETScKrylovSolver.norm_type.preconditioned, PETScKrylovSolver.norm_type.none, PETScKrylovSolver.norm_type.unpreconditioned) for norm in norm_type: # Solve a system of equations mesh = UnitSquareMesh(4, 4) V = FunctionSpace(mesh, "Lagrange", 1) u, v = TrialFunction(V), TestFunction(V) a = u*v*dx L = Constant(1.0)*v*dx A, b = assemble(a), assemble(L) solver = PETScKrylovSolver("cg") solver.parameters["maximum_iterations"] = 2 solver.parameters["error_on_nonconvergence"] = False solver.set_norm_type(norm) solver.set_operator(A) solver.solve(b.copy(), b) solver.get_norm_type() if norm is not PETScKrylovSolver.norm_type.default_norm: assert solver.get_norm_type() == norm
def calculate_cell_powers(self): """ Calculates cell-integrated powers (sets :attr:`E`). Also performs normalization to the specified core(-fraction) power (:attr:`core.power`). Note that the array is ordered by the associated DG(0) dof, not by the cell index in the mesh. """ q_calc_timer = Timer("FM: Calculation of cell powers") ass_timer = Timer("FM: Assemble cell powers") if self.verb > 2: print0(self.print_prefix + " calculating cell-wise powers.") self.E.fill(0) if not self.up_to_date["flux"]: self.update_phi() for g in xrange(self.DD.G): self.PD.get_xs('eSf', self.R, g) ass_timer.start() self.phig.assign(self.phi_mg[g]) assemble(self.cell_RR_form, tensor=self._cell_RRg_vector) ass_timer.stop() self.E += self._cell_RRg_vector.get_local() self.up_to_date["cell_powers"] = True self.normalize_cell_powers()
def assemble_L(self): #------------------------------ # evaluate numerically, adding the real and imaginary parts L = self.get_L_form() L_theta = dolfin.assemble(L['r_theta']) + 1j*dolfin.assemble(L['i_theta']) L_phi = dolfin.assemble(L['r_phi']) + 1j*dolfin.assemble(L['i_phi']) return (L_theta, L_phi)
def assemble_N(self): #------------------------------ # evaluate numerically, adding the real and imaginary parts N = self.get_N_form() N_theta = dolfin.assemble(N['r_theta']) + 1j*dolfin.assemble(N['i_theta']) N_phi = dolfin.assemble(N['r_phi']) + 1j*dolfin.assemble(N['i_phi']) return (N_theta, N_phi)
def __init__(self, u_, Space, bcs=[], name="div", method={}): solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') low_memory_version = method.get('low_memory_version', False) OasisFunction.__init__(self, div(u_), Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) Source = u_[0].function_space() if not low_memory_version: self.matvec = [[A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], u_[i]] for i in range(Space.mesh().geometry().dim())] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module DG = FunctionSpace(Space.mesh(), 'DG', 0) G = assemble(TrialFunction(DG) * self.test * dx()) dg = Function(DG) self.WGM = [] st = TrialFunction(Source) for i in range(Space.mesh().geometry().dim()): dP = assemble(st.dx(i) * TestFunction(DG) * dx) A = Matrix(G) self.WGM.append(compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, dg))
def compute_err(self, is_tent, velocity, t): if self.doErrControl: er_list_L2 = self.listDict['u2L2' if is_tent else 'u_L2']['list'] er_list_H1 = self.listDict['u2H1' if is_tent else 'u_H1']['list'] self.tc.start('errorV') # assemble is faster than errornorm errorL2_sq = assemble(inner(velocity - self.solution, velocity - self.solution) * dx) errorH1seminorm_sq = assemble(inner(grad(velocity - self.solution), grad(velocity - self.solution)) * dx) info(' H1 seminorm error: %f' % sqrt(errorH1seminorm_sq)) errorL2 = sqrt(errorL2_sq) errorH1 = sqrt(errorL2_sq + errorH1seminorm_sq) info(" Relative L2 error in velocity = %f" % (errorL2 / self.analytic_v_norm_L2)) self.last_error = errorH1 / self.analytic_v_norm_H1 self.last_status_functional = self.last_error info(" Relative H1 error in velocity = %f" % self.last_error) er_list_L2.append(errorL2) er_list_H1.append(errorH1) self.tc.end('errorV') if self.testErrControl: er_list_test_H1 = self.listDict['u2H1test' if is_tent else 'u_H1test']['list'] er_list_test_L2 = self.listDict['u2L2test' if is_tent else 'u_L2test']['list'] self.tc.start('errorVtest') er_list_test_L2.append(errornorm(velocity, self.solution, norm_type='L2', degree_rise=0)) er_list_test_H1.append(errornorm(velocity, self.solution, norm_type='H1', degree_rise=0)) self.tc.end('errorVtest') # stopping criteria for detecting diverging solution if self.last_error > self.divergence_treshold: raise RuntimeError('STOPPED: Failed divergence test!')
def initialize(self, V, Q, PS, D): super(Problem, self).initialize(V, Q, PS, D) print("IC type: " + self.ic) print("Velocity scale factor = %4.2f" % self.factor) reynolds = 728.761 * self.factor # TODO modify by nu_factor print("Computing with Re = %f" % reynolds) self.v_in = Function(V) print('Initializing error control') self.load_precomputed_bessel_functions(PS) self.solution = self.assemble_solution(0.0) # set constants for self.area = assemble(interpolate(Expression("1.0"), Q) * self.dsIn) # inflow area # womersley = steady + e^iCt, e^iCt has average 0 self.pg_normalization_factor.append(womersleyBC.average_analytic_pressure_grad(self.factor)) self.p_normalization_factor.append(norm( interpolate(womersleyBC.average_analytic_pressure_expr(self.factor), self.pSpace), norm_type='L2')) self.vel_normalization_factor.append(norm( interpolate(womersleyBC.average_analytic_velocity_expr(self.factor), self.vSpace), norm_type='L2')) # print('Normalisation factors (vel, p, pg):', self.vel_normalization_factor[0], self.p_normalization_factor[0], # self.pg_normalization_factor[0]) one = (interpolate(Expression('1.0'), Q)) self.outflow_area = assemble(one*self.dsOut) print('Outflow area:', self.outflow_area)
def les_update(nut_, nut_form, A_mass, At, u_, dt, bc_ksgs, bt, ksgs_sol, KineticEnergySGS, CG1, ksgs, delta, **NS_namespace): p, q = TrialFunction(CG1), TestFunction(CG1) Ck = KineticEnergySGS["Ck"] Ce = KineticEnergySGS["Ce"] Sij = sym(grad(u_)) assemble(dt*inner(dot(u_, 0.5*grad(p)), q)*dx + inner((dt*Ce*sqrt(ksgs)/delta)*0.5*p, q)*dx + inner(dt*Ck*sqrt(ksgs)*delta*grad(0.5*p), grad(q))*dx, tensor=At) assemble(dt*2*Ck*delta*sqrt(ksgs)*inner(Sij,grad(u_))*q*dx, tensor=bt) bt.axpy(1.0, A_mass*ksgs.vector()) bt.axpy(-1.0, At*ksgs.vector()) At.axpy(1.0, A_mass, True) # Solve for ksgs bc_ksgs.apply(At, bt) ksgs_sol.solve(At, ksgs.vector(), bt) ksgs.vector().set_local(ksgs.vector().array().clip(min=1e-7)) ksgs.vector().apply("insert") # Update nut_ nut_()
def check_ass_penaro(bcsd=None, bcssfuns=None, V=None, plot=False): mesh = V.mesh() bcone = bcsd[1] contshfunone = bcssfuns[1] Gammaone = bcone() bparts = dolfin.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) Gammaone.mark(bparts, 0) u = dolfin.TrialFunction(V) v = dolfin.TestFunction(V) # Robin boundary form arob = dolfin.inner(u, v) * dolfin.ds(0) brob = dolfin.inner(v, contshfunone) * dolfin.ds(0) amatrob = dolfin.assemble(arob, exterior_facet_domains=bparts) bmatrob = dolfin.assemble(brob, exterior_facet_domains=bparts) amatrob = dts.mat_dolfin2sparse(amatrob) amatrob.eliminate_zeros() print 'Number of nonzeros in amatrob:', amatrob.nnz bmatrob = bmatrob.array() # [ININDS] if plot: plt.figure(2) plt.spy(amatrob) if plot: plt.figure(1) for x in contshfunone.xs: plt.plot(x[0], x[1], 'bo') plt.show()
def weighted_gradient_matrix(mesh, i, degree=1, constrained_domain=None): """Compute weighted gradient matrix The matrix allows us to compute the gradient of a P1 Function through a simple matrix vector product p_ is the pressure solution on CG1 dPdX = weighted_gradient_matrix(mesh, 0, degree) V = FunctionSpace(mesh, 'CG', degree) dpdx = Function(V) dpdx.vector()[:] = dPdX * p_.vector() The space for dpdx must be continuous Lagrange of some order """ DG = FunctionSpace(mesh, 'DG', 0) CG = FunctionSpace(mesh, 'CG', degree, constrained_domain=constrained_domain) CG1 = FunctionSpace(mesh, 'CG', 1, constrained_domain=constrained_domain) C = assemble(TrialFunction(CG)*TestFunction(CG)*dx) G = assemble(TrialFunction(DG)*TestFunction(CG)*dx) dg = Function(DG) if isinstance(i, (tuple, list)): CC = [] for ii in i: dP = assemble(TrialFunction(CG1).dx(ii)*TestFunction(DG)*dx) A = Matrix(G) compiled_gradient_module.compute_weighted_gradient_matrix(A, dP, C, dg) CC.append(C.copy()) return CC else: dP = assemble(TrialFunction(CG1).dx(i)*TestFunction(DG)*dx) compiled_gradient_module.compute_weighted_gradient_matrix(G, dP, C, dg) return C
def save_pressure(self, is_tent, pressure): super(Problem, self).save_pressure(is_tent, pressure) self.tc.start('computePG') # Report pressure gradient p_in = assemble((1.0/self.area) * pressure * self.dsIn) p_out = assemble((1.0/self.area) * pressure * self.dsOut) computed_gradient = (p_in - p_out)/20.0 # 20.0 is a length of a pipe NT should depend on mesh length (implement through metadata or function of mesh) self.tc.end('computePG') self.tc.start('errorP') error = errornorm(self.sol_p, pressure, norm_type="l2", degree_rise=0) self.listDict['p2' if is_tent else 'p']['list'].append(error) print("Normalized pressure error norm:", error/self.p_normalization_factor[0]) self.listDict['pg2' if is_tent else 'pg']['list'].append(computed_gradient) if not is_tent: self.listDict['apg']['list'].append(self.analytic_gradient) self.listDict['pgE2' if is_tent else 'pgE']['list'].append(computed_gradient-self.analytic_gradient) self.listDict['pgEA2' if is_tent else 'pgEA']['list'].append(abs(computed_gradient-self.analytic_gradient)) self.tc.end('errorP') if self.doSaveDiff: sol_pg_expr = Expression(("0", "0", "pg"), pg=self.analytic_gradient / self.pg_normalization_factor[0]) # sol_pg = interpolate(sol_pg_expr, self.pgSpace) # plot(sol_p, title="sol") # plot(pressure, title="p") # plot(pressure - sol_p, interactive=True, title="diff") # exit() self.pFunction.assign(pressure-self.sol_p) self.fileDict['p2D' if is_tent else 'pD']['file'] << self.pFunction
def gp(self, Bt): """Assemble discrete pressure gradient. It is crucial to respect any constraints placed on the velocity test space by Dirichlet boundary conditions.""" assemble(self.get_dolfin_form("gp"), tensor=Bt) for bc in self._bcs: bc.apply(Bt)
def identity_at_coarse_level(self): I = PETScMatrix() u = TrialFunction(self.V_coarse) v = TestFunction(self.V_coarse) assemble(Constant(0)*u*v*dx, tensor=I) I.ident_zeros() return I
def __init__(self, coarse_mesh, nref, p_coarse, p_fine): super(LaplaceEigenvalueProblem, self).__init__(coarse_mesh, nref, p_coarse, p_fine) print0("Assembling fine-mesh problem") self.dirichlet_bdry = lambda x,on_boundary: on_boundary bc = DirichletBC(self.V_fine, 0.0, self.dirichlet_bdry) u = TrialFunction(self.V_fine) v = TestFunction(self.V_fine) a = inner(grad(u), grad(v))*dx m = u*v*dx # Assemble the stiffness matrix and the mass matrix. b = v*dx # just need this to feed an argument to assemble_system assemble_system(a, b, bc, A_tensor=self.A_fine) assemble_system(m, b, bc, A_tensor=self.B_fine) # set the diagonal elements of M corresponding to boundary nodes to zero to # remove spurious eigenvalues. bc.zero(self.B_fine) print0("Assembling coarse-mesh problem") self.bc_coarse = DirichletBC(self.V_coarse, 0.0, self.dirichlet_bdry) u = TrialFunction(self.V_coarse) v = TestFunction(self.V_coarse) a = inner(grad(u), grad(v))*dx m = u*v*dx # Assemble the stiffness matrix and the mass matrix, without Dirichlet BCs. Dirichlet DOFs will be removed later. assemble(a, tensor=self.A_coarse) assemble(m, tensor=self.B_coarse)
def initialize(self, V, Q, PS, D): super(Problem, self).initialize(V, Q, PS, D) print("IC type: " + self.ic) print("Velocity scale factor = %4.2f" % self.factor) reynolds = 728.761 * self.factor print("Computing with Re = %f" % reynolds) # set constants for self.area = assemble(interpolate(Expression("1.0"), Q) * self.dsIn) # inflow area self.solution = interpolate(Expression(("0.0", "0.0", "factor*(1081.48-43.2592*(x[0]*x[0]+x[1]*x[1]))"), factor=self.factor), self.vSpace) analytic_pressure = womersleyBC.average_analytic_pressure_expr(self.factor) self.sol_p = interpolate(analytic_pressure, self.pSpace) self.analytic_gradient = womersleyBC.average_analytic_pressure_grad(self.factor) self.analytic_pressure_norm = norm(self.sol_p, norm_type='L2') self.analytic_v_norm_L2 = norm(self.solution, norm_type='L2') self.analytic_v_norm_H1 = norm(self.solution, norm_type='H1') self.analytic_v_norm_H1w = sqrt(assemble((inner(grad(self.solution), grad(self.solution)) + inner(self.solution, self.solution)) * self.dsWall)) print("Prepared analytic solution.") self.pg_normalization_factor.append(womersleyBC.average_analytic_pressure_grad(self.factor)) self.p_normalization_factor.append(self.analytic_pressure_norm) self.vel_normalization_factor.append(norm(self.solution, norm_type='L2')) print('Normalisation factors (vel, p, pg):', self.vel_normalization_factor[0], self.p_normalization_factor[0], self.pg_normalization_factor[0]) one = (interpolate(Expression('1.0'), Q)) self.outflow_area = assemble(one*self.dsOut) print('Outflow area:', self.outflow_area)
def setup_forms(self, old_solver): prob = self.prob if old_solver is not None: self.old_vel = dfn.interpolate(old_solver.old_vel, prob.v_fnc_space) self.cur_vel = dfn.interpolate(old_solver.cur_vel, prob.v_fnc_space) else: self.old_vel = dfn.Function(prob.v_fnc_space) self.cur_vel = dfn.Function(prob.v_fnc_space) # Assemble matrices from variational forms. Ax = Ls self.a = dfn.inner(dfn.grad(prob.v), dfn.grad(prob.vt)) * dfn.dx self.A = dfn.assemble(self.a) if params['bcs'] is 'test': self.bcs = get_test_bcs(prob.v_fnc_space, test_bc) else: self.bcs = get_normal_bcs(prob.v_fnc_space, test_bc) # For the gradient term in the stress update self.l_elastic = self.dt * self.mu * \ dfn.inner(dfn.grad(prob.v), prob.St) * dfn.dx self.L_elastic = dfn.assemble(self.l_elastic)
def mult(self, lamhat, y): """ mult(self, lamhat, y): return y = Hessian * lamhat inputs: y, lamhat = Function(V).vector() """ self.regularization.assemble_hessian(lamhat) setfct(self.lamhat, lamhat) self.C = assemble(self.wkformrhsincr) if self.PDE.abc: self.Dp = assemble(self.wkformDprime) # solve for phat self.PDE.set_fwd() self.PDE.ftime = self.ftimeincrfwd self.solincrfwd,_ = self.PDE.solve() # solve for vhat self.PDE.set_adj() self.PDE.ftime = self.ftimeincradj self.solincradj,_ = self.PDE.solve() # Compute Hessian*lamhat y.zero() index = 0 if self.PDE.abc: self.vD.vector().zero(); self.vhatD.vector().zero(); self.p1D.vector().zero(); self.p2D.vector().zero(); self.p1hatD.vector().zero(); self.p2hatD.vector().zero(); for fwd, adj, incrfwd, incradj, fact in \ zip(self.solfwd, reversed(self.soladj), \ self.solincrfwd, reversed(self.solincradj), self.factors): ttf, tta, ttf2 = incrfwd[1], incradj[1], fwd[1] assert isequal(ttf, tta, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\ format(ttf, tta, abs(ttf-tta)/ttf) assert isequal(ttf, ttf2, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\ format(ttf, ttf2, abs(ttf-ttf2)/ttf) setfct(self.p, fwd[0]) setfct(self.v, adj[0]) setfct(self.phat, incrfwd[0]) setfct(self.vhat, incradj[0]) y.axpy(fact, assemble(self.wkformhess)) if self.PDE.abc: if index%2 == 0: self.p2D.vector().axpy(1.0, self.p.vector()) self.p2hatD.vector().axpy(1.0, self.phat.vector()) setfct(self.dp, self.p2D) setfct(self.dph, self.p2hatD) y.axpy(1.0*0.5*self.invDt, assemble(self.wkformhessD)) setfct(self.p2D, -1.0*self.p.vector()) setfct(self.p2hatD, -1.0*self.phat.vector()) else: self.p1D.vector().axpy(1.0, self.p.vector()) self.p1hatD.vector().axpy(1.0, self.phat.vector()) setfct(self.dp, self.p1D) setfct(self.dph, self.p1hatD) y.axpy(1.0*0.5*self.invDt, assemble(self.wkformhessD)) setfct(self.p1D, -1.0*self.p.vector()) setfct(self.p1hatD, -1.0*self.phat.vector()) setfct(self.vD, self.v) setfct(self.vhatD, self.vhat) index += 1 # add regularization term y.axpy(self.alpha_reg, self.regularization.hessian(lamhat))
def __init__(self, Vh, dX, bcs, form = None): """ Constructor: :code:`Vh`: the finite element space for the state variable. :code:`dX`: the integrator on subdomain `X` where observation are presents. \ E.g. :code:`dX = dl.dx` means observation on all :math:`\Omega` and :code:`dX = dl.ds` means observations on all :math:`\partial \Omega`. :code:`bcs`: If the forward problem imposes Dirichlet boundary conditions :math:`u = u_D \mbox{ on } \Gamma_D`; \ :code:`bcs` is a list of :code:`dolfin.DirichletBC` object that prescribes homogeneuos Dirichlet conditions :math:`u = 0 \mbox{ on } \Gamma_D`. :code:`form`: if :code:`form = None` we compute the :math:`L^2(X)` misfit: :math:`\int_X (u - u_d)^2 dX,` \ otherwise the integrand specified in the given form will be used. """ if form is None: u, v = dl.TrialFunction(Vh), dl.TestFunction(Vh) self.W = dl.assemble(dl.inner(u,v)*dX) else: self.W = dl.assemble( form ) if bcs is None: bcs = [] if isinstance(bcs, dl.DirichletBC): bcs = [bcs] if len(bcs): Wt = Transpose(self.W) [bc.zero(Wt) for bc in bcs] self.W = Transpose(Wt) [bc.zero(self.W) for bc in bcs] self.d = dl.Vector(self.W.mpi_comm()) self.W.init_vector(self.d,1) self.noise_variance = None
def assemble_AA_BB(aa, bb, pp=None, cc=None): ''' Return assembled system matrix [[aa, bb.T], [bb, 0]] and its preconditioner [[pp, 0], [cc]] from forms. ''' # Get the blocks A = assemble(aa) B = assemble(bb) n = A.size(0) N = n + B.size(0) print 'System has size', N # Assemble system matrix and get its condition number AA = np.zeros((N, N)) AA[:n, :n] = A.array() AA[:n, n:] = B.array().T AA[n:, :n] = B.array() AA = csr_matrix(AA) # convert to sparse if pp is None and cc is None: return AA else: P = assemble(pp) C = assemble(cc) BB = np.zeros((N, N)) BB[:n, :n] = P.array() BB[n:, n:] = C.array() BB = csr_matrix(BB) return AA, BB
def setget_rhs(V, Q, fv, fp, t=None): if t is not None: fv.t = t fp.t = t elif hasattr(fv, 't') or hasattr(fp, 't'): Warning('No value for t specified') v = dolfin.TestFunction(V) q = dolfin.TestFunction(Q) fv = inner(fv, v) * dx fp = inner(fp, q) * dx fv = dolfin.assemble(fv) fp = dolfin.assemble(fp) fv = fv.get_local() fv = fv.reshape(len(fv), 1) fp = fp.get_local() fp = fp.reshape(len(fp), 1) rhsvecs = {'fv': fv, 'fp': fp} return rhsvecs
def get_voltage_current_matrix(phi, physical_indices, dx, Sigma, omega, v_ref ): '''Compute the matrix that relates the voltages with the currents in the coil rings. (The relationship is indeed linear.) This is according to :cite:`KP02`. The entry :math:`J_{k,l}` in the resulting matrix is the contribution of the potential generated by coil :math:`l` to the current in coil :math:`k`. ''' mesh = phi[0].function_space().mesh() r = Expression('x[0]', degree=1, domain=mesh) num_coil_rings = len(phi) J = numpy.empty((num_coil_rings, num_coil_rings), dtype=numpy.complex) for l, pi0 in enumerate(physical_indices): partial_phi_r, partial_phi_i = phi[l].split() for k, pi1 in enumerate(physical_indices): # -1i*omega*int_{coil_k} sigma phi. int_r = assemble(Sigma[pi1] * partial_phi_r * dx(pi1)) int_i = assemble(Sigma[pi1] * partial_phi_i * dx(pi1)) J[k][l] = -1j * omega * (int_r + 1j * int_i) # v_ref/(2*pi) * int_{coil_l} sigma/r. # 1/r doesn't explode since we only evaluate it in the coils where # r!=0. # For assemble() to work, a mesh needs to be supplied either implicitly # by the integrand, or explicitly. Since the integrand doesn't contain # mesh information here, pass it through explicitly. J[l][l] += v_ref / (2 * pi) \ * assemble(Sigma[pi0] / r * dx(pi0)) return J
def __init__(self, p_, Space, i=0, bcs=[], name="grad", method={}): assert len(p_.ufl_shape) == 0 assert i >= 0 and i < Space.mesh().geometry().dim() solver_type = method.get('solver_type', 'cg') preconditioner_type = method.get('preconditioner_type', 'default') solver_method = method.get('method', 'default') low_memory_version = method.get('low_memory_version', False) OasisFunction.__init__(self, p_.dx(i), Space, bcs=bcs, name=name, method=solver_method, solver_type=solver_type, preconditioner_type=preconditioner_type) self.i = i Source = p_.function_space() if not low_memory_version: self.matvec = [ A_cache[(self.test * TrialFunction(Source).dx(i) * dx, ())], p_] if solver_method.lower() == "gradient_matrix": from fenicstools import compiled_gradient_module DG = FunctionSpace(Space.mesh(), 'DG', 0) G = assemble(TrialFunction(DG) * self.test * dx()) dg = Function(DG) dP = assemble(TrialFunction(p_.function_space()).dx(i) * TestFunction(DG) * dx()) self.WGM = compiled_gradient_module.compute_weighted_gradient_matrix( G, dP, dg)
def test_krylov_solver_options_prefix(pushpop_parameters): "Test set/get PETScKrylov solver prefix option" # Set backend parameters["linear_algebra_backend"] = "PETSc" # Prefix prefix = "test_foo_" # Create solver and set prefix solver = PETScKrylovSolver() solver.set_options_prefix(prefix) # Check prefix (pre solve) assert solver.get_options_prefix() == prefix # Solve a system of equations mesh = UnitSquareMesh(4, 4) V = FunctionSpace(mesh, "Lagrange", 1) u, v = TrialFunction(V), TestFunction(V) a, L = u*v*dx, Constant(1.0)*v*dx A, b = assemble(a), assemble(L) solver.set_operator(A) solver.solve(b.copy(), b) # Check prefix (post solve) assert solver.get_options_prefix() == prefix
def __init__(self, aneurysm, near_vessel, *args, **kwargs): Field.__init__(self, *args, **kwargs) self.aneurysm = aneurysm self.near_vessel = near_vessel self.Vnv = assemble(Constant(1)*dx(near_vessel[1], domain=near_vessel[0].mesh(), subdomain_data=near_vessel[0])) self.Va = assemble(Constant(1)*dx(aneurysm[1], domain=aneurysm[0].mesh(), subdomain_data=aneurysm[0]))
def __init__(self, cparams, dtype_u, dtype_f): """ Initialization routine Args: cparams: custom parameters for the example dtype_u: particle data type (will be passed parent class) dtype_f: acceleration data type (will be passed parent class) """ # define the Dirichlet boundary def Boundary(x, on_boundary): return on_boundary # these parameters will be used later, so assert their existence assert 'c_nvars' in cparams assert 'nu' in cparams assert 't0' in cparams assert 'family' in cparams assert 'order' in cparams assert 'refinements' in cparams # add parameters as attributes for further reference for k,v in cparams.items(): setattr(self,k,v) df.set_log_level(df.WARNING) # set mesh and refinement (for multilevel) mesh = df.UnitIntervalMesh(self.c_nvars) # mesh = df.UnitSquareMesh(self.c_nvars[0],self.c_nvars[1]) for i in range(self.refinements): mesh = df.refine(mesh) # define function space for future reference self.V = df.FunctionSpace(mesh, self.family, self.order) tmp = df.Function(self.V) print('DoFs on this level:',len(tmp.vector().array())) # invoke super init, passing number of dofs, dtype_u and dtype_f super(fenics_heat2d,self).__init__(self.V,dtype_u,dtype_f) # Stiffness term (Laplace) u = df.TrialFunction(self.V) v = df.TestFunction(self.V) a_K = -1.0*df.inner(df.nabla_grad(u), self.nu*df.nabla_grad(v))*df.dx # Mass term a_M = u*v*df.dx self.M = df.assemble(a_M) self.K = df.assemble(a_K) # set forcing term as expression self.g = df.Expression('-sin(a*x[0]) * (sin(t) - b*a*a*cos(t))',a=np.pi,b=self.nu,t=self.t0,degree=self.order) # self.g = df.Expression('-sin(a*x[0]) * sin(a*x[1]) * (sin(t) - b*2*a*a*cos(t))',a=np.pi,b=self.nu,t=self.t0,degree=self.order) # set boundary values self.bc = df.DirichletBC(self.V, df.Constant(0.0), Boundary)
def compute(self, get): u = get("Velocity") assemble(dot(u[1].dx(0)-u[0].dx(1), self.q)*dx(), tensor=self.L) self.bc.apply(self.L) self.solver.solve(self.psi.vector(), self.L) #solve(self.A, self.psi.vector(), self.L) return self.psi
def compile_continuation_data(self, load, iteration, perturbed): model = self.model u = self.solver.u alpha = self.solver.alpha if not perturbed: self.continuation_data_i = {} self.continuation_data_i["elastic_energy"] = assemble(model.elastic_energy_density(model.eps(u), alpha)*model.dx) if self.user_density is not None: self.continuation_data_i["elastic_energy"] += assemble(self.user_density*model.dx) self.continuation_data_i["dissipated_energy"] = assemble(model.damage_dissipation_density(alpha)*model.dx) self.continuation_data_i["total_energy"] = self.continuation_data_i["elastic_energy"] + self.continuation_data_i["dissipated_energy"] self.continuation_data_i["load"] = load self.continuation_data_i["iteration"] = iteration self.continuation_data_i["alpha_l2"] = alpha.vector().norm('l2') self.continuation_data_i["alpha_h1"] = norm(alpha, 'h1') self.continuation_data_i["alpha_max"] = np.max(alpha.vector()[:]) self.continuation_data_i["eigs"] = self.stability.eigs else: elastic_post = assemble(model.elastic_energy_density(model.eps(u), alpha)*model.dx) if self.user_density is not None: elastic_post += assemble(self.user_density*model.dx) dissipated_post = assemble(model.damage_dissipation_density(alpha)*model.dx) self.continuation_data_i["elastic_energy_diff"] = elastic_post-self.continuation_data_i["elastic_energy"] self.continuation_data_i["dissipated_energy_diff"] = dissipated_post-self.continuation_data_i["dissipated_energy"] self.continuation_data_i["total_energy_diff"] = self.continuation_data_i["elastic_energy_diff"]\ +self.continuation_data_i["dissipated_energy_diff"] # ColorPrint.print_info('energy {:4e}'.format(elastic_energy_post + dissipated_energy_post)) # ColorPrint.print_info('estimate {:4e}'.format(stability.en_estimate)) # ColorPrint.print_info('en-est {:4e}'.format(elastic_energy_post + dissipated_energy_post-stability.en_estimate)) pass
def gradient(self, z_v): self.z.vector().set_local(z_v) grad = self.solver.gradient(self.z, self.data) + dl.assemble( self.solver.grad_reg)[:] return grad
def get_stokessysmats(V, Q, nu=None, bccontrol=False, cbclist=None, cbshapefuns=None): """ Assembles the system matrices for Stokes equation in mixed FEM formulation, namely .. math:: \\begin{bmatrix} A & -J' \\\\ J & 0 \\end{bmatrix}\ \\colon V \\times Q \\to V' \\times Q' as the discrete representation of .. math:: \\begin{bmatrix} -\\Delta & \\text{grad} \\\\ \ \\text{div} & 0 \\end{bmatrix} plus the velocity and pressure mass matrices for a given trial and test space W = V * Q not considering boundary conditions. Parameters ---------- V : dolfin.VectorFunctionSpace Fenics VectorFunctionSpace for the velocity Q : dolfin.FunctionSpace Fenics FunctionSpace for the pressure nu : float, optional viscosity parameter - defaults to 1 bccontrol : boolean, optional whether boundary control (via penalized Robin conditions) is applied, defaults to `False` cbclist : list, optional list of dolfin's Subdomain classes describing the control boundaries cbshapefuns : list, optional list of spatial shape functions of the control boundaries Returns ------- stokesmats, dictionary a dictionary with the following keys: * ``M``: the mass matrix of the velocity space, * ``A``: the stiffness matrix \ :math:`\\nu \\int_\\Omega (\\nabla \\phi_i, \\nabla \\phi_j)` * ``JT``: the gradient matrix, * ``J``: the divergence matrix, and * ``MP``: the mass matrix of the pressure space * ``Apbc``: (N, N) sparse matrix, \ the contribution of the Robin conditions to `A` \ :math:`\\nu \\int_\\Gamma (\\phi_i, \\phi_j)` * ``Bpbc``: (N, k) sparse matrix, the input matrix of the Robin \ conditions :math:`\\nu \\int_\\Gamma (\\phi_i, g_k)`, \ where :math:`g_k` is the shape function associated with the \ j-th control boundary segment """ u = dolfin.TrialFunction(V) p = dolfin.TrialFunction(Q) v = dolfin.TestFunction(V) q = dolfin.TestFunction(Q) if nu is None: nu = 1 print('No viscosity provided -- we set `nu=1`') ma = inner(u, v) * dx mp = inner(p, q) * dx aa = nu * inner(grad(u), grad(v)) * dx grada = div(v) * p * dx diva = q * div(u) * dx # Assemble system M = dolfin.assemble(ma) A = dolfin.assemble(aa) Grad = dolfin.assemble(grada) Div = dolfin.assemble(diva) MP = dolfin.assemble(mp) # Convert DOLFIN representation to scipy arrays Ma = mat_dolfin2sparse(M) MPa = mat_dolfin2sparse(MP) Aa = mat_dolfin2sparse(A) JTa = mat_dolfin2sparse(Grad) Ja = mat_dolfin2sparse(Div) stokesmats = {'M': Ma, 'A': Aa, 'JT': JTa, 'J': Ja, 'MP': MPa} if bccontrol: amatrobl, bmatrobl = [], [] mesh = V.mesh() for bc, bcfun in zip(cbclist, cbshapefuns): # get an instance of the subdomain class Gamma = bc() # bparts = dolfin.MeshFunction('size_t', mesh, # mesh.topology().dim() - 1) boundaries = dolfin.FacetFunction("size_t", mesh) boundaries.set_all(0) Gamma.mark(boundaries, 1) ds = dolfin.Measure('ds', domain=mesh, subdomain_data=boundaries) # Gamma.mark(bparts, 0) # Robin boundary form arob = dolfin.inner(u, v) * ds(1) # , subdomain_data=bparts) brob = dolfin.inner(v, bcfun) * ds(1) # , subdomain_data=bparts) amatrob = dolfin.assemble(arob) # , exterior_facet_domains=bparts) bmatrob = dolfin.assemble(brob) # , exterior_facet_domains=bparts) amatrob = mat_dolfin2sparse(amatrob) amatrob.eliminate_zeros() amatrobl.append(amatrob) bmatrobl.append(bmatrob.array().reshape((V.dim(), 1))) # [ININDS] amatrob = amatrobl[0] for amatadd in amatrobl[1:]: amatrob = amatrob + amatadd bmatrob = np.hstack(bmatrobl) stokesmats.update({'amatrob': amatrob, 'bmatrob': bmatrob}) return stokesmats
ndim = 2 nx = 64 ny = 64 mesh = dl.UnitSquareMesh(nx, ny) Vh = dl.FunctionSpace(mesh, "CG", 1) T = dl.Expression(code_AnisTensor2D) T.theta0 = 2. T.theta1 = .5 T.alpha = math.pi/4 u = dl.TrialFunction(Vh) v = dl.TestFunction(Vh) a = dl.inner(T*dl.grad(u), dl.grad(v))*dl.dx A = dl.assemble(a) e = dl.Expression(code_Mollifier) e.o = 2 e.l = 0.2 e.addLocation(.1,.1) e.addLocation(.1,.9) e.addLocation(.5,.5) e.addLocation(.9,.1) e.addLocation(.9,.9) e.theta0 = 1./T.theta0 e.theta1 = 1./T.theta1 e.alpha = T.alpha m = dl.interpolate(e, Vh)
def j(self, t, u): return dol.assemble(u * self.dx_obs) / self.t_end
def compute(geo): vol = dolfin.assemble(r * geo.dx("molecule")) return Qmol / vol if vol > 0. else 0.
def normal_velocity(mode, solver): return dolf.assemble((dolf.dot(mode[1], solver.domain.n)) * solver.domain.ds(boundary5.surface_index))
RectangleMesh = 2.548s msrh.Rectangle = 2.886s 1000x1000 Serial (ccgo1): UnitSquareMesh = 30.083s RectangleMesh = 30.216s msrh.Rectangle = 53.257s Parallel 16 cores (ccgo1): UnitSquareMesh = 6.686s RectangleMesh = 6.537s msrh.Rectangle = 23.670s """ import dolfin as dl from mshr import Rectangle, generate_mesh mesh = dl.UnitSquareMesh(20, 20) #mesh = dl.RectangleMesh(dl.Point(0.,0.), dl.Point(1.,1.), 1000, 1000) #domain= Rectangle(dl.Point(0.,0.), dl.Point(1.,1.)) #mesh = generate_mesh(domain, 893) V = dl.FunctionSpace(mesh, 'Lagrange', 3) test, trial = dl.TestFunction(V), dl.TrialFunction(V) u = dl.interpolate(dl.Expression('x[0]*x[1]'), V) M = dl.assemble(dl.inner(test, trial) * dl.dx) print u.vector().size(), len(V.dofmap().dofs()) # only to check size of mesh
def __init__(self, fenics_2d_part, loads, boundary_conditions, element): """ The FacetFunction must be the same for all BC and facet loads. Its type of value must be 'size_t' (unsigned integers). Parameters ---------- fenics_2d_part : FEnicsPart [description] loads : [type] [description] boundary_conditions : list or tuple All the boundary conditions. Each of them is describe by a tuple or a dictionnary. Only one periodic BC can be prescribed. Format: if Periodic BC : {'type': 'Periodic', 'constraint': PeriodicDomain} or ('Periodic', PeriodicDomain) if Dirichlet BC : { 'type': 'Dirichlet', 'constraint': the prescribed value, 'facet_function': facet function, 'facet_idx': facet function index} or ('Dirichlet', the prescribed value, facet function, facet function index) or ('Dirichlet', the prescribed value, indicator function) where the indicator function is python function like : def clamped(x, on_boundary): return on_boundary and x[0] < tolerance element: tuple or dict Ex: ('CG', 2) or {'family':'Lagrange', degree:2} """ self.part = fenics_2d_part # * Boundary conditions self.per_bc = None self.Dirichlet_bc = list() for bc in boundary_conditions: if isinstance(bc, dict): bc_ = bc bc = [bc_["type"], bc_["constraint"]] try: bc.append(bc_["facet_function"]) bc.append(bc_["facet_idx"]) except KeyError: pass bc_type, *bc_data = bc if bc_type == "Periodic": if self.per_bc is not None: raise AttributeError( "Only one periodic boundary condition can be prescribed." ) self.per_bc = bc_data[0] elif bc_type == "Dirichlet": if len(bc_data) == 2 or len(bc_data) == 3: bc_data = tuple(bc_data) else: raise AttributeError( "Too much parameter for the definition of a Dirichlet BC." ) self.Dirichlet_bc.append(bc_data) self.measures = {self.part.dim: fe.dx, self.part.dim - 1: fe.ds} # * Function spaces try: self.elmt_family = family = element["family"] self.elmt_degree = degree = element["degree"] except TypeError: # Which means that element is not a dictionnary self.element_family, self.element_degree = element family, degree = element cell = self.part.mesh.ufl_cell() Voigt_strain_dim = int(self.part.dim * (self.part.dim + 1) / 2) strain_deg = degree - 1 if degree >= 1 else 0 strain_FE = fe.VectorElement("DG", cell, strain_deg, dim=Voigt_strain_dim) self.scalar_fspace = fe.FunctionSpace( self.part.mesh, fe.FiniteElement(family, cell, degree), constrained_domain=self.per_bc, ) self.displ_fspace = fe.FunctionSpace( self.part.mesh, fe.VectorElement(family, cell, degree, dim=self.part.dim), constrained_domain=self.per_bc, ) self.strain_fspace = fe.FunctionSpace(self.part.mesh, strain_FE, constrained_domain=self.per_bc) self.v = fe.TestFunction(self.displ_fspace) self.u = fe.TrialFunction(self.displ_fspace) self.a = (fe.inner( mat.sigma(self.part.elasticity_tensor, mat.epsilon(self.u)), mat.epsilon(self.v), ) * self.measures[self.part.dim]) self.K = fe.assemble(self.a) # * Create suitable objects for Dirichlet boundary conditions for i, bc_data in enumerate(self.Dirichlet_bc): self.Dirichlet_bc[i] = fe.DirichletBC(self.displ_fspace, *bc_data) # ? Vu comment les conditions aux limites de Dirichlet interviennent dans le problème, pas sûr que ce soit nécessaire que toutes soient définies avec la même facetfunction # * Taking into account the loads if loads: self.set_loads(loads) else: self.loads_data = None self.load_integrals = None # * Prepare attribute for the solver self.solver = None
Echi = df.FiniteElement("Lagrange", mesh.ufl_cell(), 2) pbc = PeriodicBC(Lx, Ly) wall = Wall(Lx, Ly) notwall = NotWall(Lx, Ly) subd = df.MeshFunction("size_t", mesh, mesh.topology().dim()-1) subd.set_all(0) wall.mark(subd, 1) notwall.mark(subd, 0) S = df.FunctionSpace(mesh, Echi, constrained_domain=pbc) one = df.interpolate(df.Constant(1.), S) V_Omega = df.assemble(one*df.dx) n = df.FacetNormal(mesh) chi = df.TrialFunction(S) chi_ = df.Function(S, name="chi") psi = df.TestFunction(S) ds = df.Measure("ds", domain=mesh, subdomain_data=subd) F_chi = (n[0]*psi*ds(1) + df.inner(df.grad(chi), df.grad(psi))*df.dx) a_chi, L_chi = df.lhs(F_chi), df.rhs(F_chi) problem_chi2 = df.LinearVariationalProblem(a_chi, L_chi, chi_, bcs=[])
def callback(arg): return assemble(arg)
def __init__( self, a_k, u, a_m=None, # optional, for eigpb of the type (K-lambda M)x=0 bcs=None, restricted_dofs_is=None, slepc_options='', option_prefix='eigen_', comm=MPI.comm_world, slepc_eigensolver=None, initial_guess=None): """ Solver object for constrained eigenvalue pb of the type: - K z y = \\lmbda <z, y>, forall y \\in V_h(\\Omega') - K z y = \\lmbda <z, y>, forall y \\in {inactive constraints} where \\Omega' \\subseteq \\Omega where {inactive constraints} is a proper subset """ self.comm = comm self.slepc_options = slepc_options self.V = u.function_space() self.u = u self.index_set = None if type(bcs) == list: self.bcs = bcs elif type(bcs) == dolfin.fem.dirichletbc.DirichletBC: self.bcs = [bcs] else: self.bcs = None if type(a_k) == ufl.form.Form: # a form to be assembled self.K = dolfin.as_backend_type(assemble(a_k)).mat() elif type(a_k) == petsc4py.PETSc.Mat: # an assembled petsc matrix self.K = a_k if a_m is not None and type(a_m) == ufl.form.Form: self.M = dolfin.as_backend_type(assemble(a_m)).mat() elif a_m is not None and type(a_m) == petsc4py.PETSc.Mat: self.M = a_m if self.bcs: self.index_set = self.get_interior_index_set(self.bcs, self.V) if restricted_dofs_is: self.index_set = restricted_dofs_is self.K, self.M = self.restrictOperator(self.index_set) self.projector = self.createProjector(self.index_set) if slepc_eigensolver: self.E = slepc_eigensolver else: self.E = self.eigensolver_setup(prefix=option_prefix) if a_m: self.E.setOperators(self.K, self.M) else: self.E.setOperators(self.K)
def __init__(self, mesh, Vh, t_init, t_final, t_1, dt, wind_velocity, gls_stab, Prior): self.mesh = mesh self.Vh = Vh self.t_init = t_init self.t_final = t_final self.t_1 = t_1 self.dt = dt self.sim_times = np.arange(self.t_init, self.t_final + .5 * self.dt, self.dt) u = dl.TrialFunction(Vh[STATE]) v = dl.TestFunction(Vh[STATE]) kappa = dl.Constant(.001) dt_expr = dl.Constant(self.dt) r_trial = u + dt_expr * (-dl.div(kappa * dl.nabla_grad(u)) + dl.inner(wind_velocity, dl.nabla_grad(u))) r_test = v + dt_expr * (-dl.div(kappa * dl.nabla_grad(v)) + dl.inner(wind_velocity, dl.nabla_grad(v))) h = dl.CellSize(mesh) vnorm = dl.sqrt(dl.inner(wind_velocity, wind_velocity)) if gls_stab: tau = dl.Min((h * h) / (dl.Constant(2.) * kappa), h / vnorm) else: tau = dl.Constant(0.) self.M = dl.assemble(dl.inner(u, v) * dl.dx) self.M_stab = dl.assemble(dl.inner(u, v + tau * r_test) * dl.dx) self.Mt_stab = dl.assemble(dl.inner(u + tau * r_trial, v) * dl.dx) Nvarf = (dl.inner(kappa * dl.nabla_grad(u), dl.nabla_grad(v)) + dl.inner(wind_velocity, dl.nabla_grad(u)) * v) * dl.dx Ntvarf = (dl.inner(kappa * dl.nabla_grad(v), dl.nabla_grad(u)) + dl.inner(wind_velocity, dl.nabla_grad(v)) * u) * dl.dx self.N = dl.assemble(Nvarf) self.Nt = dl.assemble(Ntvarf) stab = dl.assemble(tau * dl.inner(r_trial, r_test) * dl.dx) self.L = self.M + dt * self.N + stab self.Lt = self.M + dt * self.Nt + stab boundaries = dl.FacetFunction("size_t", mesh) boundaries.set_all(0) class InsideBoundary(dl.SubDomain): def inside(self, x, on_boundary): x_in = x[0] > dl.DOLFIN_EPS and x[0] < 1 - dl.DOLFIN_EPS y_in = x[1] > dl.DOLFIN_EPS and x[1] < 1 - dl.DOLFIN_EPS return on_boundary and x_in and y_in Gamma_M = InsideBoundary() Gamma_M.mark(boundaries, 1) ds_marked = dl.Measure("ds")[boundaries] self.Q = dl.assemble(self.dt * dl.inner(u, v) * ds_marked(1)) self.Prior = Prior self.solver = dl.PETScKrylovSolver("gmres", "ilu") self.solver.set_operator(self.L) self.solvert = dl.PETScKrylovSolver("gmres", "ilu") self.solvert.set_operator(self.Lt) self.ud = self.generate_vector(STATE) self.noise_variance = 0
# Commented out below is the option for creating a ParaView readable file to visualize the difference # between the solution of the two approaches over the surface of the cube. # The error values over the elememts of the mesh is expected to vary and cause error in the magnitude # of up to 3e-3. This observation is due to the difference in the calculation of the solution for the solid. # In addition to the constitutive law, the PoroelasticProblem applies the Lagrange multiplier # subjecting the constitutive law to the constraint evoked by the influence of the fluid mass divergence, # density of the fluid and in sum the difference of the fluid influence in each compartment # changing the determinante J. # This difference in calculation leads to the error observed. #diff = project(dU-u, dU.function_space()) #poro.write_file(f4, diff, 'du', t) domain_area += df.assemble(df.div(dU)*dx)*(1-phi) sum_fluid_mass += df.assemble(Mf*dx) sum_disp += df.assemble(dU[0]*ds(4)) [f1[i].close() for i in range(N)] f2.close() [f3[i].close() for i in range(N)] f4.close() # # The function 'write_config' inherited by the class 'ParamParser' of the module # param_parser is executed on the configuration files to be created. # params.write_config('../data/{}/{}.cfg'.format(data_dir, data_dir)) # # Finally, the result for the expected sum fluid mass, the error between the
def avg(u, dx): return dolfin.assemble(u * dx) / dolfin.assemble( dolfin.Constant(1.) * dx)
def block_assemble(lhs, rhs=None, bcs=None, symmetric=False, signs=None, symmetric_mod=None): """ Assembles block matrices, block vectors or block systems. Input can be arrays of variational forms or block matrices/vectors. Arguments: symmetric : Boundary conditions are applied so that symmetry of the system is preserved. If only the left hand side of the system is given, then a matrix represententing the rhs corrections is returned along with a symmetric matrix. symmetric_mod : Matrix describing symmetric corrections for assembly of the of the rhs of a variational system. signs : An array to specify the signs of diagonal blocks. The sign of the blocks are computed if the argument is not provided. """ error_msg = {'incompatibility' : 'A and b do not have compatible dimensions.', 'symm_mod error' : 'symmetric_mod argument only accepted when assembling a vector', 'not square' : 'A must be square for symmetric assembling', 'invalid bcs' : 'Expecting a list or list of lists of DirichletBC.', 'invalid signs' : 'signs should be a list of length n containing only 1 or -1', 'mpi and symm' : 'Symmetric application of BC not yet implemented in parallel'} # Check arguments from numpy import ndarray has_rhs = True if isinstance(rhs, ndarray) else rhs != None has_lhs = True if isinstance(rhs, ndarray) else rhs != None if symmetric: from dolfin import MPI, mpi_comm_world if MPI.size(mpi_comm_world()) > 1: raise NotImplementedError(error_msg['mpi and symm']) if has_lhs and has_rhs: A, b = map(block_tensor,[lhs,rhs]) n, m = A.blocks.shape if not ( isinstance(b,block_vec) and len(b.blocks) is m): raise TypeError(error_msg['incompatibility']) else: A, b = block_tensor(lhs), None if isinstance(A,block_vec): A, b = None, A n, m = 0, len(b.blocks) else: n,m = A.blocks.shape if A and symmetric and (m is not n): raise RuntimeError(error_msg['not square']) if symmetric_mod and ( A or not b ): raise RuntimeError(error_msg['symmetric_mod error']) # First assemble everything needing assembling. from dolfin import assemble assemble_if_form = lambda x: assemble(x, keep_diagonal=True) if _is_form(x) else x if A: A.blocks.flat[:] = map(assemble_if_form,A.blocks.flat) if b: #b.blocks.flat[:] = map(assemble_if_form, b.blocks.flat) b = block_vec(map(assemble_if_form, b.blocks.flat)) # If there are no boundary conditions then we are done. if bcs is None: if A: return [A,b] if b else A else: return b # check if arguments are forms, in which case bcs have to be split from ufl import Form if isinstance(lhs, Form): from splitting import split_bcs bcs = split_bcs(bcs, m) # Otherwise check that boundary conditions are valid. if not hasattr(bcs,'__iter__'): raise TypeError(error_msg['invalid bcs']) if len(bcs) is not m: raise TypeError(error_msg['invalid bcs']) from dolfin import DirichletBC for bc in bcs: if isinstance(bc,DirichletBC) or bc is None: pass else: if not hasattr(bc,'__iter__'): raise TypeError(error_msg['invalid bcs']) else: for bc_i in bc: if isinstance(bc_i,DirichletBC): pass else: raise TypeError(error_msg['invalid bcs']) bcs = [bc if hasattr(bc,'__iter__') else [bc] if bc else bc for bc in bcs] # Apply BCs if we are only assembling the righ hand side if not A: if symmetric_mod: b.allocate(symmetric_mod) for i in xrange(m): if bcs[i]: if isscalar(b[i]): b[i], val = create_vec_from(bcs[i][0]), b[i] b[i][:] = val for bc in bcs[i]: bc.apply(b[i]) if symmetric_mod: b.allocate(symmetric_mod) b -= symmetric_mod*b return b # If a signs argument is passed, check if it is valid. # Otherwise guess. if signs and symmetric: if ( hasattr(signs,'__iter__') and len(signs)==m ): for sign in signs: if sign not in (-1,1): raise TypeError(error_msg['invalid signs']) else: raise TypeError(error_msg['invalid signs']) elif symmetric: from numpy.random import random signs = [0]*m for i in xrange(m): if isscalar(A[i,i]): signs[i] = -1 if A[i,i] < 0 else 1 else: x = A[i,i].create_vec(dim=1) x.set_local(random(x.local_size())) signs[i] = -1 if x.inner(A[i,i]*x) < 0 else 1 # Now apply boundary conditions. if b: b.allocate(A) elif symmetric: # If we are preserving symmetry but don't have the rhs b, # then we need to store the symmetric corretions to b # as a matrix which we call A_mod b, A_mod = A.create_vec(), A.copy() for i in xrange(n): if bcs[i]: for bc in bcs[i]: # Apply BCs to the diagonal block. if isscalar(A[i,i]): A[i,i] = _new_square_matrix(bc,A[i,i]) if symmetric: A_mod[i,i] = A[i,i].copy() if symmetric: bc.zero_columns(A[i,i],b[i],signs[i]) bc.apply(A_mod[i,i]) elif b: bc.apply(A[i,i],b[i]) else: bc.apply(A[i,i]) # Zero out the rows corresponding to BC dofs. for j in range(i) + range(i+1,n): if A[i,j] is 0: continue assert not isscalar(A[i,j]) bc.zero(A[i,j]) # If we are not preserving symmetry then we are done at this point. # Otherwise, we need to zero out the columns as well if symmetric: for j in range(i) + range(i+1,n): if A[j,i] is 0: continue assert not isscalar(A[j,i]) bc.zero_columns(A[j,i],b[j]) bc.zero(A_mod[i,j]) result = [A] if symmetric: for i in range(n): for j in range(n): A_mod[i,j] -= A[i,j] result += [A_mod] if b: result += [b] return result[0] if len(result)==1 else result
def stress(mode, solver): return dolf.assemble( _stress(mode, solver) * solver.domain.ds(boundary5.surface_index))
def assemble_lhs(self): if self.tensor_lhs is None: self.tensor_lhs = dolfin.assemble(self.form_lhs) else: dolfin.assemble(self.form_lhs, tensor=self.tensor_lhs) return self.tensor_lhs
dolfin.File(os.path.join(results_outdir_functions, "stress_field.pvd")) << stress_field dolfin.File(os.path.join(results_outdir_functions, "maximal_compressive_stress_field.pvd")) << maximal_compressive_stress_field dolfin.File(os.path.join(results_outdir_functions, "fraction_compressive_stress_field.pvd")) << fraction_compressive_stress_field if __name__ == "__main__": if SAVE_RESULTS: save_functions() phasefield_fraction = dolfin.assemble(p*dolfin.dx) \ / dolfin.assemble(1*dolfin.dx(domain=mesh)) strain_energy = dolfin.assemble(W) m_arr = m.vector().get_local() u_arr = u.vector().get_local() m.vector()[:] = 1.0 equilibrium_solve() strain_energy_ref = dolfin.assemble(W) m.vector()[:] = m_arr u.vector()[:] = u_arr
def __init__(self, Vh): test = dl.TestFunction(Vh[STATE]) f = dl.Constant(1.0) self.f = dl.assemble(f * test * dl.dx)
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving the Germano Dynamic LES model applying Lagrangian Averaging. """ # Create function spaces CG1 = FunctionSpace(mesh, "CG", 1) p, q = TrialFunction(CG1), TestFunction(CG1) dim = mesh.geometry().dim() # Define delta and project delta**2 to CG1 delta = pow(CellVolume(mesh), 1. / dim) delta_CG1_sq = project(delta, CG1) delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2) delta_CG1_sq.vector().apply("insert") # Define nut_ Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) Cs = Function(CG1) nut_form = Cs**2 * delta**2 * magS # Create nut_ BCs ff = FacetFunction("size_t", mesh, 0) bcs_nut = [] for i, bc in enumerate(bcs['u0']): bc.apply(u_[0].vector()) # Need to initialize bc m = bc.markers() # Get facet indices of boundary ff.array()[m] = i + 1 bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i + 1)) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") # Create functions for holding the different velocities u_CG1 = as_vector([Function(CG1) for i in range(dim)]) u_filtered = as_vector([Function(CG1) for i in range(dim)]) dummy = Function(CG1) ll = LagrangeInterpolator() # Assemble required filter matrices and functions G_under = Function(CG1, assemble(TestFunction(CG1) * dx)) G_under.vector().set_local(1. / G_under.vector().array()) G_under.vector().apply("insert") G_matr = assemble(inner(p, q) * dx) # Set up functions for Lij and Mij Lij = [Function(CG1) for i in range(dim * dim)] Mij = [Function(CG1) for i in range(dim * dim)] # Check if case is 2D or 3D and set up uiuj product pairs and # Sij forms, assemble required matrices Sijcomps = [Function(CG1) for i in range(dim * dim)] Sijfcomps = [Function(CG1) for i in range(dim * dim)] # Assemble some required matrices for solving for rate of strain terms Sijmats = [assemble_matrix(p.dx(i) * q * dx) for i in range(dim)] if dim == 3: tensdim = 6 uiuj_pairs = ((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)) else: tensdim = 3 uiuj_pairs = ((0, 0), (0, 1), (1, 1)) # Set up Lagrange functions JLM = Function(CG1) JLM.vector()[:] += 1E-32 JMM = Function(CG1) JMM.vector()[:] += 1 return dict(Sij=Sij, nut_form=nut_form, nut_=nut_, delta=delta, bcs_nut=bcs_nut, delta_CG1_sq=delta_CG1_sq, CG1=CG1, Cs=Cs, u_CG1=u_CG1, u_filtered=u_filtered, ll=ll, Lij=Lij, Mij=Mij, Sijcomps=Sijcomps, Sijfcomps=Sijfcomps, Sijmats=Sijmats, JLM=JLM, JMM=JMM, dim=dim, tensdim=tensdim, G_matr=G_matr, G_under=G_under, dummy=dummy, uiuj_pairs=uiuj_pairs)
v, T_hat = df.TestFunctions(mixed_fs) residual_form = get_residual_form(displacements_function, v, density_function, temperature_function, T_hat, KAPPA, K, ALPHA) residual_form -= (df.dot(f_r, v) * dss(10) + df.dot(f_t, v) * dss(14) + \ q*T_hat*dss(5) + q_half*T_hat*dss(6) + q_quart*T_hat*dss(7)) print("get residual_form-------") # print('ssssssss',df.assemble(T_hat*df.dx).get_local()) pde_problem.add_state('mixed_states', mixed_function, residual_form, 'density') ''' 4. 3. Add outputs ''' # Add output-avg_density to the PDE problem: volume = df.assemble(df.Constant(1.) * df.dx(domain=mesh)) avg_density_form = density_function / (df.Constant( 1. * volume)) * df.dx(domain=mesh) pde_problem.add_scalar_output('avg_density', avg_density_form, 'density') print("Add output-avg_density-------") # Add output-compliance to the PDE problem: compliance_form = df.dot(f_r, displacements_function) * dss(10) +\ df.dot(f_t, displacements_function) * dss(14) pde_problem.add_scalar_output('compliance', compliance_form, 'mixed_states') print("Add output-compliance-------") compliance_form = df.dot(f_r, displacements_function) * dss(10) +\ df.dot(f_t, displacements_function) * dss(14) pde_problem.add_scalar_output('compliance', compliance_form, 'mixed_states')
def solve(self, J, grad, H, m): rtol = self.parameters["rel_tolerance"] atol = self.parameters["abs_tolerance"] gdm_tol = self.parameters["gdm_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_coarse_tol = self.parameters["cg_coarse_tolerance"] Jn = dl.assemble( J(m) ) gn = dl.assemble( grad(m) ) g0_norm = gn.norm("l2") gn_norm = g0_norm tol = max(g0_norm*rtol, atol) dm = dl.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:>7}".format( "It", "Energy", "||g||", "(g,du)", "alpha", "tol_cg", "cg_it") ) for self.it in range(max_iter): Hn = dl.assemble( H(m) ) Hn.init_vector(dm,1) solver = dl.PETScKrylovSolver("cg", "petsc_amg") solver.set_operator(Hn) solver.parameters["nonzero_initial_guess"] = False cg_tol = min(cg_coarse_tol, math.sqrt( gn_norm/g0_norm) ) solver.parameters["relative_tolerance"] = cg_tol lin_it = solver.solve(dm,-gn) self.total_cg_iter += lin_it dm_gn = dm.inner(gn) if(-dm_gn < gdm_tol): self.converged=True self.reason = 3 break m_backtrack = m.copy(deepcopy=True) alpha = 1. bk_converged = False #Backtrack for j in range(max_backtrack): m.assign(m_backtrack) m.vector().axpy(alpha, dm) Jnext = dl.assemble( J(m) ) if Jnext < Jn + alpha*c_armijo*dm_gn: Jn = Jnext bk_converged = True break alpha = alpha/2. if not bk_converged: self.reason = 2 break gn = dl.assemble( grad(m) ) gn_norm = gn.norm("l2") if prt_level > 0: print( "{0:3d} {1:15e} {2:15e} {3:15e} {4:15e} {5:15e} {6:7d}".format( self.it, Jn, gn_norm, dm_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", Jn)
print( f"Relative observation error: {obs_err/np.linalg.norm(obs_data)*100:.4f}%") p = dl.plot(z, vmax=vmax, vmin=vmin) plt.colorbar(p) plt.savefig("z_map.png", dpi=200) plt.cla() plt.clf() p = dl.plot(dl.exp(z)) plt.colorbar(p) plt.savefig("z_map_exp.png", dpi=200) # plt.cla() # plt.clf() # p = dl.plot(z_true, vmax=vmax, vmin=vmin) # plt.colorbar(p) # plt.savefig("z_true.png", dpi=200) reconst_err = dl.assemble(dl.inner(z - z_true, z - z_true) * dl.dx) z_true_norm = dl.assemble(dl.inner(z_true, z_true) * dl.dx) rel_r_err = np.sqrt(reconst_err / z_true_norm) print(f"Relative reconstruction error: {rel_r_err * 100:.4f}%") print(f"Reconstruction error: {reconst_err:.4f}") rel_err = 100 * np.abs(z_true.vector()[:] - z.vector()[:]) / np.sqrt(z_true_norm) z_err = dl.Function(V) z_err.vector().set_local(rel_err) np.save('rel_err', rel_err)
def ass_convmat_asmatquad(W=None, invindsw=None): """ assemble the convection matrix H, so that N(v)v = H[v.v] for the inner nodes. Notes ----- Implemented only for 2D problems """ mesh = W.mesh() deg = W.ufl_element().degree() fam = W.ufl_element().family() V = dolfin.FunctionSpace(mesh, fam, deg) # this is very specific for V being a 2D VectorFunctionSpace invindsv = invindsw[::2] / 2 v = dolfin.TrialFunction(V) vt = dolfin.TestFunction(V) def _pad_csrmats_wzerorows(smat, wheretoput='before'): """add zero rows before/after each row """ indpeter = smat.indptr auxindp = np.c_[indpeter, indpeter].flatten() if wheretoput == 'after': smat.indptr = auxindp[1:] else: smat.indptr = auxindp[:-1] smat._shape = (2 * smat.shape[0], smat.shape[1]) return smat def _shuff_mrg_csrmats(xm, ym): """shuffle merge csr mats [xxx],[yyy] -> [xyxyxy] """ xm.indices = 2 * xm.indices ym.indices = 2 * ym.indices + 1 xm._shape = (xm.shape[0], 2 * xm.shape[1]) ym._shape = (ym.shape[0], 2 * ym.shape[1]) return xm + ym nklist = [] for i in invindsv: # for i in range(V.dim()): # iterate for the columns # get the i-th basis function bi = dolfin.Function(V) bvec = np.zeros((V.dim(), )) bvec[i] = 1 bi.vector()[:] = bvec # assemble for the i-th basis function nxi = dolfin.assemble(v * bi.dx(0) * vt * dx) nyi = dolfin.assemble(v * bi.dx(1) * vt * dx) nxim = mat_dolfin2sparse(nxi) nxim.eliminate_zeros() nyim = mat_dolfin2sparse(nyi) nyim.eliminate_zeros() # resorting of the arrays and inserting zero columns nxyim = _shuff_mrg_csrmats(nxim, nyim) nxyim = nxyim[invindsv, :][:, invindsw] nyxxim = _pad_csrmats_wzerorows(nxyim.copy(), wheretoput='after') nyxyim = _pad_csrmats_wzerorows(nxyim.copy(), wheretoput='before') # tile the arrays in horizontal direction nklist.extend([nyxxim, nyxyim]) hmat = sps.hstack(nklist, format='csc') return hmat
def gradient(self, z_v): self.z.vector().set_local(z_v) self.solver._k.assign(self.z) self.grad, self.cost = self.solver_r.grad_reduced(self.z) self.grad = self.grad + dl.assemble(self.solver.grad_reg) return self.grad
u_1.assign(u_) converged = False while not converged: if parameters["anneal"]: tau.assign( anneal_func( t+dt.get(), parameters["tau"], parameters["tau_ramp"], parameters["t_ramp"])) # Compute energy u_.assign(u_1) Eout_0 = df.assemble(geo_map.form(E_0)) Eout_2 = df.assemble(geo_map.form(E_2)) E_before = Eout_0 + Eout_2 try: solver.solve() converged = True except: info_blue("Did not converge. Chopping timestep.") dt.chop() info_blue("New timestep is: dt = {}".format(dt.get())) Eout_0 = df.assemble(geo_map.form(E_0)) Eout_2 = df.assemble(geo_map.form(E_2)) E_after = Eout_0 + Eout_2 dE = E_after - E_before
editor.close() return mesh mesh = UnitSquareMesh(200, 200) # mesh = create_dolfin_mesh(*meshzoo.triangle(1500, corners=[[0, 0], [1, 0], [0, 1]])) V = FunctionSpace(mesh, "CG", 1) u = TrialFunction(V) v = TestFunction(V) n = FacetNormal(mesh) # A = assemble(dot(grad(u), grad(v)) * dx - dot(n, grad(u)) * v * ds) A = assemble(dot(grad(u), grad(v)) * dx - dot(n, grad(u)) * v * ds) M = assemble(u * v * dx) f = Expression("sin(pi * x[0]) * sin(pi * x[1])", element=V.ufl_element()) x = project(f, V) Ax = A * x.vector() Minv_Ax = Function(V).vector() solve(M, Minv_Ax, Ax) val = Ax.inner(Minv_Ax) print(val) # Exact value x = sympy.Symbol("x")
def __init__(self, Vh, dt, save, out_path, subdmn_path, mesh_tag, qoi_type): self.Vh = Vh self._param_dim = Vh[PARAMETER].dim() self.dt = dt self._out_path = out_path self._file = None self._qoi_type = qoi_type if save: self._file = [None] * 5 for i in range(5): names = [ "susceptible", "exposed", "infected", "recovered", "deceased" ] self._file[i] = dl.File(out_path + names[i] + '.pvd', "compressed") self.m = dl.Function(Vh[PARAMETER]) self.gamma = [None] * 5 self.sigma = None self.beta = [None] * 5 self.nu = [None] * 5 self.A = None self.help = dl.Function(Vh[STATE]) self.p = dl.TestFunction(self.Vh[STATE]) self.u_trial = dl.TrialFunction(self.Vh[STATE]) self.M = dl.assemble(self.u_trial * self.p * dl.dx) self.z = dl.assemble(dl.Constant(1.0) * self.p * dl.dx) self.u_0 = [dl.Function(self.Vh[STATE]) for i in range(5)] self.u_k = [dl.Function(self.Vh[STATE]) for i in range(5)] self.H = [None] * 5 self.b = [None] * 5 self.a = [None] * 5 self.L = [None] * 5 # load subdomains self.subdmn_path = subdmn_path if qoi_type == 'district': subdomain = dl.MeshFunction("size_t", self.Vh[STATE].mesh(), 2) dl.File(self.subdmn_path + 'subdomain_' + mesh_tag + '.xml.gz') >> subdomain dx_dist = dl.Measure('dx', domain=self.Vh[STATE].mesh(), subdomain_data=subdomain) # for integration over districts self.z_dist = [ dl.assemble(dl.Constant(1.0) * self.p * dx_dist(i)) for i in range(25) ] # read area factor (integration of unit function over district subdomain is # smaller than the district area) self.dist_area_factor = np.load(self.subdmn_path + 'area_factor_' + mesh_tag + '.npy') else: self.z_dist = [] self.dist_area_factor = []
# As long as the for loop continues, the theoretical solution and the currently # approximated solution of the sum of the fluid mass are printed to the screen. # # Upon exiting the for loop, the XDMFFiles created are closed by calling the # 'close()' function. for Mf, Uf, p, Us, t in pprob.solve(): dU, L = Us.split(True) [poro.write_file(f1[i], Uf[i], 'uf{}'.format(i), t) for i in range(N)] poro.write_file(f2, Mf, 'mf', t) [poro.write_file(f3[i], p[i], 'p{}'.format(i), t) for i in range(N)] poro.write_file(f4, dU, 'du', t) domain_area += df.assemble(df.div(dU) * dx) * (1 - phi) sum_fluid_mass += df.assemble(Mf * dx) theor_fluid_mass += qi * rho * dt theor_sol = theor_fluid_mass * domain_area sum_disp += df.assemble(dU[0] * ds(4)) avg_error.append( np.sqrt(((df.assemble(Mf * dx) - theor_sol) / theor_sol)**2)) print(theor_sol, df.assemble(Mf * dx)) [f1[i].close() for i in range(N)] f2.close() [f3[i].close() for i in range(N)] f4.close() # # The final error is calculated by normalizing the avg_error by the number of elements # in the list of errors.