def project(self, t=None): """Project solution onto CG subspace. soln.project(t) project projects the solution at time t onto a CG FunctionSpace. The projected function is left in self.CGfunction. If argument t is not supplied, the currently loaded solution will be used. (In this case, you must have called load(t) before calling project(). project returns self.CGfunction as its value. """ solver_type = 'petsc' if t is not None: self.load(t) if not hasattr(self, 'CS'): # # create CG FunctionSpace # self.CE = CGelement(self.fs) self.CS = FunctionSpace(self.fs.mesh(), self.CE) self.CGfunction = fe.project(self.function, self.CS, solver_type=solver_type) return self.CGfunction
def project_gradient_neumann( f0, degree=None, mesh=None, solver_type='gmres', preconditioner_type='default' ): """Find an approximation to f0 that has the same gradient The resulting function also satisfies homogeneous Neumann boundary conditions. Parameters: f0: the function to approximate mesh=None: the mesh on which to approximate it If not provided, the mesh is extracted from f0. degree=None: degree of the polynomial approximation. extracted from f0 if not provided. solver_type='gmres': The linear solver type to use. preconditioner_type='default': Preconditioner type to use """ if not mesh: mesh = f0.function_space().mesh() element = f0.ufl_element() if not degree: degree = element.degree() CE = FiniteElement('CG', mesh.ufl_cell(), degree) CS = FunctionSpace(mesh, CE) DE = FiniteElement('DG', mesh.ufl_cell(), degree) DS = FunctionSpace(mesh, DE) CVE = VectorElement('CG', mesh.ufl_cell(), degree - 1) CV = FunctionSpace(mesh, CVE) RE = FiniteElement('R', mesh.ufl_cell(), 0) R = FunctionSpace(mesh, RE) CRE = MixedElement([CE, RE]) CR = FunctionSpace(mesh, CRE) f = fe.project(f0, CS, solver_type=solver_type, preconditioner_type=preconditioner_type) g = fe.project(fe.grad(f), CV, solver_type=solver_type, preconditioner_type=preconditioner_type) lf = fe.project(fe.nabla_div(g), CS, solver_type=solver_type, preconditioner_type=preconditioner_type) tf, tc = TrialFunction(CR) wf, wc = TestFunctions(CR) dx = Measure('dx', domain=mesh, metadata={'quadrature_degree': min(degree, 10)}) a = (fe.dot(fe.grad(tf), fe.grad(wf)) + tc * wf + tf * wc) * dx L = (f * wc - lf * wf) * dx igc = Function(CR) fe.solve(a == L, igc, solver_parameters={'linear_solver': solver_type, 'preconditioner': preconditioner_type} ) ig, c = igc.sub(0), igc.sub(1) igd = fe.project(ig, DS, solver_type=solver_type, preconditioner_type=preconditioner_type) return igd
def test_multiplication(self): print( '\n== testing multiplication of system matrix for problem of weighted projection ====' ) for dim, pol_order in itertools.product([2, 3], [1, 2]): N = 2 # no. of elements print('dim={0}, pol_order={1}, N={2}'.format(dim, pol_order, N)) # creating MESH and defining MATERIAL if dim == 2: mesh = UnitSquareMesh(N, N) m = Expression("1+10*16*x[0]*(1-x[0])*x[1]*(1-x[1])", degree=2) # material coefficients elif dim == 3: mesh = UnitCubeMesh(N, N, N) m = Expression("1+10*16*x[0]*(1-x[0])*(1-x[1])*x[2]", degree=2) # material coefficients mesh.coordinates()[:] += 0.1 * np.random.random( mesh.coordinates().shape) # mesh perturbation V = FunctionSpace(mesh, "CG", pol_order) # original FEM space W = FunctionSpace(mesh, "CG", 2 * pol_order) # double-grid space print('assembling local matrices for DoGIP...') Bhat = get_Bhat( dim, pol_order, problem=0) # projection between V on W on a reference element AT_dogip = get_A_T(m, V, W, problem=0) dofmapV = V.dofmap() def system_multiplication_DoGIP(AT_dogip, Bhat, u_vec): # mutliplication with DoGIP decomposition Au = np.zeros_like(u_vec) for ii, cell in enumerate(cells(mesh)): ind = dofmapV.cell_dofs(ii) # local to global map Au[ind] += Bhat.T.dot(AT_dogip[ii] * Bhat.dot(u_vec[ind])) return Au print('assembling FEM sparse matrix') u, v = TrialFunction(V), TestFunction(V) Asp = assemble(m * u * v * dx, tensor=EigenMatrix()) # Asp = Asp.sparray() print('multiplication...') ur = Function(V) # creating random vector ur_vec = 5 * np.random.random(V.dim()) ur.vector().set_local(ur_vec) Au_DoGIP = system_multiplication_DoGIP( AT_dogip, Bhat, ur_vec) # DoGIP multiplication Auex = Asp.dot(ur_vec) # FEM multiplication with sparse matrix # testing the difference between DoGIP and FEniCS self.assertAlmostEqual(0, np.linalg.norm(Auex - Au_DoGIP)) print('...ok')
def make_function_space(self, mesh=None, dim=None, degree=None): if not mesh: mesh = self.mesh if not dim: dim = self.dim if not degree: degree = self.degree SE = FiniteElement('DG', cellShapes[dim - 1], degree) SS = FunctionSpace(mesh, SE) # scalar space VE = MixedElement(SE, SE) VS = FunctionSpace(mesh, VE) # vector space return dict(SE=SE, SS=SS, VE=VE, VS=VS)
def make_function_space(self, mesh=None, dim=None, degree=None): if not mesh: mesh = self.mesh if not dim: dim = self.dim if not degree: degree = self.degree SE = FiniteElement('DG', cellShapes[dim - 1], degree) SS = FunctionSpace(mesh, SE) # scalar space elements = [SE] * ((self.nligands + 1) * 2**self.dim) VE = MixedElement(elements) VS = FunctionSpace(mesh, VE) # vector space logPERIODIC('VS', VS) return dict(SE=SE, SS=SS, VE=VE, VS=VS)
def evenodd_functions_old( omesh, degree, func, width=None, evenodd=None ): """Break a function into even and odd components Required parameters: omesh: the mesh on which the function is defined degree: the degree of the FunctionSpace func: the Function. This has to be something that fe.interpolate can interpolate onto a FunctionSpace or that fe.project can project onto a FunctionSpace. width: the width of the domain on which func is defined. (If not provided, this will be determined from omesh. evenodd: the symmetries of the functions to be constructed evenodd_symmetries(dim) is used if this is not provided """ SS = FunctionSpace(omesh, 'CG', degree) dim = omesh.geometry().dim() if width is None: stats = mesh_stats(omesh) width = stats['xmax'] if evenodd is None: evenodd = evenodd_symmetries(dim) try: f0 = fe.interpolate(func, SS) except TypeError: f0 = fe.project(func, SS) ffuncs = [] flips = evenodd_symmetries(dim) for flip in (flips): fmesh = Mesh(omesh) SSf = FunctionSpace(fmesh, 'CG', degree) ffunc = fe.interpolate(f0, SSf) fmesh.coordinates()[:, :] = (width*flip + (1 - 2*flip)*fmesh.coordinates()) fmesh.bounding_box_tree().build(fmesh) ffuncs.append(ffunc) E = evenodd_matrix(evenodd) components = matmul(2**(-dim)*E, ffuncs) cs = [] for c in components: try: cs.append(fe.interpolate(c, SS)) except TypeError: cs.append(fe.project(c, SS, solver_type='lu')) return(cs)
def read_dem(bounds, res): """ Function to read in a DEM from SRTM amd interplolate it onto a dolphyn mesh. This function uses the python package 'elevation' (http://elevation.bopen.eu/en/stable/) and the gdal libraries. I will assume you want the 30m resolution SRTM model. :param bounds: west, south, east, north coordinates :return u_n, lx, ly: the elevation interpolated onto the dolphyn mesh and the lengths of the domain """ west, south, east, north = bounds # Create a temporary file to store the DEM and go get it using elevation dem_path = 'tmp.tif' output = os.getcwd() + '/' + dem_path elv.clip(bounds=bounds, output=output, product='SRTM1') # read in the DEM into a numpy array gdal_data = gdal.Open(output) data_array = gdal_data.ReadAsArray().astype(np.float) # The DEM is 30m per pixel, so lets make a array for x and y at 30 m ny, nx = np.shape(data_array) lx = nx * 30 ly = ny * 30 x, y = np.meshgrid(np.linspace(0, lx / ly, nx), np.linspace(0, 1, ny)) # Create mesh and define function space domain = Rectangle(Point(0, 0), Point(lx / ly, 1)) mesh = generate_mesh(domain, res) V = FunctionSpace(mesh, 'P', 1) u_n = Function(V) # Get the global coordinates gdim = mesh.geometry().dim() gc = V.tabulate_dof_coordinates().reshape((-1, gdim)) # Interpolate elevation into the initial condition elevation = interpolate.griddata((x.flatten(), y.flatten()), data_array.flatten(), (gc[:, 0], gc[:, 1]), method='nearest') u_n.vector()[:] = elevation # remove tmp DEM os.remove(output) return u_n, lx, ly, mesh, V
def solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) epsilon = Constant(arguments[Components().Diffusion]) f = Expression("(1 - epsilon*4*pow(pi,2))*cos(2*pi*x[0])",\ epsilon=epsilon, degree=1) a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx L = f * w * dx # solving the variational problem. v = Function(H) solve(a == L, v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def __init__(self, function): """Expand a Function defined on a corner mesh to a full mesh. Required parameter: funcion: the Function to be expanded. """ self.VS = function.function_space() self.submesh = self.VS.mesh() self.dim = self.submesh.geometric_dimension() self.nss = self.VS.num_sub_spaces() self.nfields = self.nss // (2**self.dim) self.subcoords = self.submesh.coordinates() self.vtrans = integerify_transform(self.subcoords) self.icols = ['i' + str(i) for i in range(self.dim)] self.emesh, self.maps, self.cellmaps, self.vertexmaps = (expand_mesh( self.submesh, self.vtrans)) self.dcoords = np.reshape(self.VS.tabulate_dof_coordinates(), (-1, self.dim)) self.dtrans = integerify_transform(self.dcoords) self.eSE = scalar_element(self.VS) self.degree = self.eSE.degree() self.eVE = MixedElement([self.eSE] * self.nfields) self.eVS = FunctionSpace(self.emesh, self.eVE) self.sub_dof_list = dof_list(self.VS, self.dtrans) subs = self.sub_dof_list['sub'].values self.sub_dof_list['submesh'] = subs % (2**self.dim) self.sub_dof_list['field'] = subs // (2**self.dim) sc = self.sub_dof_list[['submesh', 'cell']].values self.sub_dof_list['ecell'] = self.cellmaps[(sc[:, 0], sc[:, 1])] self.e_dof_list = dof_list(self.eVS, self.dtrans) self.remap = self.sub2e_map() self.symmetries = evenodd_symmetries(self.dim) self.eomat = evenodd_matrix(self.symmetries) self.sub_function = Function(self.VS) self.expanded_function = Function(self.eVS)
def solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) epsilon = Constant(arguments[Components().Diffusion]) f = Constant(0) a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx #Still have to figure it how to use a Neumann Condition here L = f * w * dx # solving the variational problem. v = Function(H) solve(a == L, v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def compute_mesh_error(do_local_refine, mesh_resolution, num_refinements): mesh = generate_rectangle_mesh(mesh_resolution) # Define heat kernel t0 = 0.01 u = Expression("exp(-(x[0]*x[0]+x[1]*x[1])/(4*t))/(4*pi*t)", t=t0, domain=mesh, degree=3) # Define finite element function space degree = 1 V = FunctionSpace(mesh, "CG", degree) # Refine mesh r = 0.4 xc, yc = 0.0, 0.0 for i in range(0, num_refinements): if do_local_refine: mesh = local_refine(mesh, [xc, yc], r) else: mesh = refine(mesh) # Interpolate the heat kernel into the function space Iu = interpolate(u, V) # Compute L1 error between u and its interpolant error = compute_error(u, Iu) return error
def initialise(dem, bounds, res): """ Function to initialise the model space :param dem: 0 = no input DEM; 1 = input DEM :param bounds: west, south, east, north - if no DEM [0, 0, lx, ly]; if DEM [west, south, east, north] :param res: model resolution along the y-axis. :return model_space, u_n, mesh, V, bc: """ if dem == 0: lx = bounds[1] ly = bounds[3] # Create mesh and define function space domain = Rectangle(Point(0, 0), Point(lx / ly, ly / ly)) mesh = generate_mesh(domain, res) V = FunctionSpace(mesh, 'P', 1) # Define initial value u_D = Constant(0) eps = 10 / ly u_n = interpolate(u_D, V) u_n.vector().set_local(u_n.vector().get_local() + eps * np.random.random(u_n.vector().size())) if dem == 1: u_n, lx, ly, mesh, V = read_dem(bounds, res) # boundary conditions class East(SubDomain): def inside(self, x, on_boundary): return near(x[0], lx / ly) class West(SubDomain): def inside(self, x, on_boundary): return near(x[0], 0.0) class North(SubDomain): def inside(self, x, on_boundary): return near(x[1], ly / ly) class South(SubDomain): def inside(self, x, on_boundary): return near(x[1], 0.0) # Should make this into an option! bc = [DirichletBC(V, u_n, West()), DirichletBC(V, u_n, East())] # def boundary(x, on_boundary): # return on_boundary # bc = DirichletBC(V, u_n, boundary) model_space = [lx, ly, res] return model_space, u_n, mesh, V, bc
def run_fokker_planck(nx, num_steps, t_0 = 0, t_final=10): # define mesh mesh = IntervalMesh(nx, -200, 200) # define function space. V = FunctionSpace(mesh, "Lagrange", 1) # Homogenous Neumann BCs don't have to be defined as they are the default in dolfin # define parameters. dt = (t_final-t_0) / num_steps # set mu and sigma mu = Constant(-1) D = Constant(1) # define initial conditions u_0 u_0 = Expression('x[0]', degree=1) # set U_n to be the interpolant of u_0 over the function space V. Note that # u_n is the value of u at the previous timestep, while u is the current value. u_n = interpolate(u_0, V) # Define variational problem u = TrialFunction(V) v = TestFunction(V) F = u*v*dx + dt*inner(D*grad(u), grad(v))*dx + dt*mu*grad(u)[0]*v*dx - inner(u_n, v)*dx # isolate the bilinear and linear forms. a, L = lhs(F), rhs(F) # initialize function to capture solution. t = 0 u_h = Function(V) plt.figure(figsize=(15, 15)) # time-stepping section for n in range(num_steps): t += dt # compute solution solve(a == L, u_h) u_n.assign(u_h) # Plot solutions intermittently if n % (num_steps // 10) == 0 and num_steps > 0: plot(u_h, label='t = %s' % t) plt.legend() plt.grid() plt.title("Finite Element Solutions to Fokker-Planck Equation with $\mu(x, t) = -(x+1)$ , $D(x, t) = e^t x^2$, $t_n$ = %s" % t_final) plt.ylabel("$u(x, t)$") plt.xlabel("x") plt.savefig("fpe/fokker-planck-solutions-mu.png") plt.clf() # return the approximate solution evaluated on the coordinates, and the actual coordinates. return u_n.compute_vertex_values(), mesh.coordinates()
def test_video_loading(): m = UnitSquareMesh(30, 30) V = FunctionSpace(m, "CG", 4) video = VideoData(element=V.ufl_element()) video.load_video("video_data/ach12.mp4") print(video) plot(video, mesh=m) plt.show() video.set_time(10000.) plot(video, mesh=m) plt.show() assert True
def dual_error_estimates(resolution): mesh = UnitSquareMesh(resolution, resolution) def all_boundary(_, on_boundary): return on_boundary zero = Constant(0.0) def a(u, v): return inner(grad(u), grad(v)) * dx def L(f, v): return f * v * dx # Primal problem f = Expression("32.*x[0]*(1. - x[0])+32.*x[1]*(1. - x[1])", domain=mesh, degree=5) ue = Expression("16.*x[0]*(1. - x[0])*x[1]*(1. - x[1])", domain=mesh, degree=5) Qp = FunctionSpace(mesh, 'CG', 1) bcp = DirichletBC(Qp, zero, all_boundary) u = TrialFunction(Qp) v = TestFunction(Qp) U = Function(Qp) solve(a(u, v) == L(f, v), U, bcp) # Dual problem Qd = FunctionSpace(mesh, 'CG', 2) psi = Constant(1.0) bcd = DirichletBC(Qd, zero, all_boundary) w = TestFunction(Qd) phi = TrialFunction(Qd) Phi = Function(Qd) solve(a(w, phi) == L(psi, w), Phi, bcd) # Compute errors e1 = compute_error(ue, U) e2 = assemble((inner(grad(U), grad(Phi)) - f * Phi) * dx) print("e1 = {}".format(e1)) print("e2 = {}".format(e2))
def main(): np.random.seed(793817931) degree = 3 mesh = UnitSquareMesh(2, 2) gdim = mesh.geometry().dim() fs = FunctionSpace(mesh, 'CG', degree) f = Function(fs) random_function(f) print(f.vector()[:])
def evenodd_functions( omesh, degree, func, width=None, evenodd=None ): """Break a function into even and odd components Required parameters: omesh: the mesh on which the function is defined degree: the degree of the FunctionSpace func: the Function. This has to be something that fe.interpolate can interpolate onto a FunctionSpace or that fe.project can project onto a FunctionSpace. width: the width of the domain on which func is defined. (If not provided, this will be determined from omesh. evenodd: the symmetries of the functions to be constructed evenodd_symmetries(dim) is used if this is not provided """ SS = FunctionSpace(omesh, 'CG', degree) dim = omesh.geometry().dim() comm = omesh.mpi_comm() rank = comm.rank if width is None: stats = mesh_stats(omesh) width = stats['xmax'] if evenodd is None: evenodd = evenodd_symmetries(dim) try: f0 = fe.interpolate(func, SS) except TypeError: f0 = fe.project(func, SS) vec0 = f0.vector().gather_on_zero() dofcoords = gather_dof_coords(SS) ndofs = len(dofcoords) fvecs = np.empty((2**dim, len(vec0)), float) flips = evenodd_symmetries(dim) for row,flip in enumerate(flips): newcoords = (width*flip + (1 - 2*flip)*dofcoords) remap = coord_remap(SS, newcoords) E = evenodd_matrix(evenodd) if rank == 0: fvecs[row, :] = vec0[remap] components = np.matmul(2**(-dim)*E, fvecs) else: components = np.zeros((2**dim, ndofs), float) logPERIODIC('components.shape', components.shape) fs = [] logPERIODIC('broadcasting function DOFs') for c in components: f = Function(SS) f = bcast_function(SS, c, f) # f.set_allow_extrapolation(True) fs.append(f) return(fs)
def restart(self): logVARIABLE('restart') self.set_time(self.t0) CE = FiniteElement('CG', cellShapes[self.dim - 1], self.degree) CS = FunctionSpace(self.mesh, CE) # scalar space coords = gather_dof_coords(CS) fe.assign(self.sol.sub(0), function_interpolate(self.rho0, self.SS, coords=coords)) for i, U0i in enumerate(self.U0s): fe.assign(self.sol.sub(i + 1), function_interpolate(U0i, self.SS, coords=coords))
def solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) coeff_dx2 = Constant(1) coeff_v = Constant(1) f = Expression("(4*pow(pi,2))*exp(-(1/coeff_v)*t)*sin(2*pi*x[0])", {'coeff_v': coeff_v}, degree=2) v0 = Expression("sin(2*pi*x[0])", degree=2) f.t = 0 def boundary(x, on_boundary): return on_boundary bc = DirichletBC(H, v0, boundary) v1 = interpolate(v0, H) dt = self.steps.time a = (dt * inner(grad(v), grad(w)) + dt * coeff_v * inner(v, w)) * dx L = (f * dt - coeff_v * v1) * w * dx A = assemble(a) v = Function(H) T = self.domain.time[-1] t = dt # solving the variational problem. while t <= T: b = assemble(L, tensor=b) vo.t = t bc.apply(A, b) solve(A, v.vector(), b) t += dt v1.assign(v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def restart(self): logSOLVER('restart') self.t = self.t0 CE = FiniteElement('CG', cellShapes[self.dim - 1], self.degree) CS = FunctionSpace(self.mesh, CE) # scalar space coords = gather_dof_coords(CS) logSOLVER('function_interpolate(self.U0, self.SS, coords=coords)', function_interpolate(self.U0, self.SS, coords=coords)) fe.assign(self.sol.sub(1), function_interpolate(self.U0, self.SS, coords=coords)) logSOLVER('U0 assign returned') fe.assign(self.sol.sub(0), function_interpolate(self.rho0, self.SS, coords=coords))
def __init__(self, mesh, N=0): # Define mesh parameters self.mesh = mesh self.cell_size = CellDiameter(mesh) self.normal_vector = FacetNormal(mesh) # Define measures inner_boundary = Inner_boundary() sub_domains = MeshFunction("size_t", mesh, mesh.topology().dim() - 1) sub_domains.set_all(0) inner_boundary.mark(sub_domains, 1) self.dx = Measure("dx", domain=mesh) self.ds = Measure("ds", domain=mesh, subdomain_data=sub_domains) # Define function spaces finite_element = FiniteElement("Lagrange", mesh.ufl_cell(), 1) self.function_space = FunctionSpace(mesh, finite_element * finite_element) self.function_space_split = [ self.function_space.sub(0).collapse(), self.function_space.sub(1).collapse(), ]
def __init__(self, *, V: Optional[FunctionSpace], mesh: Mesh, dt: float) -> None: V = V or FunctionSpace(mesh, "Lagrange", 1) self.V = V self.T = TrialFunction(V) self.v = TestFunction(V) self.T_prev = Function(V) self.P_s = Constant(1.0) self.c_s = Constant(1.0) self.k_e = Constant(1.0) self.Q_pc = Constant(1.0) self.Q_sw = Constant(1.0) self.Q_mm = Constant(1.0) self.dt = Constant(dt)
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 # 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=3) # material coefficients f = Expression("x[0]*x[0]*x[1]", degree=2) elif dim == 3: mesh = UnitCubeMesh(N, N, N) m = Expression("1+100*x[0]*(1-x[0])*x[1]*x[2]", degree=2) # material coefficients f = Expression("(1-x[0])*x[1]*x[2]", degree=2) 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 u, v = TrialFunction(V), TestFunction(V) u_fenics = Function(V) solve(m * u * v * dx == m * f * v * dx, u_fenics) ## DoGIP - double-grid integration with interpolation-projection ############# W = FunctionSpace(mesh, "CG", 2 * pol_order) # double-grid space w = TestFunction(W) A_dogip = assemble( m * w * dx).get_local() # diagonal matrix of material coefficients b = assemble(m * f * v * dx) # vector of right-hand side # assembling interpolation-projection matrix B B = get_B(V, W, problem=0) # # linear solver on double grid, standard Afun = lambda x: B.T.dot(A_dogip * B.dot(x)) Alinoper = linalg.LinearOperator((V.dim(), V.dim()), matvec=Afun, dtype=np.float) x, info = linalg.cg(Alinoper, b.get_local(), x0=np.zeros(V.dim()), tol=1e-10, maxiter=1e3, callback=None) # testing the difference between DoGIP and FEniCS self.assertAlmostEqual( 0, np.linalg.norm(u_fenics.vector().get_local() - x)) print('...ok')
def __init__(self, grid_shape, f, init_z, dirichlet, degree=1, polynomial_type='P', reparam=True): """Parameters ---------- grid_shape : numpy.array or list Defines the grid dimensions of the mesh used to solve the problem. f : str Source term of the Poisson equation in a form accepted by FEniCS (C++ style string) init_z : numpy.ndarray Placeholder value(s) for parameters of the model. dirichlet : str Dirichlet boundary conditions in string form accepted by FEniCS. degree : int, default 1 Polynomial degree for the functional space. polynomial_type : str, default 'P' String encoding the type of polynomials in the functional space, according to FEniCS conventions (defaults to Lagrange polynomials). reparam: bool, default True Boolean indicating whether input parameters are to be reparametrized according to an inverse-logit transform. """ def boundary(x, on_boundary): return on_boundary self.grid_shape = grid_shape self.mesh = UnitSquareMesh(*grid_shape) self.V = FunctionSpace(self.mesh, polynomial_type, degree) self.dirichlet = DirichletBC(self.V, Expression(dirichlet, degree=degree + 3), boundary) self._paramnames = ['param{}'.format(i) for i in range(len(init_z))] self.f = Expression(f, degree=degree, **dict(zip(self._paramnames, init_z))) u = TrialFunction(self.V) v = TestFunction(self.V) self.a = dot(grad(u), grad(v)) * dx self.L = self.f * v * dx self.u = Function(self.V) self.reparam = reparam self.solver = CountIt(solve)
def compute_error(u1, u2): """ L1 error between two functions u1 and u2 :param u1: FEniCS function :param u2: FEniCS function :return: Approximate L1 error between u1 and u2 """ mesh_resolution_ref = 400 mesh_ref = UnitSquareMesh(mesh_resolution_ref, mesh_resolution_ref) V_ref = FunctionSpace(mesh_ref, "CG", degree=1) Iu1 = interpolate(u1, V_ref) Iu2 = interpolate(u2, V_ref) error = assemble(abs(Iu1 - Iu2) * dx) return error
def compute_steady_state(self): names = {'Cl', 'Na', 'K'} P1 = FiniteElement('P', fe.triangle, 1) element = MixedElement([P1, P1, P1]) V = FunctionSpace(self.mesh, element) self.V_conc = V (u_cl, u_na, u_k) = TrialFunction(V) (v_cl, v_na, v_k) = TestFunction(V) assert (self.flow is not None) n = fe.FacetNormal(self.mesh) # F = ( self.F_diff_conv(u_cl, v_cl, n, grad(self.phi), 1. ,1., 0.) # + self.F_diff_conv(u_na, v_na, n, grad(self.phi), 1. ,1., 0.) # + self.F_diff_conv(u_k , v_k , n, grad(self.phi), 1. ,1., 0.) ) dx, ds = self.dx, self.ds flow = self.flow F = inner(grad(u_cl), grad(v_cl)) * dx \ + inner(flow, grad(u_cl)) * v_cl * dx \ + inner(grad(u_na), grad(v_na)) * dx \ + inner(flow, grad(u_na)) * v_na * dx \ + inner(grad(u_k), grad(v_k)) * dx \ + inner(flow, grad(u_k)) * v_k * dx a, L = fe.lhs(F), fe.rhs(F) a_mat = fe.assemble(a) L_vec = fe.assemble(L) # solve u = Function(V) fe.solve(a_mat, u.vector(), L_vec) u_cl, u_na, u_k = u.split() output1 = fe.File('/tmp/steady_state_cl.pvd') output1 << u_cl output2 = fe.File('/tmp/steady_state_na.pvd') output2 << u_na output3 = fe.File('/tmp/steady_state_k.pvd') output3 << u_k self.u_cl = u_cl self.u_na = u_na self.u_k = u_k
def solve(): mesh = UnitIntervalMesh(10) V = FunctionSpace(mesh, "Lagrange", 1) dt = 0.01 bt_params = bulk_temperature.BulkTemperatureParameters(V=V, mesh=mesh, dt=dt) bt = bulk_temperature.BulkTemperature(params=bt_params) a_T, L_T = bt.construct_variation_problem() T = Function(V) bt_params.T_prev.vector().set_local( np.random.uniform(0, -10, bt_params.T_prev.vector().size())) map_params = mass_air_phase.MassAirPhaseParameters(V=V, mesh=mesh, dt=dt) map_params.T_s = T ma_ph = mass_air_phase.MassAirPhase(params=map_params) a_P, L_P = ma_ph.construct_variation_problem() P = Function(V) num_steps = 10 t = 0 T_sols = [bt_params.T_prev.vector().array()] P_sols = [] for n in range(num_steps): bc = bt.make_bcs(V, 0, -10) _, bt_params.T_prev, T = bulk_temperature.step(time=t, dt=dt, t_prev=bt_params.T_prev, t=T, a=a_T, l=L_T, bc=bc) _, map_params.P_prev, P = mass_air_phase.step(time=t, dt=dt, p_prev=map_params.P_prev, p=P, a=a_P, l=L_P) t += dt T_sols.append(T.vector().array()) P_sols.append(P.vector().array()) for T_s in T_sols: plt.plot(T_s) plt.figure() for P_s in P_sols: plt.plot(P_s) plt.show()
def __init__(self, *, V: Optional[FunctionSpace], mesh: Mesh, dt: float): V = V or FunctionSpace(mesh, "Lagrange", 1) self.V = V self.u = TrialFunction(V) self.v = TestFunction(V) self.P_prev = Function(V) self.theta_a = Constant(1.0) self.D_e = Constant(1.0) self.P_d = Constant(1.0) self.my_v = Constant(1.0) self.my_d = Constant(1.0) self.alpha_th = Constant(1.0) self.M_mm = Constant(1.0) self.q_h = Constant(1.0) self.T_s = project(Constant(-5.0), V) self.dt = Constant(dt) self.mesh = mesh
def solve_wave_equation(u0, u1, u_boundary, f, domain, mesh, degree): """Solving the wave equation using CG-CG method. Args: u0: Initial data. u1: Initial velocity. u_boundary: Dirichlet boundary condition. f: Right-hand side. domain: Space-time domain. mesh: Computational mesh. degree: CG(degree) will be used as the finite element. Outputs: uh: Numerical solution. """ # Element V = FunctionSpace(mesh, "CG", degree) # Measures on the initial and terminal slice mask = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) domain.get_initial_slice().mark(mask, 1) ends = ds(subdomain_data=mask) # Form g = Constant(((-1.0, 0.0), (0.0, 1.0))) u = TrialFunction(V) v = TestFunction(V) a = dot(grad(v), dot(g, grad(u))) * dx L = f * v * dx + u1 * v * ends(1) # Assembled matrices A = assemble(a, keep_diagonal=True) b = assemble(L, keep_diagonal=True) # Spatial boundary condition bc = DirichletBC(V, u_boundary, domain.get_spatial_boundary()) bc.apply(A, b) # Temporal boundary conditions (by hand) (A, b) = apply_time_boundary_conditions(domain, V, u0, A, b) # Solve solver = LUSolver() solver.set_operator(A) uh = Function(V) solver.solve(uh.vector(), b) return uh
alpha = 3 # parameter alpha beta = 1.3 # parameter beta gamma = args.gamma # parameter gamma, dependence of heat flux on time y_bottom, y_top = 0, 1 x_left, x_right = 0, 2 x_coupling = 1.5 # x coordinate of coupling interface if domain_part is DomainPart.LEFT: p0 = Point(x_left, y_bottom) p1 = Point(x_coupling, y_top) elif domain_part is DomainPart.RIGHT: p0 = Point(x_coupling, y_bottom) p1 = Point(x_right, y_top) mesh = RectangleMesh(p0, p1, nx, ny) V = FunctionSpace(mesh, 'P', 2) # Define boundary condition u_D = Expression( '1 + gamma*t*x[0]*x[0] + (1-gamma)*x[0]*x[0] + alpha*x[1]*x[1] + beta*t', degree=2, alpha=alpha, beta=beta, gamma=gamma, t=0) u_D_function = interpolate(u_D, V) # Define flux in x direction on coupling interface (grad(u_D) in normal direction) f_N = Expression('2 * gamma*t*x[0] + 2 * (1-gamma)*x[0] ', degree=1, gamma=gamma, t=0)
class DataInput(object): """ This object brokers the relation between the driver file and a number of data sets. It's function is to: 1) Read the data. Presently it is assumed that all input is Matlab V5. 2) Filter or process the data. Presently the only filter is to remove rows or columns in key data sets that are entirely not a number. 3) Project the data onto a finite element mesh that is generated based on the extents of the input data set. """ def __init__(self, direc, files, flip=False, mesh=None, gen_space=True, zero_edge=False, bool_data=False, req_dg=False): """ The following data are used to initialize the class : direc : Set the directory containing the input files. files : Tuple of file names. All files are scanned for rows or columns of nans. Assume all files have the same extents. flip : flip the data over the x-axis? mesh : FEniCS mesh if there is one already created. zero_edge : Make edges of domain -0.002? bool_data : Convert data to boolean? req_dg : Some field may require DG space? Based on thickness extents, create a rectangular mesh object. Also define the function space as continious galerkin, order 1. """ self.directory = direc self.data = {} # dictionary of converted matlab data self.rem_nans = False self.chg_proj = False # change to other projection flag first = True # initialize domain by first file's extents if direc == None and type(files) == dict: self.name = files.pop('dataset') elif direc != None: self.name = direc print "::: creating %s DataInput object :::" % self.name # process the data files : for fn in files: if direc == None and type(files) == dict: d_dict = files[fn] elif direc != None: d_dict = loadmat(direc + fn) d_dict['projection'] = d_dict['projection'][0] d_dict['standard lat'] = d_dict['standard lat'][0] d_dict['standard lon'] = d_dict['standard lon'][0] d_dict['lat true scale'] = d_dict['lat true scale'][0] d = d_dict["map_data"] # initialize extents : if first: self.ny,self.nx = shape(d_dict['map_data']) self.x_min = float(d_dict['map_western_edge']) self.x_max = float(d_dict['map_eastern_edge']) self.y_min = float(d_dict['map_southern_edge']) self.y_max = float(d_dict['map_northern_edge']) self.proj = str(d_dict['projection']) self.lat_0 = str(d_dict['standard lat']) self.lon_0 = str(d_dict['standard lon']) self.lat_ts = str(d_dict['lat true scale']) self.x = linspace(self.x_min, self.x_max, self.nx) self.y = linspace(self.y_min, self.y_max, self.ny) self.good_x = array(ones(len(self.x)), dtype=bool) # no NaNs self.good_y = array(ones(len(self.y)), dtype=bool) # no NaNs first = False # identify, but not remove the NaNs : self.identify_nans(d, fn) # make edges all zero for interpolation of interior regions : if zero_edge: d[:,0] = d[:,-1] = d[0,:] = d[-1,:] = -0.002 d[:,1] = d[:,-2] = d[1,:] = d[-2,:] = -0.002 # convert to boolean : if bool_data: d[d > 0] = 1 # reflect over the x-axis : if flip: d = d[::-1, :] # add to the dictionary of arrays : self.data[fn.split('.')[0]] = d # remove un-needed rows/cols from data: if self.rem_nans: self.remove_nans() if gen_space: # define a FEniCS Rectangle over the domain : if mesh == None: self.mesh = RectangleMesh(self.x_min, self.y_min, self.x_max, self.y_max, self.nx, self.ny) else: self.mesh = mesh # define the function space of the problem : self.func_space = FunctionSpace(self.mesh, "CG", 1) # if DG space is needed : if req_dg: self.func_space_dg = FunctionSpace(self.mesh, "DG", 1) # create projection : proj = " +proj=" + self.proj \ + " +lat_0=" + self.lat_0 \ + " +lat_ts=" + self.lat_ts \ + " +lon_0=" + self.lon_0 \ + " +k=1 +x_0=0 +y_0=0 +no_defs +a=6378137 +rf=298.257223563" \ + " +towgs84=0.000,0.000,0.000 +to_meter=1" self.p = Proj(proj) def change_projection(self, di): """ change the projection of this data to that of the <di> DataInput object's projection. The works only if the object was created with the parameter create_proj = True. """ self.chg_proj = True self.new_p = di.p def integrate_field(self, fn_spec, specific, fn_main, r=20, val=0.0): """ Assimilate a field with filename <fn_spec> from DataInput object <specific> into this DataInput's field with filename <fn_main>. The parameter <val> should be set to the specific dataset's value for undefined regions, default is 0.0. <r> is a parameter used to eliminate border artifacts from interpolation; increase this value to eliminate edge noise. """ print "::: integrating %s field from %s :::" % (fn_spec, specific.name) # get the dofmap to map from mesh vertex indices to function indicies : df = self.func_space.dofmap() dfmap = df.vertex_to_dof_map(self.mesh) unew = self.get_projection(fn_main) # existing dataset projection uocom = unew.compute_vertex_values() # mesh indexed main vertex values uspec = specific.get_projection(fn_spec) # specific dataset projection uscom = uspec.compute_vertex_values() # mesh indexed spec vertex values d = float64(specific.data[fn_spec]) # original matlab spec dataset # get arrays of x-values for specific domain xs = specific.x ys = specific.y nx = specific.nx ny = specific.ny for v in vertices(self.mesh): # mesh vertex x,y coordinate : i = v.index() p = v.point() x = p.x() y = p.y() # indexes of closest datapoint to specific dataset's x and y domains : idx = abs(xs - x).argmin() idy = abs(ys - y).argmin() # data value for closest value and square around the value in question : dv = d[idy, idx] db = d[max(0,idy-r) : min(ny, idy+r), max(0, idx-r) : min(nx, idx+r)] # if the vertex is in the domain of the specific dataset, and the value # of the dataset at this point is not abov <val>, set the array value # of the main file to this new specific region's value. if dv > val: #print "found:", x, y, idx, idy, v.index() # if the values is not near an edge, make the value equal to the # nearest specific region's dataset value, otherwise, use the # specific region's projected value : if all(db > val): uocom[i] = uscom[i] else : uocom[i] = dv # set the values of the projected original dataset equal to the assimilated # dataset : unew.vector().set_local(uocom[dfmap]) return unew def identify_nans(self, data, fn): """ private method to identify rows and columns of all nans from grids. This happens when the data from multiple GIS databases don't quite align on whatever the desired grid is. """ #print "::: DataInput identifying NaNs for %s :::" % fn good_x = ~all(isnan(data), axis=0) & self.good_x # good cols good_y = ~all(isnan(data), axis=1) & self.good_y # good rows if any(good_x != self.good_x): total_nan_x = sum(good_x == False) self.rem_nans = True print "Warning: %d row(s) of \"%s\" are entirely NaN." % (total_nan_x, fn) if any(good_y != self.good_y): total_nan_y = sum(good_y == False) self.rem_nans = True print "Warning: %d col(s) of \"%s\" are entirely NaN." % (total_nan_y, fn) self.good_x = good_x self.good_y = good_y def remove_nans(self): """ remove extra rows/cols from data where NaNs were identified and set the extents to those of the good x and y values. """ self.x = self.x[self.good_x] self.y = self.y[self.good_y] self.x_min = self.x.min() self.x_max = self.x.max() self.y_min = self.y.min() self.y_max = self.y.max() self.nx = len(self.x) self.ny = len(self.y) print "::::::::REMOVING NaNs::::::::" for i in self.data.keys(): self.data[i] = self.data[i][self.good_y, : ] self.data[i] = self.data[i][:, self.good_x] def set_data_min(self, fn, boundary, val): """ set the minimum value of a data array with filename <fn> below <boundary> to value <val>. """ d = self.data[fn] d[d <= boundary] = val self.data[fn] = d def set_data_max(self, fn, boundary, val): """ set the maximum value of a data array with filename <fn> above <boundary> to value <val>. """ d = self.data[fn] d[d >= boundary] = val self.data[fn] = d def set_data_val(self, fn, old_val, new_val): """ set all values of the matrix with filename <fn> equal to <old_val> to <new_val>. """ d = self.data[fn] d[d == old_val] = new_val self.data[fn] = d def get_interpolation(self,fn,kx=3,ky=3): interp = self.get_spline_expression(fn,kx=kx,ky=ky) proj = interpolate(interp, self.func_space) return proj def get_projection(self, fn, dg=False, near=False, bool_data=False, kx=3, ky=3): """ Return a projection of data with filname <fn> on the functionspace. If multiple instances of the DataInput class are present, both initialized with identical meshes, the projections returned by this function may be used by the same mathematical problem. If <dg> is True, use a discontinuous space, otherwise, continuous. If <bool_data> is True, convert all values > 0 to 1. """ print "::: getting %s projection :::" % fn if dg: interp = self.get_nearest_expression(fn, bool_data=bool_data) proj = project(interp, self.func_space_dg) else: if near: interp = self.get_nearest_expression(fn, bool_data=bool_data) proj = project(interp, self.func_space) else: interp = self.get_spline_expression(fn,kx=kx,ky=ky,bool_data=bool_data) proj = project(interp, self.func_space) return proj def get_nearest_expression(self, fn, bool_data=False): """ Returns a dolfin expression using a nearest-neighbor interpolant of data <fn>. If <bool_data> is True, convert to boolean. """ print "::: getting %s nearest expression from %s :::" % (fn, self.name) data = self.data[fn] if bool_data: data[data > 0] = 1 if self.chg_proj: new_proj = self.new_p old_proj = self.p xs = self.x ys = self.y chg_proj = self.chg_proj class newExpression(Expression): def eval(self, values, x): if chg_proj: xn, yn = transform(new_proj, old_proj, x[0], x[1]) else: xn, yn = x[0], x[1] idx = abs(self.xs - xn).argmin() idy = abs(self.ys - yn).argmin() values[0] = self.data[idy, idx] return newExpression(element = self.func_space.ufl_element()) def get_spline_expression(self, fn, kx=3, ky=3, bool_data=False): """ Creates a spline-interpolation expression for data <fn>. Optional arguments <kx> and <ky> determine order of approximation in x and y directions (default cubic). If <bool_data> is True, convert to boolean. """ print "::: getting %s spline expression from %s :::" % (fn, self.name) data = self.data[fn] if bool_data: data[data > 0] = 1 if self.chg_proj: new_proj = self.new_p old_proj = self.p spline = RectBivariateSpline(self.x, self.y, data.T, kx=kx, ky=ky) chg_proj = self.chg_proj class newExpression(Expression): def eval(self, values, x): if chg_proj: xn, yn = transform(new_proj, old_proj, x[0], x[1]) else: xn, yn = x[0], x[1] values[0] = spline(xn, yn) return newExpression(element = self.func_space.ufl_element()) def get_nearest(self, fn): """ returns a dolfin Function object with values given by interpolated nearest-neighbor data <fn>. """ #FIXME: get to work with a change of projection. # get the dofmap to map from mesh vertex indices to function indicies : df = self.func_space.dofmap() dfmap = df.vertex_to_dof_map(self.mesh) unew = Function(self.func_space) # existing dataset projection uocom = unew.vector().array() # mesh indexed main vertex values d = float64(self.data[fn]) # original matlab spec dataset # get arrays of x-values for specific domain xs = self.x ys = self.y for v in vertices(self.mesh): # mesh vertex x,y coordinate : i = v.index() p = v.point() x = p.x() y = p.y() # indexes of closest datapoint to specific dataset's x and y domains : idx = abs(xs - x).argmin() idy = abs(ys - y).argmin() # data value for closest value : dv = d[idy, idx] if dv > 0: dv = 1.0 uocom[i] = dv # set the values of the empty function's vertices to the data values : unew.vector().set_local(uocom[dfmap]) return unew
def __init__(self, direc, files, flip=False, mesh=None, gen_space=True, zero_edge=False, bool_data=False, req_dg=False): """ The following data are used to initialize the class : direc : Set the directory containing the input files. files : Tuple of file names. All files are scanned for rows or columns of nans. Assume all files have the same extents. flip : flip the data over the x-axis? mesh : FEniCS mesh if there is one already created. zero_edge : Make edges of domain -0.002? bool_data : Convert data to boolean? req_dg : Some field may require DG space? Based on thickness extents, create a rectangular mesh object. Also define the function space as continious galerkin, order 1. """ self.directory = direc self.data = {} # dictionary of converted matlab data self.rem_nans = False self.chg_proj = False # change to other projection flag first = True # initialize domain by first file's extents if direc == None and type(files) == dict: self.name = files.pop('dataset') elif direc != None: self.name = direc print "::: creating %s DataInput object :::" % self.name # process the data files : for fn in files: if direc == None and type(files) == dict: d_dict = files[fn] elif direc != None: d_dict = loadmat(direc + fn) d_dict['projection'] = d_dict['projection'][0] d_dict['standard lat'] = d_dict['standard lat'][0] d_dict['standard lon'] = d_dict['standard lon'][0] d_dict['lat true scale'] = d_dict['lat true scale'][0] d = d_dict["map_data"] # initialize extents : if first: self.ny,self.nx = shape(d_dict['map_data']) self.x_min = float(d_dict['map_western_edge']) self.x_max = float(d_dict['map_eastern_edge']) self.y_min = float(d_dict['map_southern_edge']) self.y_max = float(d_dict['map_northern_edge']) self.proj = str(d_dict['projection']) self.lat_0 = str(d_dict['standard lat']) self.lon_0 = str(d_dict['standard lon']) self.lat_ts = str(d_dict['lat true scale']) self.x = linspace(self.x_min, self.x_max, self.nx) self.y = linspace(self.y_min, self.y_max, self.ny) self.good_x = array(ones(len(self.x)), dtype=bool) # no NaNs self.good_y = array(ones(len(self.y)), dtype=bool) # no NaNs first = False # identify, but not remove the NaNs : self.identify_nans(d, fn) # make edges all zero for interpolation of interior regions : if zero_edge: d[:,0] = d[:,-1] = d[0,:] = d[-1,:] = -0.002 d[:,1] = d[:,-2] = d[1,:] = d[-2,:] = -0.002 # convert to boolean : if bool_data: d[d > 0] = 1 # reflect over the x-axis : if flip: d = d[::-1, :] # add to the dictionary of arrays : self.data[fn.split('.')[0]] = d # remove un-needed rows/cols from data: if self.rem_nans: self.remove_nans() if gen_space: # define a FEniCS Rectangle over the domain : if mesh == None: self.mesh = RectangleMesh(self.x_min, self.y_min, self.x_max, self.y_max, self.nx, self.ny) else: self.mesh = mesh # define the function space of the problem : self.func_space = FunctionSpace(self.mesh, "CG", 1) # if DG space is needed : if req_dg: self.func_space_dg = FunctionSpace(self.mesh, "DG", 1) # create projection : proj = " +proj=" + self.proj \ + " +lat_0=" + self.lat_0 \ + " +lat_ts=" + self.lat_ts \ + " +lon_0=" + self.lon_0 \ + " +k=1 +x_0=0 +y_0=0 +no_defs +a=6378137 +rf=298.257223563" \ + " +towgs84=0.000,0.000,0.000 +to_meter=1" self.p = Proj(proj)