def test_set_parameters(self): # Define explicit function rule = lambda x, a: a * x[:, 0] - x[:, 1] parms = [{'a': 1}, {'a': 2}] f = Explicit(rule, parameters=parms, dim=2) x = (1, 2) self.assertTrue(np.allclose(f.eval(x), np.array([-1, 0]))) # Modify parameter f.set_parameters({'a': 2}, pos=0) self.assertTrue(np.allclose(f.eval(x), np.array([0, 0])))
def test_constructor(self): """ Test initialization """ f = Explicit(lambda x, a: a * x**2, parameters={'a': 1}, dim=1, n_variables=1) f.eval(1) self.assertAlmostEqual(f.eval(1), 1) # # Errors # self.assertRaises(Exception, Explicit)
def test_add_rules(self): # Define explicit function rule = lambda x, a: a * x**2 parameters = [{'a': 1}, {'a': 2}] f = Explicit(rule, parameters=parameters, dim=1) # Raises an error attempt to add multiple functions self.assertRaises(Exception, f.add_rule, *(lambda x: x, ), **{'parameters': [{}, {}]}) # Add a single rule and evaluate at a point f.add_rule(lambda x: x) x = 2 vals = [4, 8, 2] for i in range(3): #(*(x,),**{'a':1})) self.assertEqual(f.eval(x)[0, i], vals[i])
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 test_eval(self): # # Evaluate single univariate/bivariate functions in 1 or 2 dimensions # fns = { 1: { 1: lambda x: x**2, 2: lambda x, y: x + y }, 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))}} vals = {1: {1: 4, 2: 7}, 2: {1: 5, 2: 11}} for dim in [1, 2]: # # Iterate over dimension # for n_variables in [1, 2]: # # Iterate over number of variables # fn = fns[dim][n_variables] f = Explicit(fn, n_variables=n_variables, dim=dim) xn = x[dim][n_variables] self.assertEqual(f.eval(xn), vals[dim][n_variables]) # # Evaluate sampled functions # fns = { 1: { 1: lambda x, a: a * x**2, 2: lambda x, y, a: a * (x + y) }, 2: { 1: lambda x, a: a * (x[:, 0]**2 + x[:, 1]**2), 2: lambda x, y, a: a * (x[:, 0] * y[:, 0] + x[:, 1] * y[:, 1]) } } pars = [{'a': 1}, {'a': 2}] # # Singletons # x = {1: {1: 2, 2: (3, 4)}, 2: {1: (1, 2), 2: ((1, 2), (3, 4))}} vals = {1: {1: 4, 2: 7}, 2: {1: 5, 2: 11}} for dim in [1, 2]: # # Iterate over dimension # for n_variables in [1, 2]: # # Iterate over number of variables # fn = fns[dim][n_variables] f = Explicit(fn, parameters=pars, n_variables=n_variables, dim=dim) xn = x[dim][n_variables] self.assertEqual(f.eval(xn)[0][0], vals[dim][n_variables]) self.assertEqual(f.eval(xn)[0][1], 2 * vals[dim][n_variables]) # # 2 points # n_points = 2 x = { 1: { 1: [(2, ), (2, )], 2: ([(3, ), (3, )], [(4, ), (4, )]) }, 2: { 1: [(1, 2), (1, 2)], 2: ([(1, 2), (1, 2)], [(3, 4), (3, 4)]) } } for dim in [1, 2]: # # Iterate over dimension # for n_variables in [1, 2]: # # Iterate over number of variables # fn = fns[dim][n_variables] f = Explicit(fn, parameters=pars, n_variables=n_variables, dim=dim) xn = x[dim][n_variables] self.assertEqual(f.eval(xn).shape[0], n_points) self.assertEqual(f.eval(xn).shape[1], f.n_samples()) for i in range(f.n_samples()): for j in range(2): val = pars[i]['a'] * vals[dim][n_variables] self.assertEqual(f.eval(xn)[j, i], val)
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 reference_solution(): """ Use sparse grid method to compute a benchmark solution """ mesh = QuadMesh(resolution=(10,10)) mesh.mark_region('boundary', lambda x,y:True, entity_type='half_edge', on_boundary=True) element = QuadFE(mesh.dim(), 'Q1') dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() n = dofhandler.n_dofs() phi = Basis(dofhandler, 'u') phi_x = Basis(dofhandler, 'ux') phi_y = Basis(dofhandler, 'uy') yd_fn = Explicit(lambda x: np.sin(2*np.pi*x[:,0])*np.sin(2*np.pi*x[:,1]),dim=2) g = np.ones((n,1)) # # Random diffusion coefficient # # Sparse grid tasmanian_library="/home/hans-werner/bin/TASMANIAN-6.0/libtasmaniansparsegrid.so" grid = TasmanianSG.TasmanianSparseGrid(tasmanian_library=tasmanian_library) dimensions = 4 outputs = 1 depth = 4 type = 'tensor' rule = 'gauss-legendre' grid.makeGlobalGrid(dimensions, outputs, depth, type, rule) Y = grid.getPoints() w = grid.getQuadratureWeights() n_samples = grid.getNumPoints() x = dofhandler.get_dof_vertices() a_nodal = 1 + 0.1*(np.outer(np.cos(np.pi*x[:,1]),Y[:,0])+\ np.outer(np.cos(np.pi*x[:,0]),Y[:,1])+\ np.outer(np.sin(2*np.pi*x[:,1]),Y[:,2])+\ np.outer(np.sin(2*np.pi*x[:,0]),Y[:,3])) a = Nodal(data=a_nodal, dofhandler=dofhandler) yd_vec = yd_fn.eval(x) problems = [[Form(a, test=phi_x, trial=phi_x), Form(a, test=phi_y, trial=phi_y)], [Form(1, test=phi, trial=phi)]] assembler = Assembler(problems, mesh) assembler.assemble() A = assembler.af[0]['bilinear'].get_matrix() M = assembler.af[1]['bilinear'].get_matrix() state = LS(phi) state.add_dirichlet_constraint('boundary') adjoint = LS(phi) adjoint.add_dirichlet_constraint('boundary') tau = 10 k_max = 20 alpha = 0.1 u = np.zeros((n,1)) norm_dJ_iter = [] J_iter = [] u_iter = [] for k in range(k_max): print('iteration', k) # # Compute average cost and gradient # dJ = np.zeros((n,1)) J = 0 print('sampling') for n in range(n_samples): print(n) yn, pn, Jn, dJn = cost_gradient(state,adjoint,A[n],M, g,u,yd_vec,alpha) J += w[n]*Jn dJ += w[n]*dJn print('') norm_dJ = np.sqrt(dJ.T.dot(M.dot(dJ))) # # Store current iterates # norm_dJ_iter.append(norm_dJ) J_iter.append(J) u_iter.append(u) # # Check for convergence # if norm_dJ<1e-8: break # # Update iterate # u -= tau*dJ
# ----------------------------------------------------------------------------- # Observations # ----------------------------------------------------------------------------- # Determine vertices corresponding to production wells n_prod = 4 h = (x_max-x_min)/(n_prod+2) x_prod = np.array([(i+1)*h for i in range(n_prod)]) v = dh_y.get_dof_vertices() dofs_prod = [] for x in x_prod: dofs_prod.append(np.argmin(abs(v-x))) # # Target pressure at production wells # z_fn = Explicit(f=lambda x: 3-4*(x[:,0]-1)**2, dim=1, mesh=mesh) z_data = z_fn.eval(v[dofs_prod]) # ----------------------------------------------------------------------------- # Control # ----------------------------------------------------------------------------- # Determine the vertices corresponding to the injection wells n_inj = 6 h = (x_max-x_min)/(n_inj+2) x_inj = np.array([(i+1)*h for i in range(n_inj)]) dofs_inj = [] for x in x_inj: dofs_inj.append(np.argmin(abs(v-x))) u_data = np.zeros((ny,1)) u_data[dofs_inj] = 1 u = Nodal(dofhandler=dh_y, data=u_data, dim=1)
# Mark vertices for cell, dummy in cells_production: cell.get_vertex(2).mark('production') # Extract degrees of freedom production_dofs = dh_Q1.get_region_dofs(entity_type='vertex', entity_flag='production') v_production = dh_Q1.get_dof_vertices(dofs=production_dofs) # Target pressure at production wells z_fn = Explicit(f=lambda x: 3 - 4 * (x[:, 0] - 1)**2 - 8 * (x[:, 1] - 0.5)**2, dim=2, mesh=mesh) y_target = z_fn.eval(v_production) # # Locations of injection wells # n_injection = (5, 4) # resolution x_injection = np.linspace(0.5, 1.5, n_injection[0]) y_injection = np.linspace(0.25, 0.75, n_injection[1]) X, Y = np.meshgrid(x_injection, y_injection) xy = np.array([X.ravel(), Y.ravel()]).T cells_injection = mesh.bin_points(xy) # Mark vertices for cell, dummy in cells_injection: cell.get_vertex(0).mark('injection')