V = dolfin.VectorFunctionSpace(mesh, 'CG', FINITE_ELEMENT_DEGREE) # Displacement field u = Function(V) ### Dirichlet boundary conditions bcs = [] Vx, Vy, Vz = V.split() zero = Constant(0) zeros = Constant((0, 0, 0)) bcs.append(DirichletBC(Vx, zero, boundary_markers, id_subdomain_fix)) bcs.append(DirichletBC(Vx, uxD_msr, boundary_markers, id_subdomain_msr)) bcs.append(DirichletBC(V, zeros, fixed_vertex_000, "pointwise")) bcs.append(DirichletBC(Vz, zero, fixed_vertex_010, "pointwise")) ### Define hyperelastic material model material_parameters = {'E': Constant(1.0), 'nu': Constant(0.0)} E, nu = material_parameters.values() d = len(u) # Displacement dimension I = dolfin.Identity(d) F = dolfin.variable(I + dolfin.grad(u))
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 run_with_params(Tb, mu_value, k_s, path): run_time_init = clock() mesh = BoxMesh(Point(0.0, 0.0, 0.0), Point(mesh_width, mesh_width, mesh_height), nx, ny, nz) pbc = PeriodicBoundary() WE = VectorElement('CG', mesh.ufl_cell(), 2) SE = FiniteElement('CG', mesh.ufl_cell(), 1) WSSS = FunctionSpace(mesh, MixedElement(WE, SE, SE, SE), constrained_domain=pbc) # W = FunctionSpace(mesh, WE, constrained_domain=pbc) # S = FunctionSpace(mesh, SE, constrained_domain=pbc) W = WSSS.sub(0).collapse() S = WSSS.sub(1).collapse() temperature_vals = [27.0 + 273, Tb + 273, 1300.0 + 273, 1305.0 + 273] temp_prof = TemperatureProfile(temperature_vals, element=S.ufl_element()) mu_a = mu_value # this was taken from the Blankenbach paper, can change Ep = b / temp_prof.delta mu_bot = exp(-Ep * (temp_prof.bottom * temp_prof.delta - 1573.0) + cc) * mu_a # TODO: verify exponentiation Ra = rho_0 * alpha * g * temp_prof.delta * h**3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * temp_prof.delta * h**2 / mu_a tau = h / w0 p0 = mu_a * w0 / h log(mu_a, mu_bot, Ra, w0, p0) slip_vx = 1.6E-09 / w0 # Non-dimensional slip_velocity = Constant((slip_vx, 0.0, 0.0)) zero_slip = Constant((0.0, 0.0, 0.0)) time_step = 3.0E11 / tau * 2 dt = Constant(time_step) t_end = 3.0E15 / tau / 5.0 # Non-dimensional times u = Function(WSSS) # Instead of TrialFunctions, we use split(u) for our non-linear problem v, p, T, Tf = split(u) v_t, p_t, T_t, Tf_t = TestFunctions(WSSS) T0 = interpolate(temp_prof, S) mu_exp = Expression( 'exp(-Ep * (T_val * dTemp - 1573.0) + cc * x[2] / mesh_height)', Ep=Ep, dTemp=temp_prof.delta, cc=cc, mesh_height=mesh_height, T_val=T0, element=S.ufl_element()) Tf0 = interpolate(temp_prof, S) mu = Function(S) v0 = Function(W) v_theta = (1.0 - theta) * v0 + theta * v T_theta = (1.0 - theta) * T0 + theta * T Tf_theta = (1.0 - theta) * Tf0 + theta * Tf # TODO: Verify forms r_v = (inner(sym(grad(v_t)), 2.0 * mu * sym(grad(v))) - div(v_t) * p - T * v_t[2]) * dx r_p = p_t * div(v) * dx heat_transfer = Constant(k_s) * (Tf_theta - T_theta) * dt r_T = ( T_t * ((T - T0) + dt * inner(v_theta, grad(T_theta))) # TODO: Inner vs dot + (dt / Ra) * inner(grad(T_t), grad(T_theta)) - T_t * heat_transfer) * dx v_melt = Function(W) z_hat = Constant((0.0, 0.0, 1.0)) # TODO: inner -> dot, take out Tf_t r_Tf = (Tf_t * ((Tf - Tf0) + dt * inner(v_melt, grad(Tf_theta))) + Tf_t * heat_transfer) * dx r = r_v + r_p + r_T + r_Tf bcv0 = DirichletBC(WSSS.sub(0), zero_slip, top) bcv1 = DirichletBC(WSSS.sub(0), slip_velocity, bottom) bcv2 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), back) bcv3 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), front) bcp0 = DirichletBC(WSSS.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(WSSS.sub(2), Constant(temp_prof.surface), top) bct1 = DirichletBC(WSSS.sub(2), Constant(temp_prof.bottom), bottom) bctf1 = DirichletBC(WSSS.sub(3), Constant(temp_prof.bottom), bottom) bcs = [bcv0, bcv1, bcv2, bcv3, bcp0, bct0, bct1, bctf1] t = 0 count = 0 files = DefaultDictByKey(partial(create_xdmf, path)) while t < t_end: mu.interpolate(mu_exp) rhosolid = rho_0 * (1.0 - alpha * (T0 * temp_prof.delta - 1573.0)) deltarho = rhosolid - rho_melt # TODO: project (accuracy) vs interpolate assign( v_melt, project( v0 - darcy * (grad(p) * p0 / h - deltarho * z_hat * g) / w0, W)) # TODO: Written out one step later? # v_melt.assign(v0 - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0) # TODO: use nP after to avoid projection? solve(r == 0, u, bcs) nV, nP, nT, nTf = u.split() # TODO: write with Tf, ... etc if count % output_every == 0: time_left(count, t_end / time_step, run_time_init) # TODO: timestep vs dt # TODO: Make sure all writes are to the same function for each time step files['T_fluid'].write(nTf, t) files['p'].write(nP, t) files['v_solid'].write(nV, t) files['T_solid'].write(nT, t) files['mu'].write(mu, t) files['v_melt'].write(v_melt, t) files['gradp'].write(project(grad(nP), W), t) files['rho'].write(project(rhosolid, S), t) files['Tf_grad'].write(project(grad(Tf), W), t) files['advect'].write(project(dt * dot(v_melt, grad(nTf))), t) files['ht'].write(project(heat_transfer, S), t) assign(T0, nT) assign(v0, nV) assign(Tf0, nTf) t += time_step count += 1 log('Case mu={}, Tb={}, k={} complete. Run time = {:.2f} minutes'.format( mu_a, Tb, k_s, (clock() - run_time_init) / 60.0))
# =================================================================== # Scaled variables E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lambda_ = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) # Dirichlet boundary condition tol = 1E-14 def clamped_boundary(x, on_boundary): return on_boundary and near(x[0], 0, tol) bc = DirichletBC(V, Constant((0, 0, 0)), clamped_boundary) # Define strain and stress def epsilon(u): return 0.5 * (grad(u) + grad(u).T) def sigma(u): return lambda_ * div(u) * Identity(d) + 2 * mu * epsilon(u) # Mark facets of the mesh and Neumann boundary condition boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) boundaries.set_all(0)
# Define function space and basis functions V = FunctionSpace(mesh, ("CG", 2)) u = TrialFunction(V) v = TestFunction(V) u5 = Function(V) with u5.vector().localForm() as bc_local: bc_local.set(5.0) u0 = Function(V) with u0.vector().localForm() as bc_local: bc_local.set(0.0) # Define Dirichlet boundary conditions at top and bottom boundaries bcs = [ DirichletBC(V, u5, boundaries.where_equal(boundary["TOP"][0])), DirichletBC(V, u0, boundaries.where_equal(boundary["BOTTOM"][0])), ] dx = dx(subdomain_data=domains) ds = ds(subdomain_data=boundaries) # Define variational form F = (inner(a0 * grad(u), grad(v)) * dx(boundary["DOMAIN"][0]) + inner(a1 * grad(u), grad(v)) * dx(boundary["OBSTACLE"][0]) - g_L * v * ds(boundary["LEFT"][0]) - g_R * v * ds(boundary["RIGHT"][0]) - f * v * dx(boundary["DOMAIN"][0]) - f * v * dx(boundary["OBSTACLE"][0])) # Separate left and right hand sides of equation a, L = lhs(F), rhs(F)
def test_DoGIP_vs_FEniCS(self): print( '\n== testing DoGIP vs. FEniCS for problem of weighted projection ====' ) for dim, pol_order in itertools.product([2, 3], [1, 2]): print('dim={}; pol_order={}'.format(dim, pol_order)) N = 2 # no. of elements # creating MESH, defining MATERIAL and SOURCE if dim == 2: mesh = UnitSquareMesh(N, N) m = Expression("1+10*16*x[0]*(1-x[0])*x[1]*(1-x[1])", degree=4) f = Expression("80*x[0]*(0.5-x[0])*(1.-x[0])*x[1]*(1.-x[1])", degree=5) elif dim == 3: mesh = UnitCubeMesh(N, N, N) m = Expression("1+10*16*x[0]*(1-x[0])*(1-x[1])*x[2]", degree=4) f = Expression("80*x[0]*(0.5-x[0])*(1.-x[0])*x[1]*(1.-x[1])", degree=5) mesh.coordinates()[:] += 0.1 * np.random.random( mesh.coordinates().shape) # mesh perturbation ## standard approach with FEniCS ############################################# V = FunctionSpace(mesh, "CG", pol_order) # original FEM space bc = DirichletBC(V, Constant(0.0), lambda x, on_boundary: on_boundary) u, v = TrialFunction(V), TestFunction(V) u_fenics = Function(V) # the vector for storing the solution solve(m * inner(grad(u), grad(v)) * dx == f * v * dx, u_fenics, bc) # solution by FEniCS ## DoGIP - double-grid integration with interpolation-projection ############# W = FunctionSpace(mesh, "DG", 2 * (pol_order - 1)) # double-grid space Wvector = VectorFunctionSpace( mesh, "DG", 2 * (pol_order - 1)) # vector variant of double-grid space w = TestFunction(W) A_dogip = assemble( m * w * dx).get_local() # diagonal matrix of material coefficients A_dogip_full = np.einsum( 'i,jk->ijk', A_dogip, np.eye(dim)) # block-diagonal mat. for non-isotropic mat. bv = assemble(f * v * dx) bc.apply(bv) b = bv.get_local() # vector of right-hand side # assembling global interpolation-projection matrix B B = get_B(V, Wvector, problem=1) # solution to DoGIP problem def Afun(x): Axd = np.einsum('...jk,...j', A_dogip_full, B.dot(x).reshape((-1, dim))) Afunx = B.T.dot(Axd.ravel()) Afunx[list(bc.get_boundary_values() )] = 0 # application of Dirichlet BC return Afunx Alinoper = linalg.LinearOperator((b.size, b.size), matvec=Afun, dtype=np.float) # system matrix x, info = linalg.cg(Alinoper, b, x0=np.zeros_like(b), tol=1e-8, maxiter=1e2) # conjugate gradients # testing the difference between DoGIP and FEniCS self.assertAlmostEqual( 0, np.linalg.norm(u_fenics.vector().get_local() - x)) print('...ok')
def dbc(self, subspace, subdomains, mark): return DirichletBC(subspace.sub(self.dim), Constant(0.), subdomains, mark)
stab1 = 2. nE = FacetNormal(mx) hE = FacetArea(mx) test = div(grad(psi)) S_ = gamma * inner(ax, grad(grad(phi))) * test * dx(mx) \ + stab1 * avg(hE)**(-1) * inner(jump(grad(phi), nE), jump(grad(psi), nE)) * dS(mx) \ + gamma * inner(bx, grad(phi)) * test * dx(mx) \ + gamma * c * phi * test * dx(mx) # This matrix also changes since we are testing the whole equation # with div(grad(psi)) instead of psi M_ = gamma * phi * test * dx(mx) bc_Vx = DirichletBC(Vx, g, 'on_boundary') S = assemble(S_) M = assemble(M_) # Prepare special treatment of deterministic part and time-derivative. xdofs = Vx.tabulate_dof_coordinates().flatten() ix = np.argsort(xdofs) # Since we're using the mesh in the deterministic direction # only for temporary purpose, the coordinates are fine here ydofs = Vy.tabulate_dof_coordinates().flatten() ydofs.sort() ydiff = np.diff(ydofs) assert np.all(ydiff > 0) # Create meshgrid X, Y of shape (ny+1, nx+1)
def test_poisson(k): # Polynomial order and mesh resolution nx_list = [4, 8, 16] # Error list error_u_l2, error_u_h1 = [], [] for nx in nx_list: mesh = UnitSquareMesh(nx, nx) # Define FunctionSpaces and functions V = FunctionSpace(mesh, "DG", k) Vbar = FunctionSpace(mesh, FiniteElement("CG", mesh.ufl_cell(), k)["facet"]) u_soln = Expression("sin(pi*x[0])*sin(pi*x[1])", degree=k + 1, domain=mesh) f = Expression("2*pi*pi*sin(pi*x[0])*sin(pi*x[1])", degree=k + 1) u, v = Function(V), TestFunction(V) ubar, vbar = Function(Vbar), TestFunction(Vbar) n = FacetNormal(mesh) h = CellDiameter(mesh) alpha = Constant(6 * k * k) penalty = alpha / h def facet_integral(integrand): return integrand('-') * dS + integrand('+') * dS + integrand * ds u_flux = ubar F_v_flux = grad(u) + penalty * outer(u_flux - u, n) residual_local = inner(grad(u), grad(v)) * dx residual_local += facet_integral(inner(outer(u_flux - u, n), grad(v))) residual_local -= facet_integral(inner(F_v_flux, outer(v, n))) residual_local -= f * v * dx residual_global = facet_integral(inner(F_v_flux, outer(vbar, n))) a_ll = derivative(residual_local, u) a_lg = derivative(residual_local, ubar) a_gl = derivative(residual_global, u) a_gg = derivative(residual_global, ubar) l_l = -residual_local l_g = -residual_global bcs = [DirichletBC(Vbar, u_soln, "on_boundary")] # Initialize static condensation assembler assembler = AssemblerStaticCondensation(a_ll, a_lg, a_gl, a_gg, l_l, l_g, bcs) A_g, b_g = PETScMatrix(), PETScVector() assembler.assemble_global_lhs(A_g) assembler.assemble_global_rhs(b_g) for bc in bcs: bc.apply(A_g, b_g) solver = PETScKrylovSolver() solver.set_operator(A_g) PETScOptions.set("ksp_type", "preonly") PETScOptions.set("pc_type", "lu") PETScOptions.set("pc_factor_mat_solver_type", "mumps") solver.set_from_options() solver.solve(ubar.vector(), b_g) assembler.backsubstitute(ubar._cpp_object, u._cpp_object) # Compute L2 and H1 norms e_u_l2 = assemble((u - u_soln)**2 * dx)**0.5 e_u_h1 = assemble(grad(u - u_soln)**2 * dx)**0.5 if mesh.mpi_comm().rank == 0: error_u_l2.append(e_u_l2) error_u_h1.append(e_u_h1) if mesh.mpi_comm().rank == 0: iterator_list = [1.0 / float(nx) for nx in nx_list] conv_u_l2 = compute_convergence(iterator_list, error_u_l2) conv_u_h1 = compute_convergence(iterator_list, error_u_h1) # Optimal rate of k + 1 - tolerance assert np.all(conv_u_l2 >= (k + 1.0 - 0.15)) # Optimal rate of k - tolerance assert np.all(conv_u_h1 >= (k - 0.1))
def build_clamped_walls(VComplex): c0vec = Constant((0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) bcs = DirichletBC(VComplex, c0vec, OuterWalls()) return bcs
def test_unsteady_stokes(): nx, ny = 15, 15 k = 1 nu = Constant(1.E-0) dt = Constant(2.5e-2) num_steps = 20 theta0 = 1.0 # Initial theta value theta1 = 0.5 # Theta after 1 step theta = Constant(theta0) mesh = UnitSquareMesh(nx, ny) # The 'unsteady version' of the benchmark in the 2012 paper by Labeur&Wells u_exact = Expression(("sin(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ -6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-sin(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])"), t=0, degree=7, domain=mesh) p_exact = Expression("sin(t) * x[0]*(1.0 - x[0])", t=0, degree=7, domain=mesh) du_exact = Expression(("cos(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-cos(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ -6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])"), t=0, degree=7, domain=mesh) ux_exact = Expression(("x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \ - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])", "-x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \ - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])"), degree=7, domain=mesh) px_exact = Expression("x[0]*(1.0 - x[0])", degree=7, domain=mesh) sin_ext = Expression("sin(t)", t=0, degree=7, domain=mesh) f = du_exact + sin_ext * div(px_exact*Identity(2) - 2*sym(grad(ux_exact))) Vhigh = VectorFunctionSpace(mesh, "DG", 7) Phigh = FunctionSpace(mesh, "DG", 7) # New syntax: V = VectorElement("DG", mesh.ufl_cell(), k) Q = FiniteElement("DG", mesh.ufl_cell(), k-1) Vbar = VectorElement("DGT", mesh.ufl_cell(), k) Qbar = FiniteElement("DGT", mesh.ufl_cell(), k) mixedL = FunctionSpace(mesh, MixedElement([V, Q])) mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar])) V2 = FunctionSpace(mesh, V) Uh = Function(mixedL) Uhbar = Function(mixedG) U0 = Function(mixedL) Uhbar0 = Function(mixedG) u0, p0 = split(U0) ubar0, pbar0 = split(Uhbar0) ustar = Function(V2) # Then the boundary conditions bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma) bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise") bcs = [bc0, bc1] alpha = Constant(6*k*k) forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha).forms_unsteady(ustar, dt, nu, f) ssc = StokesStaticCondensation(mesh, forms_stokes['A_S'], forms_stokes['G_S'], forms_stokes['G_ST'], forms_stokes['B_S'], forms_stokes['Q_S'], forms_stokes['S_S']) t = 0. step = 0 for step in range(num_steps): step += 1 t += float(dt) if comm.Get_rank() == 0: print("Step "+str(step)+" Time "+str(t)) # Set time level in exact solution u_exact.t = t p_exact.t = t du_exact.t = t - (1-float(theta))*float(dt) sin_ext.t = t - (1-float(theta))*float(dt) ssc.assemble_global_lhs() ssc.assemble_global_rhs() for bc in bcs: ssc.apply_boundary(bc) ssc.solve_problem(Uhbar, Uh, 'none', 'default') assign(U0, Uh) assign(ustar, U0.sub(0)) assign(Uhbar0, Uhbar) if step == 1: theta.assign(theta1) udiv_e = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0))*dx)) u_ex_h = interpolate(u_exact, Vhigh) p_ex_h = interpolate(p_exact, Phigh) u_error = sqrt(assemble(dot(Uh.sub(0) - u_ex_h, Uh.sub(0) - u_ex_h)*dx)) p_error = sqrt(assemble(dot(Uh.sub(1) - p_ex_h, Uh.sub(1) - p_ex_h)*dx)) assert udiv_e < 1e-12 assert u_error < 1.5e-4 assert p_error < 1e-2
def compute_time_errors(problem, MethodClass, mesh_sizes, Dt): mesh_generator, solution, f, mu, rho, cell_type = problem() # Translate data into FEniCS expressions. sol_u = Expression((sympy.printing.ccode(solution['u']['value'][0]), sympy.printing.ccode(solution['u']['value'][1])), degree=_truncate_degree(solution['u']['degree']), t=0.0, cell=cell_type) sol_p = Expression(sympy.printing.ccode(solution['p']['value']), degree=_truncate_degree(solution['p']['degree']), t=0.0, cell=cell_type) fenics_rhs0 = Expression((sympy.printing.ccode( f['value'][0]), sympy.printing.ccode(f['value'][1])), degree=_truncate_degree(f['degree']), t=0.0, mu=mu, rho=rho, cell=cell_type) # Deep-copy expression to be able to provide f0, f1 for the Dirichlet- # boundary conditions later on. fenics_rhs1 = Expression(fenics_rhs0.cppcode, degree=_truncate_degree(f['degree']), t=0.0, mu=mu, rho=rho, cell=cell_type) # Create initial states. p0 = Expression(sol_p.cppcode, degree=_truncate_degree(solution['p']['degree']), t=0.0, cell=cell_type) # Compute the problem errors = { 'u': numpy.empty((len(mesh_sizes), len(Dt))), 'p': numpy.empty((len(mesh_sizes), len(Dt))) } for k, mesh_size in enumerate(mesh_sizes): mesh = mesh_generator(mesh_size) mesh_area = assemble(1.0 * dx(mesh)) W = VectorFunctionSpace(mesh, 'CG', 2) P = FunctionSpace(mesh, 'CG', 1) method = MethodClass( W, P, rho, mu, theta=1.0, # theta=0.5, stabilization=None # stabilization='SUPG' ) u1 = Function(W) p1 = Function(P) err_p = Function(P) divu1 = Function(P) for j, dt in enumerate(Dt): # Prepare previous states for multistepping. u = [ Expression(sol_u.cppcode, degree=_truncate_degree(solution['u']['degree']), t=0.0, cell=cell_type), # Expression( # sol_u.cppcode, # degree=_truncate_degree(solution['u']['degree']), # t=0.5*dt, # cell=cell_type # ) ] sol_u.t = dt u_bcs = [DirichletBC(W, sol_u, 'on_boundary')] sol_p.t = dt # p_bcs = [DirichletBC(P, sol_p, 'on_boundary')] p_bcs = [] fenics_rhs0.t = 0.0 fenics_rhs1.t = dt method.step(dt, u1, p1, u, p0, u_bcs=u_bcs, p_bcs=p_bcs, f0=fenics_rhs0, f1=fenics_rhs1, verbose=False, tol=1.0e-10) sol_u.t = dt sol_p.t = dt errors['u'][k][j] = errornorm(sol_u, u1) # The pressure is only determined up to a constant which makes # it a bit harder to define what the error is. For our # purposes, choose an alpha_0\in\R such that # # alpha0 = argmin ||e - alpha||^2 # # with e := sol_p - p. # This alpha0 is unique and explicitly given by # # alpha0 = 1/(2|Omega|) \int (e + e*) # = 1/|Omega| \int Re(e), # # i.e., the mean error in \Omega. alpha = (+assemble(sol_p * dx(mesh)) - assemble(p1 * dx(mesh))) alpha /= mesh_area # We would like to perform # p1 += alpha. # To avoid creating a temporary function every time, assume # that p1 lives in a function space where the coefficients # represent actual function values. This is true for CG # elements, for example. In that case, we can just add any # number to the vector of p1. p1.vector()[:] += alpha errors['p'][k][j] = errornorm(sol_p, p1) show_plots = False if show_plots: plot(p1, title='p1', mesh=mesh) plot(sol_p, title='sol_p', mesh=mesh) err_p.vector()[:] = p1.vector() sol_interp = interpolate(sol_p, P) err_p.vector()[:] -= sol_interp.vector() # plot(sol_p - p1, title='p1 - sol_p', mesh=mesh) plot(err_p, title='p1 - sol_p', mesh=mesh) # r = Expression('x[0]', degree=1, cell=triangle) # divu1 = 1 / r * (r * u1[0]).dx(0) + u1[1].dx(1) divu1.assign(project(u1[0].dx(0) + u1[1].dx(1), P)) plot(divu1, title='div(u1)') return errors
duh0=duh0, duh00=duh00) pde_u = PDEStaticCondensation(mesh, p, forms_u['N_a'], forms_u['G_a'], forms_u['L_a'], forms_u['H_a'], forms_u['B_a'], forms_u['Q_a'], forms_u['R_a'], forms_u['S_a'], 2) # Set-up Stokes Solve forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha, ds=ds).forms_multiphase(rho0, ustar, dt, mu, f) ssc = StokesStaticCondensation(mesh, forms_stokes['A_S'], forms_stokes['G_S'], forms_stokes['B_S'], forms_stokes['Q_S'], forms_stokes['S_S']) # Set pressure in upper left corner to zero bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner(xmin, ymax), "pointwise") bcs = [bc1] lstsq_u = l2projection(p, W_2, 2) # Loop and output step = 0 t = 0. # Store at step 0 xdmf_rho.write(rho0, t) xdmf_u.write(Uh.sub(0), t) xdmf_p.write(Uh.sub(1), t) p.dump2file(mesh, fname_list, property_list, 'wb')
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)
# Create function space V = VectorFunctionSpace(mesh, ("Lagrange", 1)) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(sigma(u), grad(v)) * dx L = inner(f, v) * dx u0 = Function(V) with u0.vector.localForm() as bc_local: bc_local.set(0.0) # Set up boundary condition on inner surface bc = DirichletBC(V, u0, boundary) # Assemble system, applying boundary conditions and preserving symmetry) A = assemble_matrix(a, [bc]) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) # Create solution function u = Function(V) # Create near null space basis (required for smoothed aggregation AMG). null_space = build_nullspace(V)
def truth_solve(mu_unkown): print("Performing truth solve at mu =", mu_unkown) (mesh, subdomains, boundaries, restrictions) = read_mesh() # (mesh, subdomains, boundaries, restrictions) = create_mesh() dx = Measure('dx', subdomain_data=subdomains) ds = Measure('ds', subdomain_data=boundaries) W = generate_block_function_space(mesh, restrictions) # Test and trial functions block_v = BlockTestFunction(W) v, q = block_split(block_v) block_du = BlockTrialFunction(W) du, dp = block_split(block_du) block_u = BlockFunction(W) u, p = block_split(block_u) # gap # V2 = FunctionSpace(mesh, "CG", 1) # gap = Function(V2, name="Gap") # obstacle R = 0.25 d = 0.15 x_0 = mu_unkown[0] y_0 = mu_unkown[1] obstacle = Expression("-d+(pow(x[0]-x_0,2)+pow(x[1]-y_0, 2))/2/R", d=d, R=R , x_0 = x_0, y_0 = y_0, degree=0) # Constitutive parameters E = Constant(10.0) nu = Constant(0.3) mu, lmbda = Constant(E/(2*(1 + nu))), Constant(E*nu/((1 + nu)*(1 - 2*nu))) B = Constant((0.0, 0.0, 0.0)) # Body force per unit volume T = Constant((0.0, 0.0, 0.0)) # Traction force on the boundary # Kinematics # ----------------------------------------------------------------------------- mesh_dim = mesh.topology().dim() # Spatial dimension I = Identity(mesh_dim) # Identity tensor F = I + grad(u) # Deformation gradient C = F.T*F # Right Cauchy-Green tensor J = det(F) # 3rd invariant of the deformation tensor # Strain function def P(u): # P = dW/dF: return mu*(F - inv(F.T)) + lmbda*ln(J)*inv(F.T) def eps(v): return sym(grad(v)) def sigma(v): return lmbda*tr(eps(v))*Identity(3) + 2.0*mu*eps(v) # Definition of The Mackauley bracket <x>+ def ppos(x): return (x+abs(x))/2. # Define the augmented lagrangian def aug_l(x): return x + pen*(obstacle-u[2]) pen = Constant(1e4) # Boundary conditions # bottom_bc = DirichletBC(W.sub(0), Constant((0., 0., 0.)), boundaries, 2) # left_bc = DirichletBC(W.sub(0), Constant((0., 0., 0.)), boundaries, 3) # right_bc = DirichletBC(W.sub(0), Constant((0., 0., 0.)), boundaries, 4) # front_bc = DirichletBC(W.sub(0), Constant((0., 0., 0.)), boundaries, 5) # back_bc = DirichletBC(W.sub(0), Constant((0., 0., 0.)), boundaries, 6) # # sym_x_bc = DirichletBC(W.sub(0).sub(0), Constant(0.), boundaries, 2) # # sym_y_bc = DirichletBC(W.sub(0).sub(1), Constant(0.), boundaries, 3) # # bc = BlockDirichletBC([bottom_bc, sym_x_bc, sym_y_bc]) # bc = BlockDirichletBC([bottom_bc, left_bc, right_bc, front_bc, back_bc]) bottom_bc = DirichletBC(W.sub(0), Constant((0., 0., 0.)), boundaries, 2) left_bc_x = DirichletBC(W.sub(0).sub(0), Constant(0.), boundaries, 3) left_bc_y = DirichletBC(W.sub(0).sub(1), Constant(0.), boundaries, 3) right_bc_x = DirichletBC(W.sub(0).sub(0), Constant(0.), boundaries, 4) right_bc_y = DirichletBC(W.sub(0).sub(1), Constant(0.), boundaries, 4) front_bc_x = DirichletBC(W.sub(0).sub(0), Constant(0.), boundaries, 5) front_bc_y = DirichletBC(W.sub(0).sub(1), Constant(0.), boundaries, 5) back_bc_x = DirichletBC(W.sub(0).sub(0), Constant(0.), boundaries, 6) back_bc_y = DirichletBC(W.sub(0).sub(1), Constant(0.), boundaries, 6) # sym_x_bc = DirichletBC(W.sub(0).sub(0), Constant(0.), boundaries, 2) # sym_y_bc = DirichletBC(W.sub(0).sub(1), Constant(0.), boundaries, 3) # bc = BlockDirichletBC([bottom_bc, sym_x_bc, sym_y_bc]) bc = BlockDirichletBC([bottom_bc, left_bc_x, left_bc_y, \ right_bc_x, right_bc_y, front_bc_x, front_bc_y, \ back_bc_x, back_bc_y]) # Variational forms # F = inner(sigma(u), eps(v))*dx + pen*dot(v[2], ppos(u[2]-obstacle))*ds(1) # F = [inner(sigma(u), eps(v))*dx - aug_l(l)*v[2]*ds(1) + ppos(aug_l(l))*v[2]*ds(1), # (obstacle-u[2])*v*ds(1) - (1/pen)*ppos(aug_l(l))*v*ds(1)] # F_a = inner(sigma(u), eps(v))*dx # F_b = - aug_l(p)*v[2]*ds(1) + ppos(aug_l(p))*v[2]*ds(1) # F_c = (obstacle-u[2])*q*ds(1) # F_d = - (1/pen)*ppos(aug_l(p))*q*ds(1) # # block_F = [[F_a, F_b], # [F_c, F_d]] F_a = inner(P(u), grad(v))*dx - dot(B, v)*dx - dot(T, v)*ds \ - aug_l(p)*v[2]*ds(1) + ppos(aug_l(p))*v[2]*ds(1) F_b = (obstacle-u[2])*q*ds(1) - (1/pen)*ppos(aug_l(p))*q*ds(1) block_F = [F_a, F_b] J = block_derivative(block_F, block_u, block_du) # Setup solver problem = BlockNonlinearProblem(block_F, block_u, bc, J) solver = BlockPETScSNESSolver(problem) solver.parameters.update({ "linear_solver": "mumps", "absolute_tolerance": 1E-4, "relative_tolerance": 1E-4, "maximum_iterations": 50, "report": True, "error_on_nonconvergence": True }) # solver.parameters.update({ # "linear_solver": "cg", # "absolute_tolerance": 1E-4, # "relative_tolerance": 1E-4, # "maximum_iterations": 50, # "report": True, # "error_on_nonconvergence": True # }) # Perform a fake loop over time. Note how up will store the solution at the last time. # Q. for? # A. You can remove it, since your problem is stationary. The template was targeting # a final application which was transient, but in which the ROM should have only # described the final solution (when reaching the steady state). # for _ in range(2): # solver.solve() a1 = solver.solve() print(a1) # save all the solution here as a function of time # Return the solution at the last time # Q. block_u or block # A. I think block_u, it will split split among the components elsewhere return block_u
# Define the variational (projection problem) W_e = FiniteElement("DG", mesh.ufl_cell(), k) T_e = FiniteElement("DG", mesh.ufl_cell(), 0) Wbar_e = FiniteElement("DGT", mesh.ufl_cell(), k) W = FunctionSpace(mesh, W_e) T = FunctionSpace(mesh, T_e) Wbar = FunctionSpace(mesh, Wbar_e) psi_h, psi0_h = Function(W), Function(W) lambda_h = Function(T) psibar_h = Function(Wbar) # Boundary conditions bc = DirichletBC(Wbar, Constant(0.), "on_boundary") # Initialize forms FuncSpace_adv = { 'FuncSpace_local': W, 'FuncSpace_lambda': T, 'FuncSpace_bar': Wbar } forms_pde = FormsPDEMap(mesh, FuncSpace_adv).forms_theta_linear( psi0_h, uh, dt, Constant(1.0)) pde_projection = PDEStaticCondensation( mesh, p, forms_pde['N_a'], forms_pde['G_a'], forms_pde['L_a'], forms_pde['H_a'], forms_pde['B_a'], forms_pde['Q_a'], forms_pde['R_a'], forms_pde['S_a'], [bc], property_idx) # Set initial condition at mesh and particles
def bc(t): exact_solution_expression.t = t return [DirichletBC(V, exact_solution_expression, boundary)]
def dbc(self, subspace, subdomains, mark): return DirichletBC(subspace.sub(self.dim), self.value, subdomains, mark)
def solve(self): """ Find eigenvalues for transformed mesh. """ self.progress("Building mesh.") # build transformed mesh mesh = self.refineMesh() # dim = mesh.topology().dim() if self.bcLast: mesh = transform_mesh(mesh, self.transformList) Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList) else: Robin, Steklov, shift, bcs = get_bc_parts(mesh, self.bcList) mesh = transform_mesh(mesh, self.transformList) # boundary conditions computed on non-transformed mesh # copy the values to transformed mesh fun = FacetFunction("size_t", mesh, shift) fun.array()[:] = bcs.array()[:] bcs = fun ds = Measure('ds', domain=mesh, subdomain_data=bcs) V = FunctionSpace(mesh, self.method, self.deg) u = TrialFunction(V) v = TestFunction(V) self.progress("Assembling matrices.") wTop = Expression(self.wTop) wBottom = Expression(self.wBottom) # # build stiffness matrix form # s = dot(grad(u), grad(v)) * wTop * dx # add Robin parts for bc in Robin: s += Constant(bc.parValue) * u * v * wTop * ds(bc.value + shift) # # build mass matrix form # if len(Steklov) > 0: m = 0 for bc in Steklov: m += Constant( bc.parValue) * u * v * wBottom * ds(bc.value + shift) else: m = u * v * wBottom * dx # assemble # if USE_EIGEN: # S, M = EigenMatrix(), EigenMatrix() # tempv = EigenVector() # else: S, M = PETScMatrix(), PETScMatrix() # tempv = PETScVector() if not np.any(bcs.array() == shift + 1): # no Dirichlet parts assemble(s, tensor=S) assemble(m, tensor=M) else: # # with EIGEN we could # apply Dirichlet condition symmetrically # completely remove rows and columns # # Dirichlet parts are marked with shift+1 # # temp = Constant(0)*v*dx bc = DirichletBC(V, Constant(0.0), bcs, shift + 1) # assemble_system(s, temp, bc, A_tensor=S, b_tensor=tempv) # assemble_system(m, temp, bc, A_tensor=M, b_tensor=tempv) assemble(s, tensor=S) bc.apply(S) assemble(m, tensor=M) # bc.zero(M) # if USE_EIGEN: # M = M.sparray() # M.eliminate_zeros() # print M.shape # indices = M.indptr[:-1] - M.indptr[1:] < 0 # M = M[indices, :].tocsc()[:, indices] # S = S.sparray()[indices, :].tocsc()[:, indices] # print M.shape # # solve the eigenvalue problem # self.progress("Solving eigenvalue problem.") eigensolver = SLEPcEigenSolver(S, M) eigensolver.parameters["problem_type"] = "gen_hermitian" eigensolver.parameters["solver"] = "krylov-schur" if self.target is not None: eigensolver.parameters["spectrum"] = "target real" eigensolver.parameters["spectral_shift"] = self.target else: eigensolver.parameters["spectrum"] = "smallest magnitude" eigensolver.parameters["spectral_shift"] = -0.01 eigensolver.parameters["spectral_transform"] = "shift-and-invert" eigensolver.solve(self.number) self.progress("Generating eigenfunctions.") if eigensolver.get_number_converged() == 0: return None eigf = [] eigv = [] if self.deg > 1: mesh = refine(mesh) W = FunctionSpace(mesh, 'CG', 1) for i in range(eigensolver.get_number_converged()): pair = eigensolver.get_eigenpair(i)[::2] eigv.append(pair[0]) u = Function(V) u.vector()[:] = pair[1] eigf.append(interpolate(u, W)) return eigv, eigf
def _test_nonlinear_solver_sparse(callback_type): # Create mesh and define function space mesh = IntervalMesh(132, 0, 2*pi) V = FunctionSpace(mesh, "Lagrange", 1) # Define Dirichlet boundary (x = 0 or x = 2*pi) def boundary(x): return x[0] < 0 + DOLFIN_EPS or x[0] > 2*pi - 10*DOLFIN_EPS # Define exact solution exact_solution_expression = Expression("x[0] + sin(2*x[0])", element=V.ufl_element()) exact_solution = project(exact_solution_expression, V) # Define variational problem du = TrialFunction(V) v = TestFunction(V) u = Function(V) g = Expression("4*sin(2*x[0])*(pow(x[0]+sin(2*x[0]), 2)+1)-2*(x[0]+sin(2*x[0]))*pow(2*cos(2*x[0])+1, 2)", element=V.ufl_element()) r = inner((1+u**2)*grad(u), grad(v))*dx - g*v*dx j = derivative(r, u, du) x = inner(du, v)*dx # Assemble inner product matrix X = assemble(x) # Define initial guess def sparse_initial_guess(): initial_guess_expression = Expression("0.1 + 0.9*x[0]", element=V.ufl_element()) return project(initial_guess_expression, V) # Define boundary condition bc = [DirichletBC(V, exact_solution_expression, boundary)] # Define callback function depending on callback type assert callback_type in ("form callbacks", "tensor callbacks") if callback_type == "form callbacks": def callback(arg): return arg elif callback_type == "tensor callbacks": def callback(arg): return assemble(arg) # Define problem wrapper class SparseFormProblemWrapper(NonlinearProblemWrapper): # Residual function def residual_eval(self, solution): return callback(r) # Jacobian function def jacobian_eval(self, solution): return callback(j) # Define boundary condition def bc_eval(self): return bc # Solve the nonlinear problem sparse_problem_wrapper = SparseFormProblemWrapper() sparse_solution = u assign(sparse_solution, sparse_initial_guess()) sparse_solver = SparseNonlinearSolver(sparse_problem_wrapper, sparse_solution) sparse_solver.set_parameters({ "linear_solver": "mumps", "maximum_iterations": 20, "report": True }) sparse_solver.solve() # Compute the error sparse_error = Function(V) sparse_error.vector().add_local(+ sparse_solution.vector().get_local()) sparse_error.vector().add_local(- exact_solution.vector().get_local()) sparse_error.vector().apply("") sparse_error_norm = sparse_error.vector().inner(X*sparse_error.vector()) print("SparseNonlinearSolver error (" + callback_type + "):", sparse_error_norm) assert isclose(sparse_error_norm, 0., atol=1.e-5) return (sparse_error_norm, V, u, r, j, X, sparse_initial_guess, exact_solution)
# Define boundary condition u_D = Expression( '1 + x[0]*x[0] + alpha*x[1]*x[1] + theta*x[2]*x[2] + beta*t', # '1 + beta*t', degree=2, alpha=alpha, theta=theta, beta=beta, t=0) def boundary(x, on_boundary): return on_boundary bc = DirichletBC(V, u_D, boundary) # Define initial value u_n = interpolate(u_D, V) # u_n = project(u_D, V) # Define variational problem u = TrialFunction(V) v = TestFunction(V) f = Constant(beta - 2 - 2 * alpha) F = u * v * dx + dt * dot(grad(u), grad(v)) * dx - (u_n + dt * f) * v * dx a, L = lhs(F), rhs(F) # Time-stepping u = Function(V)
def __init__(self): # https://fenicsproject.org/qa/12891/initialize-mesh-from-vertices-connectivities-at-once points, cells, _, cell_data, _ = meshes.ball_in_tube_cyl.generate() # 2018.1 # self.mesh = Mesh( # dolfin.mpi_comm_world(), dolfin.cpp.mesh.CellType.Type_triangle, # points[:, :2], cells['triangle'] # ) with TemporaryDirectory() as temp_dir: tmp_filename = os.path.join(temp_dir, "test.xml") meshio.write_points_cells( tmp_filename, points, cells, cell_data=cell_data, file_format="dolfin-xml", ) self.mesh = Mesh(tmp_filename) V0_element = FiniteElement("CG", self.mesh.ufl_cell(), 2) V1_element = FiniteElement("B", self.mesh.ufl_cell(), 3) self.W = FunctionSpace(self.mesh, V0_element * V1_element) self.P = FunctionSpace(self.mesh, "CG", 1) # Define mesh and boundaries. class LeftBoundary(SubDomain): # pylint: disable=no-self-use def inside(self, x, on_boundary): return on_boundary and x[0] < GMSH_EPS left_boundary = LeftBoundary() class RightBoundary(SubDomain): # pylint: disable=no-self-use def inside(self, x, on_boundary): return on_boundary and x[0] > 1.0 - GMSH_EPS right_boundary = RightBoundary() class LowerBoundary(SubDomain): # pylint: disable=no-self-use def inside(self, x, on_boundary): return on_boundary and x[1] < GMSH_EPS lower_boundary = LowerBoundary() # class UpperBoundary(SubDomain): # # pylint: disable=no-self-use # def inside(self, x, on_boundary): # return on_boundary and x[1] > 5.0-GMSH_EPS class CoilBoundary(SubDomain): # pylint: disable=no-self-use def inside(self, x, on_boundary): # One has to pay a little bit of attention when defining the # coil boundary; it's easy to miss the edges closest to x[0]=0. return (on_boundary and x[1] > 1.0 - GMSH_EPS and x[1] < 2.0 + GMSH_EPS and x[0] < 1.0 - GMSH_EPS) coil_boundary = CoilBoundary() self.u_bcs = [ DirichletBC(self.W, (0.0, 0.0), right_boundary), DirichletBC(self.W.sub(0), 0.0, left_boundary), DirichletBC(self.W, (0.0, 0.0), lower_boundary), DirichletBC(self.W, (0.0, 0.0), coil_boundary), ] self.p_bcs = [] # self.p_bcs = [DirichletBC(Q, 0.0, upper_boundary)] return
def __call__(self, degree=3, y=0., standard_deviation=1.): V = FunctionSpace(self._mesh, "CG", degree) v = TestFunction(V) potential_trial = TrialFunction(V) potential = Function(V) dx = Measure("dx")(subdomain_data=self._subdomains) # ds = Measure("ds")(subdomain_data=self._boundaries) csd = Expression(f''' x[1] >= {self.H} ? 0 : a * exp({-0.5 / standard_deviation ** 2} * ((x[0])*(x[0]) + (x[1] - {y})*(x[1] - {y}) + (x[2])*(x[2]) )) ''', degree=degree, a=1.0) self.a = csd.a = 1.0 / assemble( csd * Measure("dx", self._mesh)) # print(assemble(csd * Measure("dx", self._mesh))) L = csd * v * dx known_terms = assemble(L) # a = (inner(grad(potential_trial), grad(v)) # * (Constant(self.SALINE_CONDUCTIVITY) * dx(self.SALINE_VOL) # + Constant(self.SLICE_CONDUCTIVITY) * (dx(self.SLICE_VOL) # + dx(self.ROI_VOL)))) a = sum( Constant(conductivity) * inner(grad(potential_trial), grad(v)) * dx(domain) for domain, conductivity in [ (self.SALINE_VOL, self.SALINE_CONDUCTIVITY), (self.SLICE_VOL, self.SLICE_CONDUCTIVITY), (self.ROI_VOL, self.SLICE_CONDUCTIVITY), ]) terms_with_unknown = assemble(a) dirchlet_bc = DirichletBC( V, Constant(2.0 * 0.25 / (self.RADIUS * np.pi * self.SALINE_CONDUCTIVITY)), # 2.0 becaue of dielectric base duplicating # the current source # slice conductivity and thickness considered # negligible self._boundaries, self.MODEL_DOME) dirchlet_bc.apply(terms_with_unknown, known_terms) solver = KrylovSolver("cg", "ilu") solver.parameters["maximum_iterations"] = MAX_ITER solver.parameters["absolute_tolerance"] = 1E-8 # solver.parameters["monitor_convergence"] = True start = datetime.datetime.now() try: self.iterations = solver.solve(terms_with_unknown, potential.vector(), known_terms) return potential except RuntimeError as e: self.iterations = MAX_ITER logger.warning("Solver failed: {}".format(repr(e))) return None finally: self.time = datetime.datetime.now() - start
def test_krylov_reuse_pc(): "Test preconditioner re-use with PETScKrylovSolver" # Define problem mesh = UnitSquareMesh(MPI.comm_world, 8, 8) V = FunctionSpace(mesh, ('Lagrange', 1)) bc = DirichletBC(V, Constant(0.0), lambda x, on_boundary: on_boundary) u = TrialFunction(V) v = TestFunction(V) # Forms a, L = inner(grad(u), grad(v)) * dx, dot(Constant(1.0), v) * dx A, P = PETScMatrix(), PETScMatrix() b = PETScVector() # Assemble linear algebra objects assemble(a, tensor=A) # noqa assemble(a, tensor=P) # noqa assemble(L, tensor=b) # noqa # Apply boundary conditions bc.apply(A) bc.apply(P) bc.apply(b) # Create Krysolv solver and set operators solver = PETScKrylovSolver("gmres", "bjacobi") solver.set_operators(A, P) # Solve x = PETScVector() num_iter_ref = solver.solve(x, b) # Change preconditioner matrix (bad matrix) and solve (PC will be # updated) a_p = u * v * dx assemble(a_p, tensor=P) # noqa bc.apply(P) x = PETScVector() num_iter_mod = solver.solve(x, b) assert num_iter_mod > num_iter_ref # Change preconditioner matrix (good matrix) and solve (PC will be # updated) a_p = a assemble(a_p, tensor=P) # noqa bc.apply(P) x = PETScVector() num_iter = solver.solve(x, b) assert num_iter == num_iter_ref # Change preconditioner matrix (bad matrix) and solve (PC will not # be updated) solver.set_reuse_preconditioner(True) a_p = u * v * dx assemble(a_p, tensor=P) # noqa bc.apply(P) x = PETScVector() num_iter = solver.solve(x, b) assert num_iter == num_iter_ref # Update preconditioner (bad PC, will increase iteration count) solver.set_reuse_preconditioner(False) x = PETScVector() num_iter = solver.solve(x, b) assert num_iter == num_iter_mod
degree=1) rhs = -D * inner(grad(u), grad(v)) * dx + domainSource * v * dx # Define left and right boundary def boundaryLeft(x, on_boundary): return x[0] < DOLFIN_EPS def boundaryRight(x, on_boundary): return 1.0 - x[0] < DOLFIN_EPS # Left boundary has an explicit time dependency boundarySource = Expression("t", t=0, degree=1) bcLeft = DirichletBC(V, boundarySource, boundaryLeft) bcRight = DirichletBC(V, 0.0, boundaryRight) # Define the time domain T = [0, 1.0] # Define initial condition W_exact = Function(V) W_exact.interpolate(Constant(0.0)) exactSolver = ESDIRK(T, W_exact, rhs, bcs=[bcLeft, bcRight], tdfBC=[boundarySource], tdf=[domainSource])
def __init__(self): n = 40 self.mesh = UnitSquareMesh(n, n, "crossed") # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < DOLFIN_EPS class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 1.0 - DOLFIN_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < DOLFIN_EPS class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 1.0 - DOLFIN_EPS class RestrictedUpperBoundary(SubDomain): def inside(self, x, on_boundary): return (on_boundary and x[1] > 1.0 - DOLFIN_EPS and DOLFIN_EPS < x[0] and x[0] < 0.5 - DOLFIN_EPS) left = LeftBoundary() right = RightBoundary() lower = LowerBoundary() upper = UpperBoundary() # restricted_upper = RestrictedUpperBoundary() # Be particularly careful with the boundary conditions. # The main problem here is that the PPE system is consistent if and # only if # # \int_\Omega div(u) = \int_\Gamma n.u = 0. # # This is exactly and even pointwise fulfilled for the continuous # problem. In the discrete case, we can have to make sure that n.u is # 0 all along the boundary. # In the lid-driven cavity problem, of particular interest are the # corner points at the lid. One has to assert that the z-component of u # is 0 all across the lid, and the x-component of u is 0 everywhere but # the lid. Since u is L2-"continuous", the lid condition on u_x must # not be enforced in the corner points. The u_y component must be # enforced all over the lid, including the end points. V_element = FiniteElement("CG", self.mesh.ufl_cell(), 2) self.W = FunctionSpace(self.mesh, V_element * V_element) self.u_bcs = [ DirichletBC(self.W, (0.0, 0.0), left), DirichletBC(self.W, (0.0, 0.0), right), # DirichletBC(self.W.sub(0), Expression('x[0]'), restricted_upper), DirichletBC(self.W, (0.0, 0.0), lower), DirichletBC(self.W.sub(0), Constant("1.0"), upper), DirichletBC(self.W.sub(1), 0.0, upper), # DirichletBC(self.W.sub(0), Constant('-1.0'), lower), # DirichletBC(self.W.sub(1), 0.0, lower), # DirichletBC(self.W.sub(1), Constant('1.0'), left), # DirichletBC(self.W.sub(0), 0.0, left), # DirichletBC(self.W.sub(1), Constant('-1.0'), right), # DirichletBC(self.W.sub(0), 0.0, right), ] self.P = FunctionSpace(self.mesh, "CG", 1) self.p_bcs = [] return
# The mixed finite element space is known as Taylor–Hood. # It is a stable, standard element pair for the Stokes # equations. Now we can define boundary conditions:: # Extract subdomain facet arrays mf = sub_domains.values mf0 = np.where(mf == 0) mf1 = np.where(mf == 1) # No-slip boundary condition for velocity # x1 = 0, x1 = 1 and around the dolphin noslip = Function(W.sub(0).collapse()) noslip.interpolate(lambda x: np.zeros((x.shape[0], 2))) bc0 = DirichletBC(W.sub(0), noslip, mf0[0]) # Inflow boundary condition for velocity # x0 = 1 def inflow_eval(x): values = np.zeros((x.shape[0], 2)) values[:, 0] = - np.sin(x[:, 1] * np.pi) return values inflow = Function(W.sub(0).collapse()) inflow.interpolate(inflow_eval) bc1 = DirichletBC(W.sub(0), inflow, mf1[0])
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("smallest eigenvalue: {}".format(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("final smallest eigenvalue: {}".format(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 update_mesh_from_boundary_nodes(self, perturbation): """ Deform mesh with boundary perturbation (a numpy array) given as Neumann input in an linear elastic mesh deformation. """ # Reset mesh self.mesh.coordinates()[:] = self.backup volume_function = Function(self.S) for i in self.design_map.keys(): volume_function.vector()[self.design_map[i]] = perturbation[i] u, v = TrialFunction(self.S), TestFunction(self.S) def compute_mu(constant=True): """ Compute mu as according to arxiv paper https://arxiv.org/pdf/1509.08601.pdf """ mu_min=Constant(1) mu_max=Constant(500) if constant: return mu_max else: V = FunctionSpace(self.mesh, "CG",1) u, v = TrialFunction(V), TestFunction(V) a = inner(grad(u),grad(v))*dx l = Constant(0)*v*dx bcs = [] for marker in self.move_dict["Fixed"]: bcs.append(DirichletBC(V, mu_min, self.mf, marker)) for marker in self.move_dict["Deform"]: bcs.append(DirichletBC(V, mu_max, self.mf, marker)) mu = Function(V) solve(a==l, mu, bcs=bcs) return mu mu = compute_mu(False) def epsilon(u): return sym(grad(u)) def sigma(u,mu=500, lmb=0): return 2*mu*epsilon(u) + lmb*tr(epsilon(u))*Identity(2) a = inner(sigma(u,mu=mu), grad(v))*dx L = inner(Constant((0,0)), v)*dx bcs = [] for marker in self.move_dict["Fixed"]: bcs.append(DirichletBC(self.S, Constant([0]*mesh.geometric_dimension()), self.mf, marker)) dStress = Measure("ds", subdomain_data=self.mf) from femorph import VolumeNormal n = VolumeNormal(mesh) # Enforcing node movement through elastic stress computation # NOTE: This strategy does only work for the first part of the deformation for marker in self.move_dict["Deform"]: L += inner(volume_function, v)*dStress(marker) # Direct control of boundary nodes # for marker in self.move_dict["Deform"]: # bcs.append(DirichletBC(self.S, volume_function, self.mf, marker)) s = Function(self.S) solve(a==L, s, bcs=bcs) self.perturbation = s ALE.move(self.mesh, self.perturbation)