from mesh import QuadMesh, Vertex, HalfEdge, QuadCell, Mesh1D, Interval, Tree from fem import DofHandler, QuadFE, GaussRule, Function from mesh import convert_to_array from plot import Plot from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import numpy as np mtags = Tree(regular=False) mesh = Mesh1D(resolution=(1, )) flag = tuple(mtags.get_node_address()) mesh.cells.record(flag) mtags.add_child() new_flag = tuple(mtags.get_child(0).get_node_address()) mesh.cells.refine(subforest_flag=flag, \ new_label=new_flag) for leaf in mesh.cells.get_leaves(subforest_flag=flag): leaf.info() print('==' * 20) for leaf in mesh.cells.get_leaves(subforest_flag=new_flag): leaf.info() element = QuadFE(1, 'Q2') dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() dofhandler.set_dof_vertices()
def experiment01_problem(): """ Illustrate the problem: Plot sample paths of the input q, of the output, and histogram of the QoI. """ # # Computational Mesh # mesh = Mesh1D(resolution=(100, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() # # Basis # phi = Basis(dQ1, 'v') phi_x = Basis(dQ1, 'vx') # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() d = len(lmd) # # Sample and plot full dimensional parameter and solution # n_samples = 20000 z = np.random.randn(d, n_samples) q = sample_q0(V, lmd, d, z) # Define finite element function qfn = Nodal(data=q, basis=phi) problem = [[Form(qfn, test=phi_x, trial=phi_x), Form(1, test=phi)], [Form(qfn, test=phi_x, dmu='dv', flag='right')]] # Define assembler assembler = Assembler(problem) # Incorporate Dirichlet conditions assembler.add_dirichlet('left', 0) assembler.add_dirichlet('right', 1) comment.tic('assembly') # Assemble system assembler.assemble() comment.toc() comment.tic('solver') ufn = Nodal(basis=phi, data=None) J = np.zeros(n_samples) for i in range(n_samples): # Solve system u = assembler.solve(i_problem=0, i_matrix=i, i_vector=0) # Compute quantity of interest J[i] = u.dot(assembler.get_vector(1, i)) # Update sample paths ufn.add_samples(u) comment.toc() # # Plots # """ # Formatting plt.rc('text', usetex=True) # Figure sizes fs2 = (3,2) fs1 = (4,3) plot = Plot(quickview=False) plot_kwargs = {'color':'k', 'linewidth':0.05} # # Plot qfn # # Figure fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) ax = plot.line(qfn, axis=ax, i_sample=np.arange(100), plot_kwargs=plot_kwargs) ax.set_xlabel(r'$x$') ax.set_ylabel(r'$q$') plt.tight_layout() fig.savefig('fig/ex02_gauss_qfn.eps') plt.close() # # Plot ufn # fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) ax = plot.line(ufn, axis=ax, i_sample=np.arange(100), plot_kwargs=plot_kwargs) ax.set_xlabel(r'$x$') ax.set_ylabel(r'$u$') plt.tight_layout() fig.savefig('fig/ex02_gauss_ufn.eps') plt.close() """ # Formatting plt.rc('text', usetex=True) # Figure sizes fs2 = (3, 2) fs1 = (4, 3) fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) plt.hist(J, bins=100, density=True) ax.set_xlabel(r'$J(u)$') plt.tight_layout() fig.savefig('fig/ex02_gauss_jhist.eps')
L = assembler.get_vector() # Gaussian field if __name__ == '__main__': #%% Test 2: Variance test02_variance() #%% Simple projection Matrix # # Define and record coarse mesh # mesh = Mesh1D(resolution=(16, )) mesh.record(0) # # Refine mesh and record # """ # One level of refinement mesh.cells.find_node([0]).mark('r') mesh.cells.refine(refinement_flag='r') mesh.cells.find_node([0,0]).mark('r') mesh.cells.refine(refinement_flag='r') """ l_max = 4 for i in range(l_max):
def test_derivative(self): """ Compute the derivatives of a Nodal Map """ # Define meshes for each dimension meshes = {1: Mesh1D(resolution=(2, )), 2: QuadMesh(resolution=(2, 2))} # Define elements for each dimension elements = {1: QuadFE(1, 'Q2'), 2: QuadFE(2, 'Q2')} # Use function to set data fns = {1: lambda x: 2 * x[:, 0]**2, 2: lambda x: x[:, 0]**2 + x[:, 1]} derivatives = {1: [(1, 0), (2, 0)], 2: [(1, 0), (1, 1), (2, 0, 0)]} dfdx_exact = { 1: [lambda x: 4 * x[:, 0][:, None], lambda x: 4 * np.ones(x.shape)], 2: [ lambda x: 2 * x[:, 0][:, None], lambda x: np.ones(x.shape), lambda x: 2 * np.ones(x.shape) ] } # n_samples = 2 parms = {1: [{}, {}], 2: [{}, {}]} for dim in [1, 2]: mesh = meshes[dim] # Random points in domain n_points = 5 if dim == 1: x_min, x_max = mesh.bounding_box() x = x_min + 0.5 * (x_max - x_min) * np.random.rand(n_points) x = x[:, np.newaxis] elif dim == 2: x_min, x_max, y_min, y_max = mesh.bounding_box() x = np.zeros((n_points, 2)) x[:, 0] = x_min + (x_max - x_min) * np.random.rand(n_points) x[:, 1] = y_min + (y_max - y_min) * np.random.rand(n_points) element = elements[dim] fn = fns[dim] dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() basis = Basis(dofhandler) # # Deterministic # f = Nodal(f=fn, basis=basis, mesh=mesh, element=element, dim=dim, n_variables=1) count = 0 for derivative in derivatives[dim]: # Evaluate the derivative dfdx = f.differentiate(derivative) self.assertTrue( np.allclose(dfdx.eval(x=x), dfdx_exact[dim][count](x))) count += 1 # # Sampled # parm = parms[dim] f = Nodal(f=fn, parameters=parm, basis=basis, mesh=mesh, element=element, dim=dim) count = 0 for derivative in derivatives[dim]: # Evaluate the derivative dfdx = f.differentiate(derivative) self.assertTrue( np.allclose( dfdx.eval(x=x)[:, 0], dfdx_exact[dim][count](x)[:, 0])) self.assertTrue( np.allclose( dfdx.eval(x=x)[:, 1], dfdx_exact[dim][count](x)[:, 0])) count += 1
def test_eval(self): # # Out of the box covariance kernels # fig, ax = plt.subplots(6, 4, figsize=(5, 7)) cov_names = [ 'constant', 'linear', 'gaussian', 'exponential', 'matern', 'rational' ] anisotropies = {1: [None, 2], 2: [None, np.diag([2, 1])]} m_count = 0 for mesh in [Mesh1D(resolution=(10, )), QuadMesh(resolution=(10, 10))]: # Dimension dim = mesh.dim() # # Construct computational mesh # # Piecewise constant elements element = QuadFE(dim, 'DQ0') # Define dofhandler -> get vertices dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() dofhandler.set_dof_vertices() v = dofhandler.get_dof_vertices() # Define meshgrid for 1 and 2 dimensions n_dofs = dofhandler.n_dofs() M1, M2 = np.mgrid[0:n_dofs, 0:n_dofs] if dim == 1: X = v[:, 0][M1].ravel() Y = v[:, 0][M2].ravel() elif dim == 2: X = np.array([v[:, 0][M1].ravel(), v[:, 1][M1].ravel()]).T Y = np.array([v[:, 0][M2].ravel(), v[:, 1][M2].ravel()]).T x = convert_to_array(X, dim=dim) y = convert_to_array(Y, dim=dim) a_count = 0 isotropic_label = ['isotropic', 'anisotropic'] for M in anisotropies[dim]: # Cycle through anisotropies # Define covariance parameters cov_pars = { 'constant': { 'sgm': 1 }, 'linear': { 'sgm': 1, 'M': M }, 'gaussian': { 'sgm': 1, 'l': 0.1, 'M': M }, 'exponential': { 'l': 0.1, 'M': M }, 'matern': { 'sgm': 1, 'nu': 2, 'l': 0.5, 'M': M }, 'rational': { 'a': 3, 'M': M } } c_count = 0 for cov_name in cov_names: C = CovKernel(cov_name, cov_pars[cov_name]) Z = C.eval((x, y)).reshape(M1.shape) col = int(m_count * 2**1 + a_count * 2**0) row = c_count ax[row, col].imshow(Z) if col == 0: ax[row, col].set_ylabel(cov_name) if row == 0: ax[row, col].set_title('%dD mesh\n %s' % (dim, isotropic_label[a_count])) ax[row, col].set_xticks([], []) ax[row, col].set_yticks([], []) c_count += 1 a_count += 1 m_count += 1 fig.savefig('test_covkernel_eval.eps')
from mesh import QuadMesh, Mesh1D from plot import Plot from fem import QuadFE, DofHandler from function import Explicit import numpy as np plot = Plot() mesh = Mesh1D() Q0 = QuadFE(1, 'DQ0') dh0 = DofHandler(mesh, Q0) n_levels = 10 for l in range(n_levels): mesh.cells.refine(new_label=l) dh0.distribute_dofs(subforest_flag=l) f = Explicit(lambda x: np.abs(x - 0.5), dim=1) fQ = f.interpolant(dh0, subforest_flag=3) plot.line(fQ, mesh) plot.mesh(mesh, dofhandler=dh0, subforest_flag=0) mesh = QuadMesh(resolution=(10, 10)) plot.mesh(mesh)
def test_set_data(self): meshes = {1: Mesh1D(), 2: QuadMesh()} elements = {1: QuadFE(1, 'Q2'), 2: QuadFE(2, 'Q2')} # # Use function to set data # fns = { 1: { 1: lambda x: 2 * x[:, 0]**2, 2: lambda x, y: 2 * x[:, 0] + 2 * y[:, 0] }, 2: { 1: lambda x: x[:, 0]**2 + x[:, 1], 2: lambda x, y: x[:, 0] * y[:, 0] + x[:, 1] * y[:, 1] } } parms = {1: {1: [{}, {}], 2: [{}, {}]}, 2: {1: [{}, {}], 2: [{}, {}]}} for dim in [1, 2]: # Get mesh and element mesh = meshes[dim] element = elements[dim] # Set dofhandler dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() n_dofs = dofhandler.n_dofs() # Set basis basis = Basis(dofhandler) # Determine the shapes of the data det_shapes = {1: (n_dofs, 1), 2: (n_dofs, n_dofs, 1)} smp_shapes = {1: (n_dofs, 2), 2: (n_dofs, n_dofs, 2)} # Get a vertex i = np.random.randint(n_dofs) j = np.random.randint(n_dofs) dofhandler.set_dof_vertices() x = dofhandler.get_dof_vertices() x1 = np.array([x[i, :]]) x2 = np.array([x[j, :]]) for n_variables in [1, 2]: fn = fns[dim][n_variables] parm = parms[dim][n_variables] # # Deterministic # f = Nodal(f=fn, basis=basis, n_variables=n_variables) # Check shape self.assertEqual(f.data().shape, det_shapes[n_variables]) # Check value if n_variables == 1: val = fn(x1)[0] self.assertEqual(val, f.data()[i]) else: val = fn(x1, x2) self.assertEqual(val[0], f.data()[i, j]) # # Sampled # f = Nodal(f=fn, parameters=parm, basis=basis, n_variables=n_variables) # Check shape self.assertEqual(f.data().shape, smp_shapes[n_variables]) # Check that samples are stored in the right place if n_variables == 1: self.assertTrue(np.allclose(f.data()[:, 0], f.data()[:, 1])) elif n_variables == 2: self.assertTrue( np.allclose(f.data()[:, :, 0], f.data()[:, :, 1]))
def experiment04_sparse_grid(): """ Test sparse grid """ # # Computational mesh # mesh = Mesh1D(resolution=(100, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() # Truncation levels truncation_levels = [1, 5, 10, 20] # Formatting plt.rc('text', usetex=True) # Set figure and axis fs2 = (3, 2) fs1 = (4, 3) # For mean fig1 = plt.figure(figsize=fs1) ax1 = fig1.add_subplot(111) # For variance fig2 = plt.figure(figsize=fs1) ax2 = fig2.add_subplot(111) for d0 in truncation_levels: J = [] mean = [] var = [] n = [] for depth in range(5): # # Construct Sparse Grid # grid = TasmanianSG.TasmanianSparseGrid() dimensions = d0 outputs = 1 type = 'level' rule = 'gauss-hermite' grid.makeGlobalGrid(dimensions, outputs, depth, type, rule) # Get Sample Points zzSG = grid.getPoints() zSG = np.sqrt(2) * zzSG # transform to N(0,1) wSG = grid.getQuadratureWeights() wSG /= np.sqrt(np.pi)**d0 # normalize weights n0 = grid.getNumPoints() n.append(n0) # # Sample input parameter # q0 = sample_q0(V, lmd, d0, zSG.T) J = sample_qoi(q0, dQ1) EJ = np.sum(wSG * J) VJ = np.sum(wSG * (J**2)) - EJ**2 mean.append(EJ) var.append(VJ) J_mc = np.load('data/j_%d_mc.npy' % (d0)) # Compute mean and variance mean_mc = np.mean(J_mc) var_mc = np.var(J_mc) # Plot mean error mean_err = [np.abs(mean[i] - mean_mc) for i in range(5)] ax1.loglog(n, mean_err, '.-.', label=r'$k=%d$' % (d0)) ax1.set_xlabel(r'$n$') ax1.set_ylabel(r'$\mathrm{Error}$') ax1.legend() fig1.tight_layout() # Plot variance error var_err = [np.abs(var[i] - var_mc) for i in range(5)] ax2.loglog(n, var_err, '.-.', label=r'k=%d' % (d0)) ax2.set_xlabel(r'$n$') ax2.set_ylabel(r'$\mathrm{Error}$') ax2.legend() fig2.tight_layout() fig1.savefig('fig/ex02_gauss_sg_mean_error.eps') fig2.savefig('fig/ex02_gauss_sg_var_error.eps')
def experiment05_conditioning(): """ Obtain an estimate of J using sparse grids on the coarse scale and MC as a correction. REMARKS: This takes very long, especially since the convergence rate of the conditional samples is low. """ # # Computational mesh # mesh = Mesh1D(resolution=(100, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() d = len(lmd) # Fix coarse truncation level d0 = 10 # # Build Sparse Grid # grid = TasmanianSG.TasmanianSparseGrid() dimensions = d0 outputs = 1 depth = 2 type = 'level' rule = 'gauss-hermite' grid.makeGlobalGrid(dimensions, outputs, depth, type, rule) # Sample Points zzSG = grid.getPoints() zSG = np.sqrt(2) * zzSG # transform to N(0,1) # Quadrature Weights wSG = grid.getQuadratureWeights() wSG /= np.sqrt(np.pi)**d0 # normalize weights # Number of grid points n0 = grid.getNumPoints() # # Sample low dimensional input parameter # q0 = sample_q0(V, lmd, d0, zSG.T) J0 = sample_qoi(q0, dQ1) # Compute sparse grid mean and variance EJ0 = np.sum(wSG * J0) VJ0 = np.sum(wSG * (J0**2)) - EJ0**2 J = np.load('data/j_mc.npy') mean_ref = np.mean(J) var_ref = np.var(J) # Record errors mean_err = [np.abs(EJ0 - mean_ref)] var_err = [np.abs(VJ0 - var_ref)] for n_samples in [10, 100, 1000]: mean_Jg0 = 0 var_Jg0 = 0 for i in range(n0): z = np.random.randn(d - d0, n_samples) qg0 = sample_q_given_q0(q0[:, i], V, lmd, d0, z) Jg0 = sample_qoi(qg0, dQ1) mean_Jg0 += wSG[i] * np.mean(Jg0) mean_err.append(np.abs(mean_Jg0 - mean_ref)) # Formatting plt.rc('text', usetex=True) # Figure sizes fs2 = (3, 2) fs1 = (4, 3) fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) ax.semilogy([0, 10, 100, 1000], mean_err, '.-') ax.set_xlabel(r'$n$') ax.set_ylabel(r'$\mathrm{Error}$') fig.tight_layout() fig.savefig('fig/ex02_gauss_hyb_mean_err.eps') """ # # Plot conditional variances # fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) ax.hist(varJg,bins=30, density=True) ax.set_xlabel(r'$\sigma_{J|q_0}^2$') fig.tight_layout() fig.savefig('fig/ex02_gauss_cond_var.eps') """ """
def experiment02_reference(): """ Convergence rate of MC """ generate = False # # Computational Mesh # mesh = Mesh1D(resolution=(100, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() d = len(lmd) # # Generate random sample for J # n_samples = 1000000 if generate: n_batches = 1000 batch_size = n_samples // n_batches J = np.empty(n_samples) for i in range(n_batches): # Sample diffusion coefficient z = np.random.randn(d, n_samples // n_batches) q = sample_q0(V, lmd, d, z) # Evaluate quantity of interest J[(i) * batch_size:(i + 1) * batch_size] = sample_qoi(q, dQ1) # Save current update to file np.save('./data/j_mc.npy', J) # # Process data # # Load MC samples J = np.load('data/j_mc.npy') # Compute sample mean and variance of J EX = np.mean(J) VarX = np.var(J) print(EX, VarX)
def experiment03_truncation(): """ Investigate the error in truncation level """ generate = False mesh = Mesh1D(resolution=(100, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() # # Basis # phi = Basis(dQ1, 'v') phi_x = Basis(dQ1, 'vx') # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() d = len(lmd) # Truncation levels truncation_levels = [1, 5, 10, 20, 50] n_samples = 1000000 if generate: n_batches = 1000 batch_size = n_samples // n_batches for d0 in truncation_levels: comment.tic('d = %d' % (d0)) J = np.empty(n_samples) for i in range(n_batches): # Print progress #print('.',end='') # Sample diffusion coefficient z = np.random.randn(d0, batch_size) q = sample_q0(V, lmd, d0, z) # Evaluate quantity of interest J[(i) * batch_size:(i + 1) * batch_size] = sample_qoi(q, dQ1) # Save current update to file np.save('./data/j_%d_mc.npy' % (d0), J) comment.toc() # # Compute estimates and errors # n_levels = len(truncation_levels) mean = [] var = [] for d0 in truncation_levels: J = np.load('data/j_%d_mc.npy' % (d0)) # Compute mean and variance mean.append(np.mean(J)) var.append(np.var(J)) # Load reference J = np.load('data/j_mc.npy') mean_ref = np.mean(J) var_ref = np.var(J) #truncation_levels.append(101) err_mean = [np.abs(mean[i] - mean_ref) for i in range(n_levels)] err_var = [np.abs(var[i] - var_ref) for i in range(n_levels)] # # Plots # # Formatting plt.rc('text', usetex=True) # Figure sizes fs2 = (3, 2) fs1 = (4, 3) # # Plot truncation error for mean and variance of J # fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) plt.semilogy(truncation_levels, err_mean, '.-', label='mean') plt.semilogy(truncation_levels, err_var, '.--', label='variance') plt.legend() ax.set_xlabel(r'$k$') ax.set_ylabel(r'$\mathrm{Error}$') plt.tight_layout() fig.savefig('fig/ex02_gauss_trunc_error.eps') # # Plot estimated mean and variance # fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) truncation_levels.append(101) mean.append(mean_ref) var.append(var_ref) plt.plot(truncation_levels, mean, 'k.-', label='mean') plt.plot(truncation_levels, var, 'k.--', label='variance') plt.legend() ax.set_xlabel(r'$k$') plt.tight_layout() fig.savefig('fig/ex02_gauss_trunc_stats.eps')
# ------------------------------------------------------------------------- g = M.dot(p + gamma * u_data)[dofs_inj] print(np.linalg.norm(g)) return f, g.ravel() # ============================================================================= # Mesh # ============================================================================= # Computational domain x_min = 0 x_max = 2 mesh = Mesh1D(box=[x_min, x_max], resolution=(512, )) # Mark Dirichlet Vertices mesh.mark_region('left', lambda x: np.abs(x) < 1e-9) mesh.mark_region('right', lambda x: np.abs(x - 2) < 1e-9) # # Finite element spaces # Q1 = QuadFE(mesh.dim(), 'Q1') # Dofhandler for state dh_y = DofHandler(mesh, Q1) dh_y.distribute_dofs() ny = dh_y.n_dofs()
def test_integrals_1d(self): """ Test system assembly """ # # Constant form # # Mesh mesh = Mesh1D(box=[1, 2], resolution=(1, )) # Kernel kernel = Kernel(Explicit(f=lambda x: x[:, 0], dim=1)) problem = Form(kernel) assembler = Assembler(problem, mesh=mesh) assembler.assemble() self.assertAlmostEqual(assembler.get_scalar(), 3 / 2) # # Linear forms (x,x) and (x,x') over [1,2] = 7/3, 3/2 # # Elements Q1 = QuadFE(mesh.dim(), 'Q1') Q2 = QuadFE(mesh.dim(), 'Q2') Q3 = QuadFE(mesh.dim(), 'Q3') # Dofhandlers dQ1 = DofHandler(mesh, Q1) dQ2 = DofHandler(mesh, Q2) dQ3 = DofHandler(mesh, Q3) # Distribute dofs [d.distribute_dofs() for d in [dQ1, dQ2, dQ3]] for dQ in [dQ1, dQ2, dQ3]: # Basis phi = Basis(dQ, 'u') phi_x = Basis(dQ, 'ux') # Kernel function xfn = Nodal(f=lambda x: x[:, 0], basis=phi) # Kernel kernel = Kernel(xfn) # Form problem = [[Form(kernel, test=phi)], [Form(kernel, test=phi_x)]] # Assembly assembler = Assembler(problem, mesh) assembler.assemble() # Check b^Tx = (x,x) b0 = assembler.get_vector(0) self.assertAlmostEqual(np.sum(b0 * xfn.data()[:, 0]), 7 / 3) b1 = assembler.get_vector(1) self.assertAlmostEqual(np.sum(b1 * xfn.data()[:, 0]), 3 / 2) # # Bilinear forms # # Compute (1,x,x) = 7/3, or (x^2, 1, 1) = 7/3 for dQ in [dQ1, dQ2, dQ3]: # Basis phi = Basis(dQ, 'u') phi_x = Basis(dQ, 'ux') # Kernel function x2fn = Explicit(f=lambda x: x[:, 0]**2, dim=1) xfn = Nodal(f=lambda x: x[:, 0], basis=phi) # Form problems = [[Form(1, test=phi, trial=phi)], [Form(Kernel(xfn), test=phi, trial=phi_x)], [Form(Kernel(x2fn), test=phi_x, trial=phi_x)]] # Assemble assembler = Assembler(problems, mesh) assembler.assemble() x = xfn.data()[:, 0] for i_problem in range(3): A = assembler.get_matrix(i_problem) self.assertAlmostEqual(x.T.dot(A.dot(x)), 7 / 3) # ====================================================================== # Test 1: Assemble simple bilinear form (u,v) on Mesh1D # ====================================================================== # Mesh mesh = Mesh1D(resolution=(1, )) Q1 = QuadFE(mesh.dim(), 'Q1') Q2 = QuadFE(mesh.dim(), 'Q2') Q3 = QuadFE(mesh.dim(), 'Q3') # Test and trial functions dhQ1 = DofHandler(mesh, QuadFE(1, 'Q1')) dhQ1.distribute_dofs() u = Basis(dhQ1, 'u') v = Basis(dhQ1, 'v') # Form form = Form(trial=u, test=v) # Define system system = Assembler(form, mesh) # Get local information cell = mesh.cells.get_child(0) si = system.shape_info(cell) # Compute local Gauss nodes xg, wg, phi, dofs = system.shape_eval(cell) self.assertTrue(cell in xg) self.assertTrue(cell in wg) # Compute local shape functions self.assertTrue(cell in phi) self.assertTrue(u in phi[cell]) self.assertTrue(v in phi[cell]) self.assertTrue(u in dofs[cell]) # Assemble system system.assemble() # Extract system bilinear form A = system.get_matrix() # Use bilinear form to integrate x^2 over [0,1] f = Nodal(lambda x: x, basis=u) fv = f.data()[:, 0] self.assertAlmostEqual(np.sum(fv * A.dot(fv)), 1 / 3) # ====================================================================== # Test 3: Constant form (x^2,.,.) over 1D mesh # ====================================================================== # Mesh mesh = Mesh1D(resolution=(10, )) # Nodal kernel function Q2 = QuadFE(1, 'Q2') dhQ2 = DofHandler(mesh, Q2) dhQ2.distribute_dofs() phiQ2 = Basis(dhQ2) f = Nodal(lambda x: x**2, basis=phiQ2) kernel = Kernel(f=f) # Form form = Form(kernel=kernel) # Generate and assemble the system system = Assembler(form, mesh) system.assemble() # Check self.assertAlmostEqual(system.get_scalar(), 1 / 3) # ===================================================================== # Test 4: Periodic Mesh # ===================================================================== # # TODO: NO checks yet # mesh = Mesh1D(resolution=(2, ), periodic=True) # Q1 = QuadFE(1, 'Q1') dhQ1 = DofHandler(mesh, Q1) dhQ1.distribute_dofs() u = Basis(dhQ1, 'u') form = Form(trial=u, test=u) system = Assembler(form, mesh) system.assemble() # ===================================================================== # Test 5: Assemble simple sampled form # ====================================================================== mesh = Mesh1D(resolution=(3, )) Q1 = QuadFE(1, 'Q1') dofhandler = DofHandler(mesh, Q1) dofhandler.distribute_dofs() phi = Basis(dofhandler) xv = dofhandler.get_dof_vertices() n_points = dofhandler.n_dofs() n_samples = 6 a = np.arange(n_samples) f = lambda x, a: a * x fdata = np.zeros((n_points, n_samples)) for i in range(n_samples): fdata[:, i] = f(xv, a[i]).ravel() # Define sampled function fn = Nodal(data=fdata, basis=phi) kernel = Kernel(fn) # # Integrate I[0,1] ax^2 dx by using the linear form (ax,x) # v = Basis(dofhandler, 'v') form = Form(kernel=kernel, test=v) system = Assembler(form, mesh) system.assemble() one = np.ones(n_points) for i in range(n_samples): b = system.get_vector(i_sample=i) self.assertAlmostEqual(one.dot(b), 0.5 * a[i]) # # Integrate I[0,1] ax^4 dx using bilinear form (ax, x^2, x) # Q2 = QuadFE(1, 'Q2') dhQ2 = DofHandler(mesh, Q2) dhQ2.distribute_dofs() u = Basis(dhQ2, 'u') # Define form form = Form(kernel=kernel, test=v, trial=u) # Define and assemble system system = Assembler(form, mesh) system.assemble() # Express x^2 in terms of trial function basis dhQ2.distribute_dofs() xvQ2 = dhQ2.get_dof_vertices() xv_squared = xvQ2**2 for i in range(n_samples): # # Iterate over samples # # Form sparse matrix A = system.get_matrix(i_sample=i) # Evaluate the integral I = np.sum(xv * A.dot(xv_squared)) # Compare with expected result self.assertAlmostEqual(I, 0.2 * a[i]) # ===================================================================== # Test 6: Working with submeshes # ===================================================================== mesh = Mesh1D(resolution=(2, ))
def test_shape_info(self): """ Test whether system extracts the correct information """ # # 1D # mesh = Mesh1D(resolution=(1, )) Q1 = QuadFE(1, 'Q1') dhQ1 = DofHandler(mesh, Q1) dhQ1.distribute_dofs() ux = Basis(dhQ1, 'ux') v = Basis(dhQ1, 'v') system = Assembler(Form(trial=ux, test=v), mesh) cell = mesh.cells.get_child(0) si = system.shape_info(cell) self.assertTrue(cell in si) self.assertTrue(ux in si[cell]) self.assertTrue(v in si[cell]) # # 2D # mesh = QuadMesh(resolution=(1, 1)) Q1 = QuadFE(2, 'Q1') Q2 = QuadFE(2, 'Q2') dhQ1 = DofHandler(mesh, Q1) dhQ1.distribute_dofs() dhQ2 = DofHandler(mesh, Q2) dhQ2.distribute_dofs() phiQ1 = Basis(dhQ1) phiQ2 = Basis(dhQ2) # Kernel f = Nodal(lambda x: x[:, 0] * x[:, 1], basis=phiQ2) g = Nodal(lambda x: x[:, 0] + x[:, 1], basis=phiQ1) F = lambda f, g: f - g kernel = Kernel([f, g], derivatives=['fx', 'g'], F=F) # Form defined over HalfEdge with flag 1 u = Basis(dhQ1, 'u') vx = Basis(dhQ2, 'vx') v = Basis(dhQ2, 'v') form_1 = Form(kernel, trial=u, test=vx, dmu='ds', flag=1) form_2 = Form(trial=u, test=v, dmu='dx', flag=2) problem = [form_1, form_2] # Assembler system = Assembler(problem, mesh) # Shape info on cell cell = mesh.cells.get_child(0) si = system.shape_info(cell) # Empty info dictionary (Cell hasn't been marked) self.assertEqual(si, {}) # Mark HalfEdge and cell and do it again he = cell.get_half_edge(0) he.mark(1) cell.mark(2) si = system.shape_info(cell) # Check that shape info contains the right stuff for region in [he, cell]: self.assertTrue(region in si) for basis in [u, vx]: self.assertTrue(basis in si[he]) for basis in [u, v]: self.assertTrue(basis in si[cell])
return np.sign(a) elif name == 'critical_approximation': if a <= -1: return -1 - 1 / a elif np.abs(a) <= 1: return 0 elif a >= 1: return 1 - 1 / a # Parameters eps = 1e-3 a = 1 # Computational mesh mesh = Mesh1D(resolution=(200, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-9, entity_type='vertex') mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-9, entity_type='vertex') # Element element = QuadFE(1, 'Q1') dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() # Kernels k_eps = SUPGKernel(Constant(-eps), Constant(a), eps) k_a = SUPGKernel(Constant(a), Constant(a), eps) # Forms u = Basis(dofhandler, 'u') ux = Basis(dofhandler, 'ux')
def experiment06_sensitivity_stats(): """ Compute the sensitivities """ comment = Verbose() comment.comment('Computing statistics for the sensitivity dJ_dq') # # Computational mesh # mesh = Mesh1D(resolution=(100, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() n_dofs = dQ1.n_dofs() phi = Basis(dQ1, 'u') # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() d = len(lmd) # Fix coarse truncation level d0 = 10 # # Build Sparse Grid # grid = TasmanianSG.TasmanianSparseGrid() dimensions = d0 outputs = 1 depth = 4 type = 'level' rule = 'gauss-hermite' grid.makeGlobalGrid(dimensions, outputs, depth, type, rule) # Sample Points zzSG = grid.getPoints() zSG = np.sqrt(2) * zzSG # transform to N(0,1) # Quadrature Weights wSG = grid.getQuadratureWeights() wSG /= np.sqrt(np.pi)**d0 # normalize weights # Number of grid points n0 = grid.getNumPoints() comment.comment('Element DOFs: {0}'.format(n_dofs)) comment.comment('Sparse Grid Size: {0}'.format(n0)) # # Sample low dimensional input parameter # comment.tic('Sampling reference') q0 = sample_q0(V, lmd, d0, zSG.T) J0, u0 = sample_qoi(q0, dQ1, return_state=True) comment.toc() comment.tic('Sampling gradient') dJdq = np.zeros((n_dofs, n0)) for i in range(n0): # Sample input and state q = Nodal(data=q0[:, i], basis=phi) u = Nodal(data=u0[:, i], basis=phi) # Compute gradient using adjoint approach dJdq[:, i] = dJdq_adj(q, u) comment.toc() # Compute sparse grid mean and variance E_dJ = np.dot(dJdq, wSG) V_dJ = np.dot(dJdq**2, wSG) - E_dJ**2 E_dJ = Nodal(data=E_dJ, basis=phi) V_dJ = Nodal(data=V_dJ, basis=phi) fig, ax = plt.subplots(nrows=1, ncols=2) plot = Plot(quickview=False) ax[0] = plot.line(E_dJ, axis=ax[0]) ax[1] = plot.line(V_dJ, axis=ax[1]) plt.show()
def test_constructor(self): # ===================================================================== # Test 1D # ===================================================================== # # Kernel consists of a single explicit Function: # f1 = lambda x: x+2 f = Explicit(f1, dim=1) k = Kernel(f) x = np.linspace(0,1,100) n_points = len(x) # Check that it evaluates correctly. self.assertTrue(np.allclose(f1(x), k.eval(x).ravel())) # Check shape of kernel self.assertEqual(k.eval(x).shape, (n_points,1)) # # Kernel consists of a combination of two explicit functions # f1 = Explicit(lambda x: x+2, dim=1) f2 = Explicit(lambda x: x**2 + 1, dim=1) F = lambda f1, f2: f1**2 + f2 f_t = lambda x: (x+2)**2 + x**2 + 1 k = Kernel([f1,f2], F=F) # Check evaluation self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel())) # Check shape self.assertEqual(k.eval(x).shape, (n_points,1)) # # Same thing as above, but with nodal functions # mesh = Mesh1D(resolution=(1,)) Q1 = QuadFE(1,'Q1') Q2 = QuadFE(1,'Q2') dQ1 = DofHandler(mesh,Q1) dQ2 = DofHandler(mesh,Q2) # Distribute dofs [dQ.distribute_dofs() for dQ in [dQ1,dQ2]] # Basis functions phi1 = Basis(dQ1,'u') phi2 = Basis(dQ2,'u') f1 = Nodal(lambda x: x+2, basis=phi1) f2 = Nodal(lambda x: x**2 + 1, basis=phi2) k = Kernel([f1,f2], F=F) # Check evaluation self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel())) # # Replace f2 above with its derivative # k = Kernel([f1,f2], derivatives=['f', 'fx'], F=F) f_t = lambda x: (x+2)**2 + 2*x # Check derivative evaluation F = F(f1, df2_dx) self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel())) # # Sampling # one = Constant(1) f1 = Explicit(lambda x: x**2 + 1, dim=1) # Sampled function a = np.linspace(0,1,11) n_samples = len(a) # Define Dofhandler dh = DofHandler(mesh, Q2) dh.distribute_dofs() dh.set_dof_vertices() xv = dh.get_dof_vertices() n_dofs = dh.n_dofs() phi = Basis(dh, 'u') # Evaluate parameterized function at mesh dof vertices f2_m = np.empty((n_dofs, n_samples)) for i in range(n_samples): f2_m[:,i] = xv.ravel() + a[i]*xv.ravel()**2 f2 = Nodal(data=f2_m, basis=phi) # Define kernel F = lambda f1, f2, one: f1 + f2 + one k = Kernel([f1,f2,one], F=F) # Evaluate on a fine mesh x = np.linspace(0,1,100) n_points = len(x) self.assertEqual(k.eval(x).shape, (n_points, n_samples)) for i in range(n_samples): # Check evaluation self.assertTrue(np.allclose(k.eval(x)[:,i], f1.eval(x)[:,i] + x + a[i]*x**2+ 1)) # # Sample multiple constant functions # f1 = Constant(data=a) f2 = Explicit(lambda x: 1 + x**2, dim=1) f3 = Nodal(data=f2_m[:,-1], basis=phi) F = lambda f1, f2, f3: f1 + f2 + f3 k = Kernel([f1,f2,f3], F=F) x = np.linspace(0,1,100) for i in range(n_samples): self.assertTrue(np.allclose(k.eval(x)[:,i], \ a[i] + f2.eval(x)[:,i] + f3.eval(x)[:,i])) # # Submeshes # mesh = Mesh1D(resolution=(1,)) mesh_labels = Tree(regular=False) mesh = Mesh1D(resolution=(1,)) Q1 = QuadFE(1,'Q1') Q2 = QuadFE(1,'Q2') dQ1 = DofHandler(mesh,Q1) dQ2 = DofHandler(mesh,Q2) # Distribute dofs [dQ.distribute_dofs() for dQ in [dQ1,dQ2]] # Basis p1 = Basis(dQ1) p2 = Basis(dQ2) f1 = Nodal(lambda x: x, basis=p1) f2 = Nodal(lambda x: -2+2*x**2, basis=p2) one = Constant(np.array([1,2])) F = lambda f1, f2, one: 2*f1**2 + f2 + one I = mesh.cells.get_child(0) kernel = Kernel([f1,f2, one], F=F) rule1D = GaussRule(5,shape='interval') x = I.reference_map(rule1D.nodes())
def test06_linearization(): """ Compute samples on fine grid via the linearization """ plot = Plot() # # Computational mesh # mesh = Mesh1D(resolution=(100, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() nx = dQ1.n_dofs() x = dQ1.get_dof_vertices() Q3 = QuadFE(mesh.dim(), 'Q3') dQ3 = DofHandler(mesh, Q3) dQ3.distribute_dofs() # # Basis # phi = Basis(dQ1, 'u') phi_x = Basis(dQ1, 'ux') psi = Basis(dQ3, 'u') psi_x = Basis(dQ3, 'ux') # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() d = len(lmd) # Fix coarse truncation level d0 = 10 # # Build Sparse Grid # grid = TasmanianSG.TasmanianSparseGrid() dimensions = d0 outputs = 1 depth = 2 type = 'level' rule = 'gauss-hermite' grid.makeGlobalGrid(dimensions, outputs, depth, type, rule) # Sample Points zzSG = grid.getPoints() zSG = np.sqrt(2) * zzSG # transform to N(0,1) # Quadrature Weights wSG = grid.getQuadratureWeights() wSG /= np.sqrt(np.pi)**d0 # normalize weights # Number of grid points n0 = grid.getNumPoints() # # Sample low dimensional input parameter # q0 = sample_q0(V, lmd, d0, zSG.T) J0 = sample_qoi(q0, dQ1) # # Sample conditional expectation # # Pick a single coarse sample to check i0 = np.random.randint(0, high=n0) # Sample fine, conditional on coarse n_samples = 1 z1 = np.random.randn(d - d0, n_samples) q = sample_q_given_q0(q0[:, i0], V, lmd, d0, z1) # Perturbation log_qref = np.log(q0[:, i0]) dlog_q = np.log(q.ravel()) - log_qref dlog_qfn = Nodal(data=dlog_q, basis=phi) # Perturbed q n_eps = 12 # Number of refinements epsilons = [10**(-l) for l in range(n_eps)] log_qper = np.empty((nx, n_eps)) for i in range(n_eps): log_qper[:, i] = log_qref + epsilons[i] * dlog_q """ plt.plot(x, log_qref, label='ref') for i in range(n_eps): plt.plot(x, log_qper[:,i],label='%d'%(i)) """ assert np.allclose(log_qper[:, 0], np.log(q.ravel())) plt.legend() plt.show() # Define finite element function exp_qref = Nodal(data=q0[:, i0], basis=phi) exp_qper = Nodal(data=np.exp(log_qper), basis=phi) # # PDEs # # 1. State Equation state_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(1, test=phi)] state_dbc = {'left': 0, 'right': 1} # 2. Perturbed Equation perturbed_eqn = [ Form(exp_qper, test=phi_x, trial=phi_x), Form(1, test=phi) ] perturbed_dbc = {'left': 0, 'right': 1} # 3. Adjoint Equation adjoint_eqn = [Form(exp_qref, test=psi_x, trial=psi_x), Form(0, test=psi)] adjoint_dbc = {'left': 0, 'right': -1} # Combine eqns = [state_eqn, perturbed_eqn, adjoint_eqn] bcs = [state_dbc, perturbed_dbc, adjoint_dbc] # # Assembly # assembler = Assembler(eqns, n_gauss=(6, 36)) # Boundary conditions for i, bc in zip(range(3), bcs): for loc, val in bc.items(): assembler.add_dirichlet(loc, val, i_problem=i) # Assemble assembler.assemble() # # Solve # # Solve state ur = assembler.solve(i_problem=0) u_ref = Nodal(data=ur, basis=phi) ux_ref = Nodal(data=ur, basis=phi_x) # Solve perturbed state u_per = Nodal(basis=phi) for i in range(n_eps): # FEM solution up = assembler.solve(i_problem=1, i_matrix=i) u_per.add_samples(up) plt.plot(x, up - ur) plt.show() ux_per = Nodal(data=u_per.data(), basis=phi_x) # Solve adjoint equation v = assembler.solve(i_problem=2) v_adj = Nodal(data=v, basis=psi) vx_adj = Nodal(data=v, basis=psi_x) # # Sensitivity # # Sensitivity Equation ker_sen = Kernel(f=[exp_qref, dlog_qfn, ux_ref], F=lambda eq, dq, ux: -eq * dq * ux) sensitivity_eqn = [ Form(exp_qref, test=phi_x, trial=phi_x), Form(ker_sen, test=phi_x) ] sensitivity_dbc = {'left': 0, 'right': 0} assembler = Assembler(sensitivity_eqn, n_gauss=(6, 36)) for loc in sensitivity_dbc: assembler.add_dirichlet(loc, sensitivity_dbc[loc]) assembler.assemble() s = assembler.solve() sx = Nodal(data=s, basis=phi_x) plt.plot(x, s) plt.show() # # Quantities of Interest # # Reference k_ref = Kernel(f=[exp_qref, ux_ref], F=lambda eq, ux: eq * ux) ref_qoi = [Form(k_ref, dmu='dv', flag='right')] # Perturbed k_per = Kernel(f=[exp_qper, ux_per], F=lambda eq, ux: eq * ux) per_qoi = [Form(k_per, dmu='dv', flag='right')] # Adjoint k_adj = Kernel(f=[exp_qref, dlog_qfn, ux_ref, vx_adj], F=lambda eq, dq, ux, vx: -eq * dq * ux * vx) adj_qoi = [Form(k_adj)] # Sensitivity k_sens = Kernel(f=[exp_qref, dlog_qfn, ux_ref, sx], F=lambda eq, dq, ux, sx: eq * dq * ux + eq * sx) sens_qoi = Form(k_sens, dmu='dv', flag='right') qois = [ref_qoi, per_qoi, adj_qoi, sens_qoi] # Assemble assembler = Assembler(qois, mesh=mesh) assembler.assemble() # Evaluate J_ref = assembler.get_scalar(0) J_per = [] for i in range(n_eps): J_per.append(assembler.get_scalar(1, i)) # Finite difference approximation dJ = [] for eps, J_p in zip(epsilons, J_per): dJ.append((J_p - J_ref) / eps) # Adjoint differential dJ_adj = assembler.get_scalar(2) # Sensitivity differential dJ_sen = assembler.get_scalar(3) print(dJ_adj) print(dJ_sen) print(dJ) """
pp = A[1,:] - Q.dot(Q.T.dot(A[1,:])) print(pp) print('R\n',R) print(A.dot(V)) Q,R = linalg.qr(A, mode='economic') r = np.diag(R) print(len(r[np.abs(r)>1e-13])) print(Q,'\n',R) ''' print("TasmanianSG version: {0:s}".format(TasmanianSG.__version__)) print("TasmanianSG license: {0:s}".format(TasmanianSG.__license__)) mesh = Mesh1D(resolution=(2, )) element = QuadFE(mesh.dim(), 'Q1') dofhandler = DofHandler(mesh, element) phi_x = Basis(dofhandler, 'ux') problems = [Form(1, test=phi_x, trial=phi_x)] assembler = Assembler(problems, mesh) assembler.assemble() A = assembler.af[0]['bilinear'].get_matrix() n = dofhandler.n_dofs() b = np.ones((n, 1)) mesh.mark_region('left', lambda x: np.abs(x) < 1e-9) mesh.mark_region('right', lambda x: np.abs(1 - x) < 1e-9)
def test01_finite_elements(): """ Test accuracy of the finite element approximation """ # # Construct reference solution # plot = Plot(quickview=False) # Mesh mesh = Mesh1D(resolution=(2**11, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # Element Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() # Basis phi = Basis(dQ1, 'v') phi_x = Basis(dQ1, 'vx') # # Covariance # cov = Covariance(dQ1, name='gaussian', parameters={'l': 0.05}) cov.compute_eig_decomp() lmd, V = cov.get_eig_decomp() d = len(lmd) # # Sample and plot full dimensional parameter and solution # n_samples = 1 z = np.random.randn(d, n_samples) q_ref = sample_q0(V, lmd, d, z) print(q_ref.shape) # Define finite element function q_ref_fn = Nodal(data=q_ref, basis=phi) problem = [[Form(q_ref_fn, test=phi_x, trial=phi_x), Form(1, test=phi)], [Form(q_ref_fn, test=phi_x, dmu='dv', flag='right')]] # Define assembler assembler = Assembler(problem) # Incorporate Dirichlet conditions assembler.add_dirichlet('left', 0) assembler.add_dirichlet('right', 1) # Assemble system assembler.assemble() # Solve system u_ref = assembler.solve() # Compute quantity of interest J_ref = u_ref.dot(assembler.get_vector(1)) # Plot fig = plt.figure(figsize=(6, 4)) ax = fig.add_subplot(111) u_ref_fn = Nodal(basis=phi, data=u_ref) ax = plot.line(u_ref_fn, axis=ax) n_levels = 10 J = np.zeros(n_levels) for l in range(10): comment.comment('level: %d' % (l)) # # Mesh # mesh = Mesh1D(resolution=(2**l, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() # # Basis # phi = Basis(dQ1, 'v') phi_x = Basis(dQ1, 'vx') # Define problem problem = [[ Form(q_ref_fn, test=phi_x, trial=phi_x), Form(1, test=phi) ], [Form(q_ref_fn, test=phi_x, dmu='dv', flag='right')]] assembler = Assembler(problem) # Incorporate Dirichlet conditions assembler.add_dirichlet('left', 0) assembler.add_dirichlet('right', 1) assembler.assemble() A = assembler.get_matrix() print('A shape', A.shape) u = assembler.solve() J[l] = u.dot(assembler.get_vector(1)) print(u.shape) print(phi.n_dofs()) ufn = Nodal(basis=phi, data=u) ax = plot.line(ufn, axis=ax) plt.show() # # Plots # # Formatting plt.rc('text', usetex=True) # Figure sizes fs2 = (3, 2) fs1 = (4, 3) print(J_ref) print(J) # # Plot truncation error for mean and variance of J # fig = plt.figure(figsize=fs2) ax = fig.add_subplot(111) err = np.array([np.abs(J[i] - J_ref) for i in range(n_levels)]) h = np.array([2**(-l) for l in range(n_levels)]) plt.loglog(h, err, '.-') ax.set_xlabel(r'$h$') ax.set_ylabel(r'$|J-J^h|$') plt.tight_layout() fig.savefig('fig/ex02_gauss_fem_error.eps')
def test_subsample_deterministic(self): """ When evaluating a deterministic function while specifying a subsample, n_subsample copies of the function output should be returned. """ # # Deterministic functions # # Functions fns = { 1: { 1: lambda x: x[:, 0]**2, 2: lambda x, y: x[:, 0] + y[:, 0] }, 2: { 1: lambda x: x[:, 0]**2 + x[:, 1]**2, 2: lambda x, y: x[:, 0] * y[:, 0] + x[:, 1] * y[:, 1] } } # Singletons x = {1: {1: 2, 2: (3, 4)}, 2: {1: (1, 2), 2: ((1, 2), (3, 4))}} xv = { 1: { 1: [(2, ), (2, )], 2: ([(3, ), (3, )], [(4, ), (4, )]) }, 2: { 1: [(1, 2), (1, 2)], 2: ([(1, 2), (1, 2)], [(3, 4), (3, 4)]) } } vals = {1: {1: 4, 2: 7}, 2: {1: 5, 2: 11}} subsample = np.array([2, 3], dtype=np.int) for dim in [1, 2]: # # Iterate over dimension # # DofHandler if dim == 1: mesh = Mesh1D(box=[0, 5], resolution=(1, )) elif dim == 2: mesh = QuadMesh(box=[0, 5, 0, 5]) element = QuadFE(dim, 'Q2') dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() basis = Basis(dofhandler) for n_variables in [1, 2]: # # Iterate over number of variables # # # Explicit # f = fns[dim][n_variables] # Explicit fe = Explicit(f, n_variables=n_variables, dim=dim, \ subsample=subsample) # Nodal fn = Nodal(f, n_variables=n_variables, basis=basis, dim=dim, \ dofhandler=dofhandler, subsample=subsample) # Constant fc = Constant(1, n_variables=n_variables, \ subsample=subsample) # Singleton input xn = x[dim][n_variables] # Explicit self.assertEqual(fe.eval(xn).shape[1], len(subsample)) self.assertEqual(fe.eval(xn)[0, 0], vals[dim][n_variables]) self.assertEqual(fe.eval(xn)[0, 1], vals[dim][n_variables]) # Nodal self.assertEqual(fn.eval(xn).shape[1], len(subsample)) self.assertAlmostEqual( fn.eval(xn)[0, 0], vals[dim][n_variables]) self.assertAlmostEqual( fn.eval(xn)[0, 1], vals[dim][n_variables]) # Constant self.assertEqual(fc.eval(xn).shape[1], len(subsample)) self.assertAlmostEqual(fc.eval(xn)[0, 0], 1) self.assertAlmostEqual(fc.eval(xn)[0, 1], 1) # Vector input xn = xv[dim][n_variables] n_points = 2 # Explicit self.assertEqual(fe.eval(xn).shape, (2, 2)) for i in range(fe.n_subsample()): for j in range(n_points): self.assertEqual( fe.eval(xn)[i][j], vals[dim][n_variables]) # Nodal self.assertEqual(fn.eval(xn).shape, (2, 2)) for i in range(fe.n_subsample()): for j in range(n_points): self.assertAlmostEqual( fn.eval(xn)[i][j], vals[dim][n_variables]) # Constant self.assertEqual(fc.eval(xn).shape, (2, 2)) for i in range(fe.n_subsample()): for j in range(n_points): self.assertEqual(fc.eval(xn)[i][j], 1)
def test02_sensitivity(): """ Check that the sensitivity calculation works. Compare J(q+eps*dq) - J(q) ~= eps*dJ^T dq """ # # Mesh # mesh = Mesh1D(resolution=(20, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q = QuadFE(mesh.dim(), 'Q3') dQ = DofHandler(mesh, Q) dQ.distribute_dofs() nx = dQ.n_dofs() x = dQ.get_dof_vertices() # # Basis # phi = Basis(dQ, 'v') phi_x = Basis(dQ, 'vx') # # Parameters # # Reference q q_ref = np.zeros(nx) # Perturbation dq = np.ones(nx) # Perturbed q n_eps = 10 # Number of refinements epsilons = [10**(-l) for l in range(n_eps)] q_per = np.empty((nx, n_eps)) for i in range(n_eps): q_per[:, i] = q_ref + epsilons[i] * dq # Define finite element function exp_qref = Nodal(data=np.exp(q_ref), basis=phi) exp_qper = Nodal(data=np.exp(q_per), basis=phi) # # PDEs # # 1. State Equation state_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(1, test=phi)] state_dbc = {'left': 0, 'right': 1} # 2. Perturbed Equation perturbed_eqn = [ Form(exp_qper, test=phi_x, trial=phi_x), Form(1, test=phi) ] perturbed_dbc = {'left': 0, 'right': 1} # 3. Adjoint Equation adjoint_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(0, test=phi)] adjoint_dbc = {'left': 0, 'right': -1} # Combine eqns = [state_eqn, perturbed_eqn, adjoint_eqn] bcs = [state_dbc, perturbed_dbc, adjoint_dbc] # # Assembly # assembler = Assembler(eqns) # Boundary conditions for i, bc in zip(range(3), bcs): for loc, val in bc.items(): assembler.add_dirichlet(loc, val, i_problem=i) # Assemble assembler.assemble() # # Solve # # Solve state ur = assembler.solve(i_problem=0) u_ref = Nodal(data=ur, basis=phi) ux_ref = Nodal(data=ur, basis=phi_x) # Solve perturbed state u_per = Nodal(basis=phi) ue_per = Nodal(basis=phi) for i in range(n_eps): # FEM solution up = assembler.solve(i_problem=1, i_matrix=i) u_per.add_samples(up) # Exact perturbed solution eps = epsilons[i] ue_per.add_samples(0.5 * np.exp(-eps) * (x - x**2) + x) ux_per = Nodal(data=u_per.data(), basis=phi_x) # Solve adjoint equation v = assembler.solve(i_problem=2) v_adj = Nodal(data=v, basis=phi) vx_adj = Nodal(data=v, basis=phi_x) # # Check against exact solution # ue = -0.5 * x**2 + 1.5 * x ve = -x assert np.allclose(ue, u_ref.data()) assert np.allclose(ve, v_adj.data()) assert np.allclose(ue_per.data(), u_per.data()) # # Quantities of Interest # # Reference k_ref = Kernel(f=[exp_qref, ux_ref], F=lambda eq, ux: eq * ux) ref_qoi = [Form(k_ref, dmu='dv', flag='right')] # Perturbed k_per = Kernel(f=[exp_qper, ux_per], F=lambda eq, ux: eq * ux) per_qoi = [Form(k_per, dmu='dv', flag='right')] # Adjoint k_adj = Kernel(f=[exp_qref, ux_ref, vx_adj], F=lambda eq, ux, vx: -eq * ux * vx) adj_qoi = [Form(k_adj, test=phi)] qois = [ref_qoi, per_qoi, adj_qoi] # Assemble assembler = Assembler(qois) assembler.assemble() # Evaluate J_ref = assembler.get_scalar(0) J_per = [] for i in range(n_eps): J_per.append(assembler.get_scalar(1, i)) # Finite difference approximation dJ = [] for eps, J_p in zip(epsilons, J_per): dJ.append((J_p - J_ref) / eps) # Adjoint differential dJ_adj = assembler.get_vector(2).dot(dq) # # Check against exact qois # # Check reference sol Je_ref = 0.5 assert np.allclose(Je_ref, J_ref) # Check perturbed cost Je_per = -0.5 + np.exp(np.array(epsilons)) assert np.allclose(Je_per, J_per) # Check derivative by the adjoint equation dJdq = 1 assert np.allclose(dJ_adj, dJdq)
def test_eval_x(self): # # Evaluate Nodal function at a given set of x-values # # Meshes and elements meshes = {1: Mesh1D(resolution=(2, )), 2: QuadMesh(resolution=(2, 1))} elements = {1: QuadFE(1, 'Q2'), 2: QuadFE(2, 'Q2')} # Use function to set data fns = { 1: { 1: lambda x: 2 * x[:, 0]**2, 2: lambda x, y: 2 * x[:, 0] + 2 * y[:, 0] }, 2: { 1: lambda x: x[:, 0]**2 + x[:, 1], 2: lambda x, y: x[:, 0] * y[:, 0] + x[:, 1] * y[:, 1] } } # n_samples = 2 parms = {1: {1: [{}, {}], 2: [{}, {}]}, 2: {1: [{}, {}], 2: [{}, {}]}} n_points = 1 for dim in [1, 2]: mesh = meshes[dim] element = elements[dim] dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() #dofhandler.get_region_dofs() basis = Basis(dofhandler) # # Define random points in domain # if dim == 1: x_min, x_max = mesh.bounding_box() x = x_min + 0.5 * (x_max - x_min) * np.random.rand(n_points) x = x[:, np.newaxis] y = x_min + (x_max - x_min) * np.random.rand(n_points) y = y[:, np.newaxis] elif dim == 2: x_min, x_max, y_min, y_max = mesh.bounding_box() x = np.zeros((n_points, 2)) x[:, 0] = x_min + (x_max - x_min) * np.random.rand(n_points) x[:, 1] = y_min + (y_max - y_min) * np.random.rand(n_points) y = np.zeros((n_points, 2)) y[:, 0] = x_min + (x_max - x_min) * np.random.rand(n_points) y[:, 1] = y_min + (y_max - y_min) * np.random.rand(n_points) for n_variables in [1, 2]: fn = fns[dim][n_variables] parm = parms[dim][n_variables] # # Deterministic # f = Nodal(f=fn, basis=basis, mesh=mesh, element=element, dim=dim, n_variables=n_variables) if n_variables == 1: xx = x fe = fn(x) elif n_variables == 2: xx = (x, y) fe = fn(*xx) fx = f.eval(x=xx) self.assertTrue(np.allclose(fx, fe)) # # Sampled # f = Nodal(f=fn, parameters=parm, basis=basis, mesh=mesh, element=element, dim=dim, n_variables=n_variables) self.assertEqual(f.n_samples(), 2) fx = f.eval(x=xx) self.assertTrue(np.allclose(fx[:, 0], fe)) self.assertTrue(np.allclose(fx[:, 1], fe))
return f, g, y, p # ============================================================================= # Variational Form # ============================================================================= comment = Verbose() # # Mesh # # Computational domain x_min = 0 x_max = 2 mesh = Mesh1D(box=[x_min, x_max], resolution=(100, )) # Mark Dirichlet Vertices mesh.mark_region('left', lambda x: np.abs(x) < 1e-9) mesh.mark_region('right', lambda x: np.abs(x - 2) < 1e-9) # # Finite element spaces # Q1 = QuadFE(mesh.dim(), 'Q1') # Dofhandler for state dh = DofHandler(mesh, Q1) dh.distribute_dofs() m = dh.n_dofs() dh.set_dof_vertices()