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 __init__(self, space_name, variable_name, function_space): # Define initial interface values self.interface_new = Function(function_space) self.interface_old = Function(function_space) # Define initial values for time loop self.new = Function(function_space) self.old = Function(function_space) # Create arrays of empty functions and iterations self.array = [] self.iterations = [] # Create pvd files self.pvd = File(f"solutions/{space_name}/pvd/{variable_name}.pvd") # Remember space self.function_space = function_space # Remember space and variable names self.space_name = space_name self.variable_name = variable_name # Create HDF5 counter self.HDF5_counter = 0
def problem_mix(T, dt, E, coupling, VV, boundaries, rho_s, lambda_, mu_s, f, bcs, **Solid_namespace): # Temporal parameters t = 0 k = Constant(dt) # Split problem to two 1.order differential equations psi, phi = TestFunctions(VV) # Functions, wd is for holding the solution d_ = {} w_ = {} wd_ = {} for time in ["n", "n-1", "n-2", "n-3"]: if time == "n" and E not in [None, reference]: tmp_wd = Function(VV) wd_[time] = tmp_wd wd = TrialFunction(VV) w, d = split(wd) else: wd = Function(VV) wd_[time] = wd w, d = split(wd) d_[time] = d w_[time] = w # Time derivative if coupling == "center": G = rho_s / (2 * k) * inner(w_["n"] - w_["n-2"], psi) * dx else: G = rho_s / k * inner(w_["n"] - w_["n-1"], psi) * dx # Stress tensor G += inner(Piola2(d_, w_, k, lambda_, mu_s, E_func=E), grad(psi)) * dx # External forces, like gravity G -= rho_s * inner(f, psi) * dx # d-w coupling if coupling == "CN": G += inner(d_["n"] - d_["n-1"] - k * 0.5 * (w_["n"] + w_["n-1"]), phi) * dx elif coupling == "imp": G += inner(d_["n"] - d_["n-1"] - k * w_["n"], phi) * dx elif coupling == "exp": G += inner(d_["n"] - d_["n-1"] - k * w_["n-1"], phi) * dx elif coupling == "center": G += innter(d_["n"] - d_["n-2"] - 2 * k * w["n-1"], phi) * dx else: print "The coupling %s is not implemented, 'CN', 'imp', and 'exp' are the only valid choices." sys.exit(0) # Solve if E in [None, reference]: solver_nonlinear(G, d_, w_, wd_, bcs, T, dt, **Solid_namespace) else: solver_linear(G, d_, w_, wd_, bcs, T, dt, **Solid_namespace)
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 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 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 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 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 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 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 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 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 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 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 shooting_gmres(direction): # Define empty functions on interface increment = Function(interface.function_space) (increment_displacement, increment_velocity) = increment.split(increment) # Split entrance vectors direction_split = np.split(direction, 2) # Set values of functions on interface increment_displacement.vector().set_local(displacement_interface + param.EPSILON * direction_split[0]) increment_velocity.vector().set_local(velocity_interface + param.EPSILON * direction_split[1]) # Interpolate functions on solid subdomain increment_displacement_solid = interpolate( increment_displacement, solid.function_space_split[0]) increment_velocity_solid = interpolate(increment_velocity, solid.function_space_split[1]) displacement_solid.new.assign(increment_displacement_solid) velocity_solid.new.assign(increment_velocity_solid) # Compute shooting function shooting_function_increment = shooting_function( displacement_fluid, velocity_fluid, displacement_solid, velocity_solid, functional_fluid_initial, functional_solid_initial, bilinear_form_fluid, functional_fluid, bilinear_form_solid, functional_solid, first_time_step, fluid, solid, interface, param, fluid_macrotimestep, solid_macrotimestep, adjoint, ) return (shooting_function_increment - shooting_function_value) / param.EPSILON
def function_interpolate(fin, fsout, coords=None, method='nearest'): """Copy a fenics Function Required arguments: fin: the input Function to copy fsout: the output FunctionSpace onto which to copy it Optional arguments: coords: the global coordinates of the DOFs of the FunctionSpace on which fin is defined. If not provided, gather_dof_coords will be called to get them. If you intend to do several interpolations from functions defined on the same FunctionSpace, you can avoid multiple calls to gather_dof_coords by supplying this argument. method='nearest': the method argument of scipy.interpolate.griddata. Returns: The values from fin are interpolated into fout, a Function defined on fsout. fout is returned. """ comm = fsout.mesh().mpi_comm() logGATHER('comm.size', comm.size) try: fsin = fin.function_space() except AttributeError: # fallback for Constant fout = fe.interpolate(fin, fsout) return (fout) vlen = fsin.dim() # # dofs logGATHER('vlen', vlen) if coords is None: coords = gather_dof_coords(fsin) logGATHER('fsin.mesh().mpi_comm().size', fsin.mesh().mpi_comm().size) try: vec0 = fin.vector().gather_on_zero() except AttributeError: # fallback for Constant fout = fe.interpolate(fin, fsout) return (fout) if comm.rank == 0: vec = vec0.copy() else: vec = np.empty(vlen) comm.Bcast(vec, root=0) logGATHER('vec', vec) fout = Function(fsout) fout.vector()[:] = griddata(coords, vec, fsout.tabulate_dof_coordinates(), method=method).flatten() fout.vector().apply('insert') return (fout)
def _solve(self, z, x=None): # problem variables du = TrialFunction(self.V) # incremental displacement v = TestFunction(self.V) # test function u = Function(self.V) # displacement from previous iteration # kinematics ii = Identity(3) # identity tensor dimension 3 f = ii + grad(u) # deformation gradient c = f.T * f # right Cauchy-Green tensor # invariants of deformation tensors ic = tr(c) j = det(f) # elasticity parameters if type(z) in [list, np.ndarray]: param = self.param_remapper(z[0]) if self.param_remapper is not None else z[0] else: param = self.param_remapper(z) if self.param_remapper is not None else z e_var = variable(Constant(param)) # Young's modulus nu = Constant(.3) # Shear modulus (Lamè's second parameter) mu, lmbda = e_var / (2 * (1 + nu)), e_var * nu / ((1 + nu) * (1 - 2 * nu)) # strain energy density, total potential energy psi = (mu / 2) * (ic - 3) - mu * ln(j) + (lmbda / 2) * (ln(j)) ** 2 pi = psi * dx - self.time * dot(self.f, u) * self.ds(3) ff = derivative(pi, u, v) # compute first variation of pi jj = derivative(ff, u, du) # compute jacobian of f # solving if x is not None: numeric_evals = np.zeros(shape=(x.shape[1], len(self.times))) evals = np.zeros(shape=(x.shape[1], len(self.eval_times))) else: numeric_evals = None evals = None for it, t in enumerate(self.times): self.time.t = t self.solver(ff == 0, u, self.bcs, J=jj, bcs=self.bcs, solver_parameters=self.solver_parameters) if x is not None: numeric_evals[:, it] = np.log(np.array([-u(x_)[2] for x_ in x.T]).T) # time-interpolation if x is not None: for i in range(evals.shape[0]): evals[i, :] = np.interp(self.eval_times, self.times, numeric_evals[i, :]) return (evals, u) if x is not None else u
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 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 __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 local_project(v, V, u=None): """Element-wise projection using LocalSolver""" dv = TrialFunction(V) v_ = TestFunction(V) a_proj = inner(dv, v_) * dx b_proj = inner(v, v_) * dx solver = LocalSolver(a_proj, b_proj) solver.factorize() if u is None: u = Function(V) solver.solve_local_rhs(u) return u else: solver.solve_local_rhs(u) return
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 __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 load(self, number): # Load solution in HDF5 format function = Function(self.function_space) file = HDF5File( MPI.comm_world, f"solutions/{self.space_name}" f"/HDF5/{self.variable_name}_{number}.h5", "r", ) file.read( function, f"solutions/{self.space_name}" f"/HDF5/{self.variable_name}_{number}", ) file.close() return function
def fluxes_from_temperature_full_domain(F, V): """ compute flux from weak form (see p.3 in Toselli, Andrea, and Olof Widlund. Domain decomposition methods-algorithms and theory. Vol. 34. Springer Science & Business Media, 2006.) :param F: weak form with known u^{n+1} :param V: function space :param hy: spatial resolution perpendicular to flux direction :return: """ fluxes_vector = assemble(F) # assemble weak form -> evaluate integral v = TestFunction(V) fluxes = Function(V) # create function for flux area = assemble(v * ds).get_local() for i in range(area.shape[0]): if area[i] != 0: # put weight from assemble on function fluxes.vector()[i] = fluxes_vector[i] / area[i] # scale by surface area else: assert(abs(fluxes_vector[i]) < 10**-10) # for non surface parts, we expect zero flux fluxes.vector()[i] = fluxes_vector[i] return fluxes
def test_solve() -> None: dt = 0.01 mesh = UnitIntervalMesh(10) params = MassAirPhaseParameters(V=None, mesh=mesh, dt=dt) mass_air_phase = MassAirPhase(params=params) a, L = mass_air_phase.construct_variation_problem() print(type(a)) print(type(L)) P = Function(params.V) P_prev = params.P_prev num_steps = 10 t = 0 sols = [] for n in range(num_steps): t, P_prev, P = step(time=t, dt=dt, p_prev=P_prev, p=P, a=a, l=L) sols.append(P.vector().get_local()) for s in sols: plt.plot(s) plt.show()
def test_solve() -> None: mesh = UnitIntervalMesh(10) p = BulkTemperatureParameters(V=None, mesh=mesh, dt=0.01) bulk_temp = BulkTemperature(params=p) V = p.V dt = p.dt T_prev = p.T_prev a, L = bulk_temp.construct_variation_problem() T = Function(V) num_steps = 10 t = 0 sols = [] for n in range(num_steps): bc = bulk_temp.make_bcs(V, 0, -10) t, T_prev, T = step(time=t, dt=dt, t_prev=T_prev, t=T, a=a, l=L, bc=bc) sols.append(T.vector().array()) for s in sols: plt.plot(s) plt.show()
def fluid_to_solid(function, solid: Space, fluid: Space, param: Parameters, subspace_index): function_vector = function.vector() vertex_to_dof_fluid = vertex_to_dof_map( fluid.function_space_split[subspace_index]) result = Function(solid.function_space_split[subspace_index]) result_vector = result.vector() vector_to_dif_solid = vertex_to_dof_map( solid.function_space_split[subspace_index]) horizontal = param.NUMBER_ELEMENTS_HORIZONTAL + 1 vertical = param.NUMBER_ELEMENTS_VERTICAL + 1 for i in range(2): for j in range(horizontal): result_vector[vector_to_dif_solid[ (vertical - i - 1) * horizontal + j]] = function_vector[vertex_to_dof_fluid[i * horizontal + j]] return result
def fluxes_from_temperature_full_domain(f, v_vec, k): """Computes flux from weak form (see p.3 in Toselli, Andrea, and Olof Widlund. Domain decomposition methods-algorithms and theory. Vol. 34. Springer Science & Business Media, 2006.). :param f: weak form with known u^{n+1} :param v_vec: vector function space :param k: thermal conductivity :return: fluxes function """ fluxes_vector = assemble(f) # assemble weak form -> evaluate integral v = TestFunction(v_vec) fluxes = Function(v_vec) # create function for flux area = assemble(v * ds).get_local() for i in range(area.shape[0]): if area[i] != 0: # put weight from assemble on function fluxes.vector()[i] = - k * fluxes_vector[i] / area[i] # scale by surface area else: assert (abs(fluxes_vector[i]) < 1E-9) # for non surface parts, we expect zero flux fluxes.vector()[i] = - k * fluxes_vector[i] return fluxes
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