def assemble_RHS(self, t=None): """Assemble right hand side of the FBVP """ print('Assembling RHS') self.forcing_terms = np.empty([self.control_set_size, self.dim]) for i, alpha in enumerate(self.control_set): rhs = self.parameters.RHSt(alpha) if t is not None: rhs.t = t # Initialise forcing term F = np.array(assemble(rhs * self.u * dx)[:]) for j in self.parameters.regions['RobinTime']: rhs = self.parameters.RHS_bound[j](alpha) if t is not None: rhs.t = t bc = DirichletBC(self.V, rhs, self.boundary_markers, j) vals = bc.get_boundary_values() F[list(vals.keys())] = list(vals.values()) for j in self.parameters.regions['Robin']: rhs = self.parameters.RHS_bound[j](alpha) if t is not None: rhs.t = t bc = DirichletBC(self.V, rhs, self.boundary_markers, j) vals = bc.get_boundary_values() F[list(vals.keys())] = list(vals.values()) self.forcing_terms[i] = self.timestep_size * F
def solve(mesh, Eps, degree): V = FunctionSpace(mesh, "CG", degree) u = TrialFunction(V) v = TestFunction(V) n = FacetNormal(mesh) gdim = mesh.geometry().dim() A = [ _assemble_eigen( Constant(Eps[i, j]) * (u.dx(i) * v.dx(j) * dx - u.dx(i) * n[j] * v * ds) ).sparray() for j in range(gdim) for i in range(gdim) ] assert_equality = False if assert_equality: # The sum of the `A`s is exactly that: n = FacetNormal(V.mesh()) AA = _assemble_eigen( +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds ).sparray() diff = AA - sum(A) assert numpy.all(abs(diff.data) < 1.0e-14) # # ATAsum = sum(a.T.dot(a) for a in A) # diff = AA.T.dot(AA) - ATAsum # # import betterspy # # betterspy.show(ATAsum) # # betterspy.show(AA.T.dot(AA)) # # betterspy.show(ATAsum - AA.T.dot(AA)) # print(diff.data) # assert numpy.all(abs(diff.data) < 1.0e-14) tol = 1.0e-10 def lower(x, on_boundary): return on_boundary and x[1] < -1.0 + tol def upper(x, on_boundary): return on_boundary and x[1] > 1.0 - tol def left(x, on_boundary): return on_boundary and abs(x[0] + 1.0) < tol def right(x, on_boundary): return on_boundary and abs(x[0] - 1.0) < tol def upper_left(x, on_boundary): return on_boundary and x[1] > +1.0 - tol and x[0] < -0.8 def lower_right(x, on_boundary): return on_boundary and x[1] < -1.0 + tol and x[0] > 0.8 bcs = [ # DirichletBC(V, Constant(0.0), lower_right), # DirichletBC(V, Constant(0.0), upper_left), DirichletBC(V, Constant(0.0), lower), DirichletBC(V, Constant(0.0), upper), # DirichletBC(V, Constant(0.0), upper_left, method='pointwise'), # DirichletBC(V, Constant(0.0), lower_left, method='pointwise'), # DirichletBC(V, Constant(0.0), lower_right, method='pointwise'), ] M = _assemble_eigen(u * v * dx).sparray() ATMinvAsum = sum( numpy.dot(a.toarray().T, numpy.linalg.solve(M.toarray(), a.toarray())) for a in A ) AA2 = _assemble_eigen( +dot(dot(as_tensor(Eps), grad(u)), grad(v)) * dx - dot(dot(as_tensor(Eps), grad(u)), n) * v * ds, # bcs=[DirichletBC(V, Constant(0.0), 'on_boundary')] # bcs=bcs # bcs=[ # DirichletBC(V, Constant(0.0), lower), # DirichletBC(V, Constant(0.0), right), # ] ).sparray() ATA2 = numpy.dot(AA2.toarray().T, numpy.linalg.solve(M.toarray(), AA2.toarray())) # Find combination of Dirichlet points: if False: # min_val = 1.0 max_val = 0.0 # min_combi = [] max_combi = [] is_updated = False it = 0 # get boundary indices d = DirichletBC(V, Constant(0.0), "on_boundary") boundary_idx = numpy.sort(list(d.get_boundary_values().keys())) # boundary_idx = numpy.arange(V.dim()) # print(boundary_idx) # pick some at random # idx = numpy.sort(numpy.random.choice(boundary_idx, size=3, replace=False)) for idx in itertools.combinations(boundary_idx, 3): it += 1 print() print(it) # Replace the rows corresponding to test functions living in one cell # (deliberately chosen as 0) by Dirichlet rows. AA3 = AA2.tolil() for k in idx: AA3[k] = 0 AA3[k, k] = 1 n = AA3.shape[0] AA3 = AA3.tocsr() ATA2 = numpy.dot( AA3.toarray().T, numpy.linalg.solve(M.toarray(), AA3.toarray()) ) vals = numpy.sort(numpy.linalg.eigvalsh(ATA2)) if vals[0] < 0.0: continue # op = sparse.linalg.LinearOperator( # (n, n), # matvec=lambda x: _spsolve(AA3, M.dot(_spsolve(AA3.T.tocsr(), x))) # ) # vals, _ = scipy.sparse.linalg.eigsh(op, k=3, which='LM') # vals = numpy.sort(1/vals[::-1]) # print(vals) print(idx) # if min_val > vals[0]: # min_val = vals[0] # min_combi = idx # is_updated = True if max_val < vals[0]: max_val = vals[0] max_combi = idx is_updated = True if is_updated: # vals, _ = scipy.sparse.linalg.eigsh(op, k=10, which='LM') # vals = numpy.sort(1/vals[::-1]) # print(vals) is_updated = False # print(min_val, min_combi) print(max_val, max_combi) # plt.plot(dofs_x[:, 0], dofs_x[:, 1], 'x') meshzoo.plot2d(mesh.coordinates(), mesh.cells()) dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim)) # plt.plot(dofs_x[min_combi, 0], dofs_x[min_combi, 1], 'or') plt.plot(dofs_x[max_combi, 0], dofs_x[max_combi, 1], "ob") plt.gca().set_aspect("equal") plt.title(f"smallest eigenvalue: {max_val}") plt.show() # # if True: # if abs(vals[0]) < 1.0e-8: # gdim = mesh.geometry().dim() # # plt.plot(dofs_x[:, 0], dofs_x[:, 1], 'x') # X = mesh.coordinates() # meshzoo.plot2d(mesh.coordinates(), mesh.cells()) # dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim)) # plt.plot(dofs_x[idx, 0], dofs_x[idx, 1], 'or') # plt.gca().set_aspect('equal') # plt.show() meshzoo.plot2d(mesh.coordinates(), mesh.cells()) dofs_x = V.tabulate_dof_coordinates().reshape((-1, gdim)) # plt.plot(dofs_x[min_combi, 0], dofs_x[min_combi, 1], 'or') plt.plot(dofs_x[max_combi, 0], dofs_x[max_combi, 1], "ob") plt.gca().set_aspect("equal") plt.title(f"final smallest eigenvalue: {max_val}") plt.show() exit(1) # Eigenvalues of the operators if True: # import betterspy # betterspy.show(sum(A), colormap="viridis") AA = _assemble_eigen( +dot(grad(u), grad(v)) * dx - dot(grad(u), n) * v * ds ).sparray() eigvals, eigvecs = scipy.sparse.linalg.eigs(AA, k=5, which="SM") assert numpy.all(numpy.abs(eigvals.imag) < 1.0e-12) eigvals = eigvals.real assert numpy.all(numpy.abs(eigvecs.imag) < 1.0e-12) eigvecs = eigvecs.real i = numpy.argsort(eigvals) print(eigvals[i]) import meshio for k in range(3): meshio.write_points_cells( f"eigval{k}.vtk", points, {"triangle": cells}, point_data={"ev": eigvecs[:, i][:, k]}, ) exit(1) # import betterspy # betterspy.show(AA, colormap="viridis") # print(numpy.sort(numpy.linalg.eigvals(AA.todense()))) exit(1) Asum = sum(A).todense() AsumT_Minv_Asum = numpy.dot(Asum.T, numpy.linalg.solve(M.toarray(), Asum)) # print(numpy.sort(numpy.linalg.eigvalsh(Asum))) print(numpy.sort(numpy.linalg.eigvalsh(AsumT_Minv_Asum))) exit(1) # eigvals, eigvecs = numpy.linalg.eigh(Asum) # i = numpy.argsort(eigvals) # print(eigvals[i]) # exit(1) # print(eigvals[:20]) # eigvals[eigvals < 1.0e-15] = 1.0e-15 # # eigvals = numpy.sort(numpy.linalg.eigvalsh(sum(A).todense())) # print(eigvals[:20]) # plt.semilogy(eigvals, ".", label="Asum") # plt.legend() # plt.grid() # plt.show() # exit(1) ATMinvAsum_eigs = numpy.sort(numpy.linalg.eigvalsh(ATMinvAsum)) print(ATMinvAsum_eigs[:20]) ATMinvAsum_eigs[ATMinvAsum_eigs < 0.0] = 1.0e-12 # ATA2_eigs = numpy.sort(numpy.linalg.eigvalsh(ATA2)) # print(ATA2_eigs[:20]) plt.semilogy(ATMinvAsum_eigs, ".", label="ATMinvAsum") # plt.semilogy(ATA2_eigs, ".", label="ATA2") plt.legend() plt.grid() plt.show() # # Preconditioned eigenvalues # # IATA_eigs = numpy.sort(scipy.linalg.eigvalsh(ATMinvAsum, ATA2)) # # plt.semilogy(IATA_eigs, ".", label="precond eigenvalues") # # plt.legend() # # plt.show() exit(1) # # Test with A only # numpy.random.seed(123) # b = numpy.random.rand(sum(a.shape[0] for a in A)) # MTM = M.T.dot(M) # MTb = M.T.dot(b) # sol = _gmres( # MTM, # # TODO linear operator # # lambda x: M.T.dot(M.dot(x)), # MTb, # M=prec # ) # plt.semilogy(sol.resnorms) # plt.show() # exit(1) n = AA2.shape[0] # define the operator def matvec(x): # M^{-1} can be computed in O(n) with CG + diagonal preconditioning # or algebraic multigrid. # return sum([a.T.dot(a.dot(x)) for a in A]) return numpy.sum([a.T.dot(_spsolve(M, a.dot(x))) for a in A], axis=0) op = sparse.linalg.LinearOperator((n, n), matvec=matvec) # pick a random solution and a consistent rhs x = numpy.random.rand(n) b = op.dot(x) linear_system = krypy.linsys.LinearSystem(op, b) print("unpreconditioned solve...") t = time.time() out = krypy.linsys.Gmres(linear_system, tol=1.0e-12, explicit_residual=True) out.xk = out.xk.reshape(b.shape) print("done.") print(" res: {}".format(out.resnorms[-1])) print( " unprec res: {}".format( numpy.linalg.norm(b - op.dot(out.xk)) / numpy.linalg.norm(b) ) ) # The error isn't useful here; only with the nullspace removed # print(' error: {}'.format(numpy.linalg.norm(out.xk - x))) print(" its: {}".format(len(out.resnorms))) print(" duration: {}s".format(time.time() - t)) # preconditioned solver ml = pyamg.smoothed_aggregation_solver(AA2) # res = [] # b = numpy.random.rand(AA2.shape[0]) # x0 = numpy.zeros(AA2.shape[1]) # x = ml.solve(b, x0, residuals=res, tol=1.0e-12) # print(res) # plt.semilogy(res) # plt.show() mlT = pyamg.smoothed_aggregation_solver(AA2.T.tocsr()) # res = [] # b = numpy.random.rand(AA2.shape[0]) # x0 = numpy.zeros(AA2.shape[1]) # x = mlT.solve(b, x0, residuals=res, tol=1.0e-12) # print(res) def prec_matvec(b): x0 = numpy.zeros(n) b1 = mlT.solve(b, x0, tol=1.0e-12) b2 = M.dot(b1) x = ml.solve(b2, x0, tol=1.0e-12) return x prec = LinearOperator((n, n), matvec=prec_matvec) # TODO assert this in a test # x = prec_matvec(b) # print(b - AA2.T.dot(AA2.dot(x))) linear_system = krypy.linsys.LinearSystem(op, b, Ml=prec) print() print("preconditioned solve...") t = time.time() try: out_prec = krypy.linsys.Gmres( linear_system, tol=1.0e-14, maxiter=1000, explicit_residual=True ) except krypy.utils.ConvergenceError: print("prec not converged!") pass out_prec.xk = out_prec.xk.reshape(b.shape) print("done.") print(" res: {}".format(out_prec.resnorms[-1])) print( " unprec res: {}".format( numpy.linalg.norm(b - op.dot(out_prec.xk)) / numpy.linalg.norm(b) ) ) print(" its: {}".format(len(out_prec.resnorms))) print(" duration: {}s".format(time.time() - t)) plt.semilogy(out.resnorms, label="original") plt.semilogy(out_prec.resnorms, label="preconditioned") plt.legend() plt.show() return out.xk
def solverBHWreduced(P, opt): ''' Function to solve the second-order pde in nonvariational formulation using gmres ''' if P.hasDrift: raise ValueError('Method currently does not support non-zero drift terms.') if P.isTimeDependant: raise ValueError('Method currently does not support parabolic problems.') if P.hasPotential: raise ValueError('Method currently does not support non-zero potential terms.') gamma = P.normalizeSystem(opt) # Extract local space of tensor space W_h W_H_loc = P.mixedSpace.sub(1).extract_sub_space(np.array([0])).collapse() trial_u = TrialFunction(P.V) test_u = TestFunction(P.V) trial_p = TrialFunction(W_H_loc) test_p = TestFunction(W_H_loc) # Get number of dofs in V N = P.V.dim() NW = W_H_loc.dim() # Get indices of inner and boundary nodes # Calling DirichletBC with actual P.g calls project which is expensive bc_V = DirichletBC(P.V, Constant(1), 'on_boundary') idx_bnd = list(bc_V.get_boundary_values().keys()) N_bnd = len(idx_bnd) N_in = N - N_bnd # Get indices of inner nodes idx_inner = np.setdiff1d(range(N), idx_bnd) def _i2a(S): return S[:, idx_inner] def _i2i(S): return S[idx_inner, :][:, idx_inner] def _b2a(S): return S[:, idx_bnd] def _b2i(S): return S[idx_inner, :][:, idx_bnd] # Assemble mass matrix and store LU decomposition M_W = spmat(assemble(trial_p * test_p * dx)) # spy(M_W) if opt['time_check']: t1 = time() # M_LU = la.splu(M_W) M_LU = cgMat(M_W) if opt['time_check']: print("Compute LU decomposition of M_W ... %.2fs" % (time() - t1)) sys.stdout.flush() # Check for constant zero entries in diffusion matrix # The diagonal entries are set up everytime nzdiags = [(i, i) for i in range(P.dim())] # The off-diagonal entries nzs = [] Asym = True for (i, j) in itertools.product(range(P.dim()), range(P.dim())): if i == j: nzs.append((i, j)) else: is_zero = checkForZero(P.a[i, j]) if not is_zero: Asym = False print('Use value ({},{})'.format(i, j)) nzs.append((i, j)) else: print('Ignore value ({},{})'.format(i, j)) def emptyMat(d=P.dim()): return [[-1e15] * d for i in range(d)] # return [[0] * d for i in range(d)] # Assemble weighted mass matrices B = emptyMat() for (i, j) in nzs: # ipdb.set_trace() this_form = gamma * P.a[i, j] * trial_p * test_p * dx B[i][j] = spmat(assemble(this_form)) # Init array for partial stiffness matrices C = emptyMat() # Set up the form for partial stiffness matrices def C_form(i, j): this_form = -trial_u.dx(i) * test_p.dx(j) * \ dx + trial_u.dx(i) * test_p * P.nE[j] * ds if opt["HessianSpace"] == 'DG': this_form += avg(trial_u.dx(i)) \ * (test_p('+') * P.nE[j]('+') + test_p('-') * P.nE[j]('-')) * dS return this_form # Ensure the diagonal is set up, necessary for the FE Laplacian for i in range(P.dim()): C[i][i] = spmat(assemble(C_form(i, i))) # Assemble the partial stiffness matrices for off-diagonal entries # only if a_i,j is non-zero for i, j in nzs: if i != j: C[i][j] = spmat(assemble(C_form(i, j))) C_lapl = sum([C[i][j] for i, j in nzdiags]) # Set up the form for stabilization term if opt["stabilizationFlag"] > 0: this_form = 0 # First stabilization term if opt["stabilityConstant1"] > 0: this_form += opt["stabilityConstant1"] * avg(P.hE)**(-1) * \ inner(vj(grad(trial_u), P.nE), vj(grad(test_u), P.nE)) * dS # Second stabilization term if opt["stabilityConstant2"] > 0: this_form += opt["stabilityConstant2"] * avg(P.hE)**(+1) * \ inner(mj(grad(grad(trial_u)), P.nE), mj(grad(grad(test_u)), P.nE)) * dS # Assemble stabilization term S = spmat(assemble(this_form)) else: # If no stabilization is used, S is zero S = sp.csc_matrix((N, N)) # Set up matrix-vector product for inner nodes def S_II_times_u(x): Dv = [B[i][j] * M_LU.solve(_i2a(C[i][j]) * x) for i, j in nzs] w = M_LU.solve(sum(Dv)) return (_i2a(C_lapl)).transpose() * w + _i2i(S) * x # Set up matrix-vector product for boundary nodes def S_IB_times_u(x): Dv = [B[i][j] * M_LU.solve(_b2a(C[i][j]) * x) for i, j in nzs] w = M_LU.solve(sum(Dv)) return (_i2a(C_lapl)).transpose() * w + _b2i(S) * x # Assemble f_W f_W = assemble(gamma * P.f * test_p * dx) M_in = la.LinearOperator((N_in, N_in), matvec=lambda x: S_II_times_u(x)) M_bnd = la.LinearOperator((N_in, N_bnd), matvec=lambda x: S_IB_times_u(x)) # Set up right-hand side try: print('Project boundary data with LU') G = project(P.g, P.V, solver_type="lu") except RuntimeError: print('Out of memory error: Switch to projection with CG') G = project(P.g, P.V, solver_type="cg") # Compute right-hand side rhs = (_i2a(C_lapl)).transpose() * M_LU.solve(f_W.get_local()) Gvec = G.vector() g_bc = Gvec.get_local().take(idx_bnd) rhs -= M_bnd * g_bc M_W_DiagInv = sp.spdiags(1. / M_W.diagonal(), np.array([0]), NW, NW, format='csc') D = sum([sp.spdiags(B[i][j].diagonal(), np.array([0]), NW, NW, format='csc') * M_W_DiagInv * _i2a(C[i][j]) for i, j in nzs]) Prec = (_i2a(C_lapl)).transpose().tocsc() * M_W_DiagInv * D + _i2i(S) if opt['time_check']: t1 = time() # Determine approximate size of LU decomposition in GB LU_size = NW**2 / (1024.**3) MEM_size = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024.**3) if LU_size / MEM_size > 0.8: if Asym: print('Use CG for preconditioning') Prec_LU = cgMat(Prec) else: print('Use GMRES for preconditioning') Prec_LU = gmresMat(Prec) else: try: print('Use LU for preconditioning') Prec_LU = la.splu(Prec) except MemoryError: if Asym: print('Use CG for preconditioning') Prec_LU = cgMat(Prec) else: print('Use GMRES for preconditioning') Prec_LU = gmresMat(Prec) PrecLinOp = la.LinearOperator( (N_in, N_in), matvec=lambda x: Prec_LU.solve(x)) # import ipdb # ipdb.set_trace() # gmres_mode = 1 # LU decomposition of Prec # # gmres_mode = 3 # incomplete LU decomposition of Prec # # gmres_mode = 4 # aslinearop # # Findings during experiments # # - LU factorization of prec is fast, high memory demand # # - Using only the diag of prec is not suitable # # - Solve routine from scipy is slow # # 1st variant: determine LU factorization of preconditioner # if gmres_mode == 1: # Prec_LU = la.splu(Prec) # PrecLinOp = la.LinearOperator( # (N_in, N_in), matvec=lambda x: Prec_LU.solve(x)) # # 3rd variant: determine incomplete LU factorization of preconditioner # if gmres_mode == 3: # if P.solDofs(opt) < MEM_THRESHOLD: # fill_factor = 20 # fill_factor = 30 # print('Use incomplete LU with fill factor {} for preconditioning'.format(fill_factor)) # Prec_LU = la.spilu(Prec, # fill_factor=fill_factor, # drop_tol=1e-4) # else: # print('Use gmres for preconditioning') # Prec_LU = gmresMat(Prec, tol=1e-8) # # print('Use cg for preconditioning') # # Prec_LU = cgMat(Prec) # PrecLinOp = la.LinearOperator( # (N_in, N_in), matvec=lambda x: Prec_LU.solve(x)) # if gmres_mode == 4: # if P.solDofs(opt) < MEM_THRESHOLD: # Prec_LU = la.splu(Prec) # else: # Prec_LU = gmresMat(Prec) # PrecLinOp = la.LinearOperator( # (N_in, N_in), matvec=lambda x: Prec_LU.solve(x)) if opt['time_check']: t2 = time() print("Prepare GMRES (e.g. LU decomp of Prec) ... %.2fs" % (t2 - t1)) sys.stdout.flush() do_savemat = 0 if do_savemat: from scipy.io import savemat savemat('M_{}.mat'.format(P.meshLevel), mdict={'Prec': Prec, 'B': B, 'C': C, 'S': S, 'M': M_W, 'f': f_W.get_local(), 'g': Gvec.get_local(), 'idx_inner': idx_inner, 'idx_bnd': idx_bnd, }) if P.meshLevel == 1 or not opt["gmresWarmStart"]: x0 = np.zeros(N_in) else: tmp = interpolate(P.uold, P.V) x0 = tmp.vector().get_local()[idx_inner] # Initialize counter for GMRES counter = gmres_counter(disp=True) # System solve (x, gmres_flag) = la.gmres(A=M_in, b=rhs, M=PrecLinOp, x0=x0, maxiter=2000, tol=opt["gmresTolRes"], atol=opt["gmresTolRes"], restart=20, callback=counter) if opt['time_check']: print("Time for GMRES ... %.2fs" % (time() - t2)) sys.stdout.flush() print('GMRES output flag: {}'.format(gmres_flag)) N_iter = counter.niter u_loc = Function(P.V) u_loc.vector()[idx_bnd] = g_bc u_loc.vector()[idx_inner] = x # Set solution to problem structure assign(P.u, u_loc) # Compute FE Hessians # import ipdb # ipdb.set_trace() for (i, j) in itertools.product(range(P.dim()), range(P.dim())): if (i, j) in nzs: Hij = Function(P.W_H.sub(i*P.dim() + j).collapse()) hij = M_LU.solve(C[i][j] * u_loc.vector()) Hij.vector()[:] = hij assign(P.H.sub(i*P.dim() + j), Hij) return N_iter
def __init__(self, mesh_name, parameters, alpha_range=None): # LOAD MESH AND PARAMETERS self.parameters = parameters self.mesh_name = mesh_name if not alpha_range: self.alpha_range = parameters.alpha_range else: self.alpha_range = alpha_range mesh_path = self.parameters.get_mesh_path() self.mesh = Mesh() with XDMFFile(mesh_path) as f: f.read(self.mesh) print(f'Mesh size= {self.mesh.hmax()}') # dimension of approximation space self.dim = len(self.mesh.coordinates()) print(f'Dimension of solution space is {self.dim}') self.V = FunctionSpace(self.mesh, 'CG', 1) # CG = P1 self.coords = self.mesh.coordinates()[dof_to_vertex_map(self.V)] self.T = self.parameters.T # final time self.w = TrialFunction(self.V) self.u = TestFunction(self.V) ####################################################################### # CONTROL SET CREATION self.control_set = np.linspace(self.alpha_range[0], self.alpha_range[1], self.parameters.control_set_size) self.control_set_size = len(self.control_set) print(f'Discretized control set has size {self.control_set_size}') ####################################################################### # BOUNDARY CONDITIONS parameters.set_boundary_conditions(self.mesh) self.boundary_markers = MeshFunction('size_t', self.mesh, 1) self.boundary_markers.set_all(4) # pylint: disable=no-member for i, omega in self.parameters.omegas.items(): omega.mark(self.boundary_markers, i) self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundary_markers) self.dirichlet_bcs = [ DirichletBC(self.V, parameters.RHS_bound[j], self.boundary_markers, j) for j in self.parameters.regions["Dirichlet"] ] # Get indices of dirichlet and robin dofs self.dirichlet_nodes_list = set() self.dirichlet_nodes_dict = {} for j in self.parameters.regions["Dirichlet"]: bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j) self.dirichlet_nodes_list |= set(bc.get_boundary_values().keys()) self.dirichlet_nodes_dict[j] = list( bc.get_boundary_values().keys()) self.robin_nodes_list = set() self.robin_nodes_dict = {} for j in self.parameters.regions["Robin"]: bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j) self.robin_nodes_list |= set(bc.get_boundary_values().keys()) self.robin_nodes_dict[j] = list(bc.get_boundary_values().keys()) bc = DirichletBC(self.V, Constant(0), 'on_boundary') self.boundary_nodes_list = bc.get_boundary_values().keys() self.robint_nodes_list = set() self.robint_nodes_dict = {} for j in self.parameters.regions["RobinTime"]: bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j) self.robint_nodes_list |= set(bc.get_boundary_values().keys()) self.robint_nodes_dict[j] = list(bc.get_boundary_values().keys()) ####################################################################### # ASSEMBLY time_start = time.process_time() self.assemble_diagonal_matrix() # auxilliary generic diagonal matrix # used for vector*matrix multiplication of dolfin matrices self.assemble_lumpedmm() # lumped mass matrix # which serves the role of identity operator self.assemble_laplacian() # discrete laplacian self.ad_data_path = f'out/{self.parameters.experiment}' Path(self.ad_data_path).mkdir(parents=True, exist_ok=True) self.timesteps = self.parameters.get_number_of_timesteps() self.assemble_HJBe() # assembly of explicit operators self.assemble_HJBi() # assembly of implicit operators self.assemble_RHS() # assembly of forcing term print('Final time assembly complete') print(f'Assembly took {time.process_time() - time_start} seconds') print('===========================================================')