def construct_variation_problem(self) -> Tuple[Form, Form]: p = self.params u_t = (p.T - p.T_prev) / p.dt f = p.Q_pc + p.Q_sw + p.Q_mm F = p.P_s * p.c_s * u_t * p.v * dx + p.k_e * dot(grad(p.T), grad( p.v)) * dx - f * p.v * dx return lhs(F), rhs(F)
def solver(f, u_D, bc_funs, ndim, length, nx, ny, nz=None, degree=1): """Fenics 求解器 Args: f (Expression): [description] u_D (Expression): [description] bc_funs (List[Callable]): [description] ndim (int): [description] length (float): [description] nx (int): [description] ny (int): [description] nz (int, optional): [description]. Defaults to None. degree (int, optional): [description]. Defaults to 1. Returns: Function: 解 u """ mesh = get_mesh(length, nx, ny, nz) V = fs.FunctionSpace(mesh, "P", degree) bcs = [fs.DirichletBC(V, u_D, bc) for bc in bc_funs] u = fs.TrialFunction(V) v = fs.TestFunction(V) FF = fs.dot(fs.grad(u), fs.grad(v)) * fs.dx - f * v * fs.dx a = fs.lhs(FF) L = fs.rhs(FF) u = fs.Function(V) fs.solve(a == L, u, bcs) return u
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 geneForwardMatrix(self, q_fun=fe.Constant(0.0), fR=fe.Constant(0.0), \ fI=fe.Constant(0.0)): if self.haveFunctionSpace == False: self.geneFunctionSpace() xx, yy, dPML, sig0_, p_ = self.domain.xx, self.domain.yy, self.domain.dPML,\ self.domain.sig0, self.domain.p # define the coefficents induced by PML sig1 = fe.Expression('x[0] > x1 && x[0] < x1 + dd ? sig0*pow((x[0]-x1)/dd, p) : (x[0] < 0 && x[0] > -dd ? sig0*pow((-x[0])/dd, p) : 0)', degree=3, x1=xx, dd=dPML, sig0=sig0_, p=p_) sig2 = fe.Expression('x[1] > x2 && x[1] < x2 + dd ? sig0*pow((x[1]-x2)/dd, p) : (x[1] < 0 && x[1] > -dd ? sig0*pow((-x[1])/dd, p) : 0)', degree=3, x2=yy, dd=dPML, sig0=sig0_, p=p_) sR = fe.as_matrix([[(1+sig1*sig2)/(1+sig1*sig1), 0.0], [0.0, (1+sig1*sig2)/(1+sig2*sig2)]]) sI = fe.as_matrix([[(sig2-sig1)/(1+sig1*sig1), 0.0], [0.0, (sig1-sig2)/(1+sig2*sig2)]]) cR = 1 - sig1*sig2 cI = sig1 + sig2 # define the coefficients with physical meaning angl_fre = self.kappa*np.pi angl_fre2 = fe.Constant(angl_fre*angl_fre) # define equations u_ = fe.TestFunction(self.V) du = fe.TrialFunction(self.V) u_R, u_I = fe.split(u_) duR, duI = fe.split(du) def sigR(v): return fe.dot(sR, fe.nabla_grad(v)) def sigI(v): return fe.dot(sI, fe.nabla_grad(v)) F1 = - fe.inner(sigR(duR)-sigI(duI), fe.nabla_grad(u_R))*(fe.dx) \ - fe.inner(sigR(duI)+sigI(duR), fe.nabla_grad(u_I))*(fe.dx) \ - fR*u_R*(fe.dx) - fI*u_I*(fe.dx) a2 = fe.inner(angl_fre2*q_fun*(cR*duR-cI*duI), u_R)*(fe.dx) \ + fe.inner(angl_fre2*q_fun*(cR*duI+cI*duR), u_I)*(fe.dx) \ # define boundary conditions def boundary(x, on_boundary): return on_boundary bc = [fe.DirichletBC(self.V.sub(0), fe.Constant(0.0), boundary), \ fe.DirichletBC(self.V.sub(1), fe.Constant(0.0), boundary)] a1, L1 = fe.lhs(F1), fe.rhs(F1) self.u = fe.Function(self.V) self.A1 = fe.assemble(a1) self.b1 = fe.assemble(L1) self.A2 = fe.assemble(a2) bc[0].apply(self.A1, self.b1) bc[1].apply(self.A1, self.b1) bc[0].apply(self.A2) bc[1].apply(self.A2) self.A = self.A1 + self.A2
def construct_variation_problem(self) -> Tuple[Form, Form]: p = self.params ds = self.make_ds(p.mesh) u_t = (p.u - p.P_prev) / p.dt term = p.alpha_th * p.u * p.P_d * (p.my_v + p.my_d)**2 / ( (p.P_prev + p.P_d) * p.my_v * p.my_d) / p.T_s * grad(p.T_s) F = p.theta_a * u_t * p.v * dx + p.theta_a * p.D_e * dot( grad(p.u) - term, grad( p.v)) * dx - p.M_mm * p.v * dx + p.q_h * p.v * ds(1) return lhs(F), rhs(F)
def xest_second_tutorial(self): T = 2.0 # final time num_steps = 50 # number of time steps dt = T / num_steps # time step size # Create mesh and define function space nx = ny = 30 mesh = fenics.RectangleMesh(fenics.Point(-2, -2), fenics.Point(2, 2), nx, ny) V = fenics.FunctionSpace(mesh, 'P', 1) # Define boundary condition def boundary(x, on_boundary): return on_boundary bc = fenics.DirichletBC(V, fenics.Constant(0), boundary) # Define initial value u_0 = fenics.Expression('exp(-a*pow(x[0], 2) - a*pow(x[1], 2))', degree=2, a=5) u_n = fenics.interpolate(u_0, V) # Define variational problem u = fenics.TrialFunction(V) v = fenics.TestFunction(V) f = fenics.Constant(0) F = u * v * fenics.dx + dt * fenics.dot(fenics.grad(u), fenics.grad( v)) * fenics.dx - (u_n + dt * f) * v * fenics.dx a, L = fenics.lhs(F), fenics.rhs(F) # Create VTK file for saving solution vtkfile = fenics.File( os.path.join(os.path.dirname(__file__), 'output', 'heat_gaussian', 'solution.pvd')) # Time-stepping u = fenics.Function(V) t = 0 not_initialised = True for n in range(num_steps): # Update current time t += dt # Compute solution fenics.solve(a == L, u, bc) # Save to file and plot solution vtkfile << (u, t) # Here we'll need to call tripcolor ourselves to get access to the color range fenics.plot(u) animation_camera.snap() u_n.assign(u) animation = animation_camera.animate() animation.save( os.path.join(os.path.dirname(__file__), 'output', 'heat_gaussian.mp4'))
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 integrate(system_matrix, field, bcs): """Integrates the equation""" left_side, right_side = fe.lhs(system_matrix), fe.rhs(system_matrix) fe.solve(left_side == right_side, field, bcs) if ARGS['--verbose']: print('Checking periodicity:') print('Value at XMIN:', field(XMIN, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at XMAX:', field(XMAX, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at YMIN:', field((XMIN + XMAX) / 3, YMIN, (ZMIN + ZMAX) / 3)) print('Value at YMAX:', field((XMIN + XMAX) / 3, YMAX, (ZMIN + ZMAX) / 3)) print('Value at ZMIN:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMIN)) print('Value at ZMAX:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMAX)) return field
def solver_linear(G, d_, w_, wd_, bcs, T, dt, action=None, **namespace): a = lhs(G); L = rhs(G) A = assemble(a) b = assemble(L) t = 0 #d_prec = PETScPreconditioner("default") #d_solver = PETScKrylovSolver("gmres", d_prec) #d_solver.parameters["monitor_convergence"] = True #from IPython import embed; embed() #d_solver.prec = d_prec # Solver loop while t < (T - dt*DOLFIN_EPS): t += dt # Assemble assemble(a, tensor=A) assemble(L, tensor=b) # Apply BC for bc in bcs: bc.apply(A, b) # Solve #d_solver.solve(A, wd_["n"].vector(), b) solve(A, wd_["n"].vector(), b) # Update solution times = ["n-3", "n-2", "n-1", "n"] for i, t_tmp in enumerate(times[:-1]): wd_[t_tmp].vector().zero() wd_[t_tmp].vector().axpy(1, wd_[times[i+1]].vector()) # Get displacement if callable(action): action(wd_, t) if MPI.rank(mpi_comm_world()) == 0: print "Time: ",t
def xest_first_tutorial(self): T = 2.0 # final time num_steps = 10 # number of time steps dt = T / num_steps # time step size alpha = 3 # parameter alpha beta = 1.2 # parameter beta # Create mesh and define function space nx = ny = 8 mesh = fenics.UnitSquareMesh(nx, ny) V = fenics.FunctionSpace(mesh, 'P', 1) # Define boundary condition u_D = fenics.Expression('1 + x[0]*x[0] + alpha*x[1]*x[1] + beta*t', degree=2, alpha=alpha, beta=beta, t=0) def boundary(x, on_boundary): return on_boundary bc = fenics.DirichletBC(V, u_D, boundary) # Define initial value u_n = fenics.interpolate(u_D, V) #u_n = project(u_D, V) # Define variational problem u = fenics.TrialFunction(V) v = fenics.TestFunction(V) f = fenics.Constant(beta - 2 - 2 * alpha) F = u * v * fenics.dx + dt * fenics.dot(fenics.grad(u), fenics.grad( v)) * fenics.dx - (u_n + dt * f) * v * fenics.dx a, L = fenics.lhs(F), fenics.rhs(F) # Time-stepping u = fenics.Function(V) t = 0 vtkfile = fenics.File( os.path.join(os.path.dirname(__file__), 'output', 'heat_constructed_solution', 'solution.pvd')) not_initialised = True for n in range(num_steps): # Update current time t += dt u_D.t = t # Compute solution fenics.solve(a == L, u, bc) # Plot the solution vtkfile << (u, t) fenics.plot(u) if not_initialised: animation_camera = celluloid.Camera(plt.gcf()) not_initialised = False animation_camera.snap() # Compute error at vertices u_e = fenics.interpolate(u_D, V) error = np.abs(u_e.vector().get_local() - u.vector().get_local()).max() print('t = %.2f: error = %.3g' % (t, error)) # Update previous solution u_n.assign(u) # Hold plot animation = animation_camera.animate() animation.save( os.path.join(os.path.dirname(__file__), 'output', 'heat_equation.mp4'))
def solve_heat_with_fem(lightweight=False): T = 2.0 # final time num_steps = 100 # number of time steps dt = T / num_steps # time step size alpha = 3 # parameter alpha beta = 1.2 # parameter beta # Create mesh and define function space nx = ny = 8 mesh = fs.UnitSquareMesh(nx, ny) V = fs.FunctionSpace(mesh, 'P', 1) # Define boundary condition u_D = fs.Expression('1 + x[0]*x[0] + alpha*x[1]*x[1] + beta*t', degree=2, alpha=alpha, beta=beta, t=0) bc = fs.DirichletBC(V, u_D, boundary) # Define initial value u_n = fs.interpolate(u_D, V) # u_n = project(u_D, V) # Define variational problem u = fs.TrialFunction(V) v = fs.TestFunction(V) f = fs.Constant(beta - 2 - 2 * alpha) F = u * v * fs.dx + dt * fs.dot( fs.grad(u), fs.grad(v)) * fs.dx - (u_n + dt * f) * v * fs.dx a, L = fs.lhs(F), fs.rhs(F) # Time-stepping u = fs.Function(V) t = 0 images1d = [] for n in range(num_steps): # Update current time t += dt u_D.t = t # Compute solution fs.solve(a == L, u, bc) # Restore numpy object image1d = np.empty((81, ), dtype=np.float) for v in fs.vertices(mesh): image1d[v.index()] = u(*mesh.coordinates()[v.index()]) images1d.append(image1d) if not lightweight: # Compute error at vertices u_e = fs.interpolate(u_D, V) error = np.abs(u_e.vector().get_local() - u.vector().get_local()).max() print('t = %.2f: error = %.3g' % (t, error)) # Update previous solution u_n.assign(u) # Plotting if not lightweight: fs.plot(u) plt.show() save_dynamic_contours(images1d, 1.0, 1.0, 'heat2d') return images1d
def half_exp_dyn(w0, dt=1.e-5, t_end=1.e-4, show_plots=False): u0 = w0.u p0 = w0.p v0 = w0.v bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_u, V_pv.sub(0), V_pv.sub(1), boundaries) F = deformation_grad(u0) I_1, I_2, J = invariants(F) F_iso = isochronic_deformation_grad(F, J) #I_1_iso, I_2_iso = invariants(F_iso)[0:2] W = material_mooney_rivlin(I_1, I_2, c_10, c_01) g = incompr_constr(J) # Lagrange function (without constraint) L = -W P = first_piola_stress(L, F) G = incompr_stress(g, F) # a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v1, eta) * dx u1 = fe.TrialFunction(V_u) eta = fe.TestFunction(V_u) #u11 = fe.Function(V_u) #F1 = deformation_grad(u11) #g1 = incompr_constr(fe.det(F1)) #G1 = incompr_stress(g1, F1) (p1, v1) = fe.TrialFunctions(V_pv) (q, xi) = fe.TestFunctions(V_pv) a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v0, eta) * dx a_dyn_p = fe.tr(G * grad(v1)) * q * dx #a_dyn_v = rho*inner(v1-v0, xi)*dx + dt*(inner(P + p0*G, grad(xi))*dx - inner(B, xi)*dx) a_dyn_v = rho * inner(v1 - v0, xi) * dx + dt * (inner( P, grad(xi)) * dx + inner(p1 * G, grad(xi)) * dx - inner(B, xi) * dx) a_u = fe.lhs(a_dyn_u) l_u = fe.rhs(a_dyn_u) a_pv = fe.lhs(a_dyn_p + a_dyn_v) l_pv = fe.rhs(a_dyn_p + a_dyn_v) u1 = fe.Function(V_u) pv1 = fe.Function(V_pv) sol = [] vol = fe.assemble(1. * dx) A_u = fe.assemble(a_u) A_pv = fe.assemble(a_pv) for bc in bcs_u: bc.apply(A_u) t = 0 while t < t_end: print("progress: %f" % (100. * t / t_end)) # update displacement u L_u = fe.assemble(l_u) fe.solve(A_u, u1.vector(), L_u) u0.assign(u1) L_pv = fe.assemble(l_pv) for bc in bcs_p + bcs_v: bc.apply(A_pv, L_pv) fe.solve(A_pv, pv1.vector(), L_pv) if fe.norm(pv1.vector()) > 1e8: print('ERROR: norm explosion') break # update initial values for next step w0.u = u1 w0.pv = pv1 p0.assign(w0.p) v0.assign(w0.v) t += dt if show_plots: # plot result fe.plot(w0.sub(0), mode='displacement') plt.show() # save solutions sol.append(Solution(t=t)) sol[-1].upv.assign(w0) return sol, W
v_old.vector()[:], a_old.vector()[:] = v_vec, a_vec u_old.vector()[:] = u.vector() #Tiempos intermedio entre tn y tn+1 utilizando modelo alfa generalizado def avg(x_old, x_new, alpha): return alpha * x_old + (1 - alpha) * x_new #Formulación variacional a_new = update_a(du, u_old, v_old, a_old, ufl=True) v_new = update_v(a_new, u_old, v_old, a_old, ufl=True) res = m(avg(a_old, a_new, alpha_m), w) + c(avg(v_old, v_new, alpha_f), w) + k( avg(u_old, du, alpha_f), w) - Wext(w) a_form = fnc.lhs(res) L_form = fnc.rhs(res) #Solvers (veremos luego) K, res = fnc.assemble_system(a_form, L_form, bc) solver = fnc.LUSolver(K, 'default') #"mumps") solver.parameters["symmetric"] = True # We now initiate the time stepping loop. We will keep track of the beam vertical tip # displacement over time as well as the different parts of the system total energy. We # will also compute the stress field and save it, along with the displacement field, in # a ``XDMFFile``. # The option `flush_ouput` enables to open the result file before the loop is finished, # the ``function_share_mesh`` option tells that only one mesh is used for all functions # of a given time step (displacement and stress) while the ``rewrite_function_mesh`` enforces # that the same mesh is used for all time steps. These two options enables writing the mesh # information only once instead of :math:`2N_{steps}` times::
def compute_potential_flow(self): class Hole(SubDomain): def inside(s, x, on_boundary): return on_boundary and self.boundary_fnc(x) #class ActiveArea(SubDomain): # def inside(self, x, on_boundary): # return between(x[0], (0., 0.1)) and between(x[1], (0, 0.2)) # Initialize sub-domain instances hole = Hole() # self.activate = ActiveArea() # Initialize mesh function for interior domains self.domains = MeshFunction("size_t", self.mesh, 2) self.domains.set_all(0) # self.activate.mark(self.domains, 1) # Initialize mesh function for boundary domains self.boundaries = MeshFunction("size_t", self.mesh, 1) self.boundaries.set_all(0) hole.mark(self.boundaries, 1) # Define new measures associated with the interior domains and # exterior boundaries self.dx = Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) dx, ds = self.dx, self.ds # Define function space and basis functions V = FunctionSpace(self.mesh, "P", 1) self.V_vel = V phi = TrialFunction(V) # potential v = TestFunction(V) # Define Dirichlet boundary conditions at top and bottom boundaries bcs = [fe.DirichletBC(V, 0.0, self.boundaries, 1)] # Define input data a0 = fe.Constant(1.0) a1 = fe.Constant(0.01) f_water = fe.Constant(self.water_in_flux) # Define the reaction equation # Define variational form F_pot = inner(a0 * grad(phi), grad(v)) * dx - f_water * v * dx # Separate left and right hand sides of equation a, L = fe.lhs(F_pot), fe.rhs(F_pot) # Solve problem phi = fe.Function(V) fe.solve(a == L, phi, bcs) # Evaluate integral of normal gradient over top boundary n = fe.FacetNormal(self.mesh) result_flux = fe.assemble(dot(grad(phi), n) * ds(1)) # test conservation of water expected_flux = -self.water_in_flux * fe.assemble(1 * dx) print("relative error of conservation of water %f" % ((result_flux - expected_flux) / expected_flux)) self.phi = phi self.flow = -grad(phi) # Save result output = fe.File("/tmp/potential.pvd") output << self.phi
def F(self, new_equation): self.LHS = FEN.lhs(new_equation) self.RHS = FEN.rhs(new_equation)
v_old.vector()[:], a_old.vector()[:] = v_vec, a_vec u_old.vector()[:] = u.vector() def avg(x_old, x_new, alpha): return alpha * x_old + (1 - alpha) * x_new # residual a_np1 = update_a(du, u_n, v_n, a_n, ufl=True) v_np1 = update_v(a_np1, u_n, v_n, a_n, ufl=True) res = m(avg(a_n, a_np1, alpha_m), v) + k(avg(u_n, du, alpha_f), v) a_form = lhs(res) L_form = rhs(res) # parameters for Time-Stepping t = 0.0 n = 0 E_ext = 0 displacement_out = File("output/u_fsi.pvd") u_n.rename("Displacement", "") u_np1.rename("Displacement", "") displacement_out << u_n while precice.is_coupling_ongoing(): if precice.is_action_required(
def main(): """Main function. Organizes workflow.""" fname = str(INPUTS['filename']) term = Terminal() print(term.yellow + "Working on file {}.".format(fname) + term.normal) # Load mesh and physical domains from file. mesh = fe.Mesh(fname + ".xml") if INPUTS['saving']['mesh']: fe.File(fname + "_mesh.pvd") << mesh if INPUTS['plotting']['mesh']: fe.plot(mesh, title='Mesh') subdomains = fe.MeshFunction('size_t', mesh, fname + '_physical_region.xml') if INPUTS['saving']['subdomains']: fe.File(fname + "_subdomains.pvd") << subdomains if INPUTS['plotting']['subdomains']: fe.plot(subdomains, title='Subdomains') # function space for temperature/concentration func_space = fe.FunctionSpace(mesh, INPUTS['element_type'], INPUTS['element_degree'], constrained_domain=PeriodicDomain()) # discontinuous function space for visualization dis_func_space = fe.FunctionSpace(mesh, 'DG', INPUTS['element_degree'], constrained_domain=PeriodicDomain()) if ARGS['--verbose']: print('Number of cells:', mesh.num_cells()) print('Number of faces:', mesh.num_faces()) print('Number of edges:', mesh.num_edges()) print('Number of vertices:', mesh.num_vertices()) print('Number of DOFs:', len(func_space.dofmap().dofs())) # temperature/concentration field field = fe.TrialFunction(func_space) # test function test_func = fe.TestFunction(func_space) # function, which is equal to 1 everywhere unit_function = fe.Function(func_space) unit_function.assign(fe.Constant(1.0)) # assign material properties to each domain if INPUTS['mode'] == 'conductivity': mat_prop = SubdomainConstant( subdomains, fe.Constant(INPUTS['conductivity']['gas']), fe.Constant(INPUTS['conductivity']['solid']), degree=0) elif INPUTS['mode'] == 'diffusivity': mat_prop = SubdomainConstant( subdomains, fe.Constant(INPUTS['diffusivity']['gas']), fe.Constant(INPUTS['diffusivity']['solid']) * fe.Constant( INPUTS['solubility'] * gas_constant * INPUTS['temperature']), degree=0) # assign 1 to gas domain, and 0 to solid domain gas_content = SubdomainConstant(subdomains, fe.Constant(1.0), fe.Constant(0.0), degree=0) # define structure of foam over whole domain structure = fe.project(unit_function * gas_content, dis_func_space) # calculate porosity and wall thickness porosity = fe.assemble(structure * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN) * (ZMAX - ZMIN)) print('Porosity: {0}'.format(porosity)) dwall = wall_thickness(porosity, INPUTS['morphology']['cell_size'], INPUTS['morphology']['strut_content']) print('Wall thickness: {0} m'.format(dwall)) # calculate effective conductivity/diffusivity by analytical model if INPUTS['mode'] == 'conductivity': eff_prop = analytical_conductivity( INPUTS['conductivity']['gas'], INPUTS['conductivity']['solid'], porosity, INPUTS['morphology']['strut_content']) print('Analytical model: {0} W/(mK)'.format(eff_prop)) elif INPUTS['mode'] == 'diffusivity': eff_prop = analytical_diffusivity( INPUTS['diffusivity']['solid'] * INPUTS['solubility'], INPUTS['solubility'], porosity, INPUTS['morphology']['cell_size'], dwall, INPUTS['temperature'], INPUTS['morphology']['enhancement_par']) print('Analytical model: {0} m^2/s'.format(eff_prop)) # create system matrix system_matrix = -mat_prop * \ fe.inner(fe.grad(field), fe.grad(test_func)) * fe.dx left_side, right_side = fe.lhs(system_matrix), fe.rhs(system_matrix) # define boundary conditions bcs = [ fe.DirichletBC(func_space, fe.Constant(INPUTS['boundary_conditions']['top']), top_bc), fe.DirichletBC(func_space, fe.Constant(INPUTS['boundary_conditions']['bottom']), bottom_bc) ] # compute solution field = fe.Function(func_space) fe.solve(left_side == right_side, field, bcs) # output temperature/concentration at the boundaries if ARGS['--verbose']: print('Checking periodicity:') print('Value at XMIN:', field(XMIN, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at XMAX:', field(XMAX, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at YMIN:', field((XMIN + XMAX) / 3, YMIN, (ZMIN + ZMAX) / 3)) print('Value at YMAX:', field((XMIN + XMAX) / 3, YMAX, (ZMIN + ZMAX) / 3)) print('Value at ZMIN:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMIN)) print('Value at ZMAX:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMAX)) # calculate flux, and effective properties vec_func_space = fe.VectorFunctionSpace(mesh, INPUTS['element_type'], INPUTS['element_degree']) flux = fe.project(-mat_prop * fe.grad(field), vec_func_space) divergence = fe.project(-fe.div(mat_prop * fe.grad(field)), func_space) flux_x, flux_y, flux_z = flux.split() av_flux = fe.assemble(flux_z * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN)) eff_prop = av_flux * (ZMAX - ZMIN) / (INPUTS['boundary_conditions']['top'] - INPUTS['boundary_conditions']['bottom']) if INPUTS['mode'] == 'conductivity': print('Numerical model: {0} W/(mK)'.format(eff_prop)) elif INPUTS['mode'] == 'diffusivity': print('Numerical model: {0} m^2/s'.format(eff_prop)) # projection of concentration has to be in discontinuous function space if INPUTS['mode'] == 'diffusivity': sol_field = SubdomainConstant( subdomains, fe.Constant(1.0), fe.Constant(INPUTS['solubility'] * gas_constant * INPUTS['temperature']), degree=0) field = fe.project(field * sol_field, dis_func_space) # save results with open(fname + "_eff_prop.csv", 'w') as textfile: textfile.write('eff_prop\n') textfile.write('{0}\n'.format(eff_prop)) fe.File(fname + "_solution.pvd") << field fe.File(fname + "_structure.pvd") << structure if INPUTS['saving']['flux']: fe.File(fname + "_flux.pvd") << flux if INPUTS['saving']['flux_divergence']: fe.File(fname + "_flux_divergence.pvd") << divergence if INPUTS['saving']['flux_components']: fe.File(fname + "_flux_x.pvd") << flux_x fe.File(fname + "_flux_y.pvd") << flux_y fe.File(fname + "_flux_z.pvd") << flux_z # plot results if INPUTS['plotting']['solution']: fe.plot(field, title="Solution") if INPUTS['plotting']['flux']: fe.plot(flux, title="Flux") if INPUTS['plotting']['flux_divergence']: fe.plot(divergence, title="Divergence") if INPUTS['plotting']['flux_components']: fe.plot(flux_x, title='x-component of flux (-kappa*grad(u))') fe.plot(flux_y, title='y-component of flux (-kappa*grad(u))') fe.plot(flux_z, title='z-component of flux (-kappa*grad(u))') if True in INPUTS['plotting'].values(): fe.interactive() print(term.yellow + "End." + term.normal)
def boundary(x, on_boundary): return on_boundary bc = fs.DirichletBC(V, u_D, boundary) # Define initial value u_0 = fs.Expression('exp(-a * pow(x[0], 2) - a * pow(x[1], 2))', degree=2, a=5) u_n = fs.interpolate(u_0, V) # Define variational problem u = fs.TrialFunction(V) v = fs.TestFunction(V) f = fs.Constant(0) F = u * v * fs.dx + dt * fs.dot(fs.grad(u), fs.grad(v)) *fs.dx - (u_n + dt * f) * v * fs.dx a, L = fs.lhs(F), fs.rhs(F) # Create VTK file for saving solution vtkfile = fs.File('heat_gaussian/solution.pvd') # Time-stepping u = fs.Function(V) t = 0 for n in range(num_steps): # Update current time t += dt # Compute solution fs.solve(a == L, u, bc)
def compute_conv_diff_reac(self, initial_condition=None): names = {'Cl', 'Na', 'K'} dt = 0.1 t = 0. t_end = 1. P1 = FiniteElement('P', fe.triangle, 3) element = MixedElement([P1, P1, P1]) V = FunctionSpace(self.mesh, element) self.V_conc = V u_init = Function(V) (u_cl, u_na, u_k) = TrialFunction(V) (v_cl, v_na, v_k) = TestFunction(V) if initial_condition is None: initial_condition = Expression(("exp(-((x[0]-0.1)*(x[0]-0.1)+x[1]*x[1])/0.01)", "exp(-((x[0]-0.12)*(x[0]-0.12)+x[1]*x[1])/0.01)", "0."), element=element) u_init = fe.interpolate(initial_condition, V) u_init_cl = u_init[0] u_init_na = u_init[1] u_init_k = u_init[2] assert (self.flow is not None) n = fe.FacetNormal(self.mesh) dx, ds = self.dx, self.ds flow = 10 * self.flow f_in = fe.Constant(0.00) D = fe.Constant(0.01) k1 = fe.Constant(0.1) k_1 = fe.Constant(0.001) F = ( (u_cl - u_init_cl) * v_cl * dx + dt * D * inner(grad(u_cl), grad(v_cl)) * dx + dt * inner(flow, grad(u_cl)) * v_cl * dx + (u_na - u_init_na) * v_na * dx + dt * D * inner(grad(u_na), grad(v_na)) * dx + dt * inner(flow, grad(u_na)) * v_na * dx + (u_k - u_init_k) * v_k * dx + dt * D * inner(grad(u_k), grad(v_k)) * dx + dt * inner(flow, grad(u_k)) * v_k * dx + f_in * v_cl * dx + f_in * v_na * dx + f_in * v_k * dx + dt * k1 * u_init_cl * u_init_na * v_cl * dx + dt * k1 * u_init_cl * u_init_na * v_na * dx - dt * k1 * u_init_cl * u_init_na * v_k * dx - dt * k_1 * u_init_k * v_cl * dx - dt * k_1 * u_init_k * v_na * dx + dt * k_1 * u_init_k * v_k * dx ) self.F = F a, L = fe.lhs(F), fe.rhs(F) a_mat = fe.assemble(a) L_vec = fe.assemble(L) output1 = fe.File('/tmp/cl_dyn.pvd') output2 = fe.File('/tmp/na_dyn.pvd') output3 = fe.File('/tmp/k_dyn.pvd') output4 = fe.File('/tmp/all_dyn.pvd') # solve self.sol = [] while t < t_end: t = t + dt print(t) u = Function(V) a_mat = fe.assemble(a) L_vec = fe.assemble(L) fe.solve(a_mat, u.vector(), L_vec) # NonlinearVariationalProblem(F,u) u_init.assign(u) u_cl, u_na, u_k = u.split() # u_init_cl.assign(u_cl) # u_init_na.assign(u_na) # u_init_k.assign(u_k) u_cl.rename("cl", "cl") u_na.rename("na", "na") u_k.rename("k", "k") output1 << u_cl, t output2 << u_na, t output3 << u_k, t self.sol.append((u_cl, u_na, u_k)) self.u_cl = u_cl self.u_na = u_na self.u_k = u_k
# The forcing on the rhs of the PDE heat_source = fe.Constant(0.0) # Create the Finite Element Problem u_trial = fe.TrialFunction(lagrange_polynomial_space_first_order) v_test = fe.TestFunction(lagrange_polynomial_space_first_order) weak_form_residuum = (u_trial * v_test * fe.dx + time_step_length * fe.dot( fe.grad(u_trial), fe.grad(v_test), ) * fe.dx - (u_old * v_test * fe.dx + time_step_length * heat_source * v_test * fe.dx)) # We have a linear PDE that is separable into a lhs and rhs weak_form_lhs = fe.lhs(weak_form_residuum) weak_form_rhs = fe.rhs(weak_form_residuum) # The function we will be solving for at each point in time u_solution = fe.Function(lagrange_polynomial_space_first_order) # time stepping n_time_steps = 5 time_current = 0.0 for i in range(n_time_steps): time_current += time_step_length # Finite Element Assembly, BC imprint & solving the linear system fe.solve( weak_form_lhs == weak_form_rhs, u_solution,
def boundary(x, on_boundary): return on_boundary bc = fex.DirichletBC(V, u_D, on_boundary) u_n = project(u_D, V) u_n = interpolate(u_D < V) u = fex.TrialFunction(V) v = fex.TestFunctin(V) f = fex.Constant(beta - 2 - 2 * alpha) F = u * v * dx + dt * fex.dot(fex.grad(u), fex.grad(v)) * dx - (u_n + dt * f) * dx a, L = fex.lhs(F), fex.rhs(F) u = fex.Function(V) t = 0 for n in range(num_steps): #Update current time t += dt u_D.t = t #Solve variational problem fex.solve(a == L, u, bc) #Update previous solution u_n.assign(u)
def solve_cell_problems(self, method='regularized', plot=False): """ Solve the cell problems for the given PDE by changing the geometry to exclude the zone in the middle :return: """ class PeriodicBoundary(fe.SubDomain): # Left boundary is "target domain" G def inside(self, x, on_boundary): par = MembraneSimulator.w / MembraneSimulator.length tol = 1E-4 return on_boundary and x[1] >= -tol and x[1] <= tol # Map right boundary (H) to left boundary (G) def map(self, x, y): y[1] = x[1] + 2 * self.eta / MembraneSimulator.length y[0] = x[0] mesh_size = 50 # Domain if method == 'circle': self.obstacle_radius = self.eta / MembraneSimulator.length / 2 box_begin_point = fe.Point(-self.w / MembraneSimulator.length, 0) box_end_point = fe.Point(self.w / MembraneSimulator.length, 2 * self.eta / MembraneSimulator.length) box = mshr.Rectangle(box_begin_point, box_end_point) cell = box - mshr.Circle( fe.Point(0, self.eta / MembraneSimulator.length), self.obstacle_radius, mesh_size) self.cell_mesh = mshr.generate_mesh(cell, mesh_size) diff_coef = fe.Constant( ((0, 0), (0, self.D[1, 1]))) # limit for regularisation below. # elif method == 'diff_coef': # print("Haha this is going to crash. Also it is horrible in accuracy") # self.cell_mesh = fe.RectangleMesh(fe.Point(-self.w / MembraneSimulator.length, 0), # fe.Point(self.w / MembraneSimulator.length, # 2 * self.eta / MembraneSimulator.length), mesh_size, mesh_size) # diff_coef = fe.Expression( # (('0', '0'), ('0', 'val * ((x[0] - c_x)*(x[0] - c_x) + (x[1] - c_y)*(x[1] - c_y) > r*r)')), # val=(4 * self.ref_T * MembraneSimulator.d2 / MembraneSimulator.length ** 2), c_x=0, # c_y=(self.eta / MembraneSimulator.length), # r=self.obstacle_radius, degree=2, domain=self.cell_mesh) elif method == 'regularized': box_begin_point = fe.Point(-self.w / MembraneSimulator.length, 0) box_end_point = fe.Point(self.w / MembraneSimulator.length, 2 * self.eta / MembraneSimulator.length) box = mshr.Rectangle(box_begin_point, box_end_point) obstacle_begin_point = fe.Point( -self.w / MembraneSimulator.length * self.obs_length, self.eta / MembraneSimulator.length * (1 - self.obs_height)) obstacle_end_point = fe.Point( self.w / MembraneSimulator.length * self.obs_length, self.eta / MembraneSimulator.length * (1 + self.obs_height)) obstacle = mshr.Rectangle(obstacle_begin_point, obstacle_end_point) cell = box - obstacle self.cell_mesh = mshr.generate_mesh(cell, mesh_size) diff_coef = fe.Constant(((self.obs_ratio * self.D[0, 0], 0), (0, self.D[1, 1]))) # defect matrix. else: raise ValueError("%s not a valid method to solve cell problem" % method) self.cell_fs = fe.FunctionSpace(self.cell_mesh, 'P', 2) self.cell_solutions = [ fe.Function(self.cell_fs), fe.Function(self.cell_fs) ] w = fe.TrialFunction(self.cell_fs) phi = fe.TestFunction(self.cell_fs) scaled_unit_vectors = [ fe.Constant((1. / np.sqrt(self.obs_ratio), 0.)), fe.Constant((0., 1.)) ] for i in range(2): weak_form = fe.dot( diff_coef * (fe.grad(w) + scaled_unit_vectors[i]), fe.grad(phi)) * fe.dx print("Solving cell problem") bc = fe.DirichletBC(self.cell_fs, fe.Constant(0), MembraneSimulator.cell_boundary) if i == 0: # Periodicity is applied automatically bc = None fe.solve( fe.lhs(weak_form) == fe.rhs(weak_form), self.cell_solutions[i], bc) if plot: plt.rc('text', usetex=True) f = fe.plot(self.cell_solutions[i]) plt.colorbar(f) plt.title(r'Solution to cell problem $w_%d$' % (i + 1)) plt.xlabel(r'$Y_1$') plt.ylabel(r'$Y_2$') print("Cell solution") print(np.min(self.cell_solutions[i].vector().get_local()), np.max(self.cell_solutions[i].vector().get_local())) plt.show()
# Define strain-rate tensor def epsilon(u): return fs.sym(fs.nabla_grad(u)) # Define stress tensor def sigma(u, p): return 2*mu*epsilon(u) - p*fs.Identity(len(u)) # Define variational problem for step 1 (Tentative velocity step) F1 = rho*fs.dot((u - u_n) / k, v)*fs.dx + \ rho*fs.dot(fs.dot(u_n, fs.nabla_grad(u_n)), v)*fs.dx \ + fs.inner(sigma(U, p_n), epsilon(v))*fs.dx \ + fs.dot(p_n*n, v)*fs.ds - fs.dot(mu*fs.nabla_grad(U)*n, v)*fs.ds \ - fs.dot(f, v)*fs.dx a1 = fs.lhs(F1) L1 = fs.rhs(F1) # Define variational problem for step 2 (Pressure correction step) a2 = fs.dot(fs.nabla_grad(p), fs.nabla_grad(q))*fs.dx L2 = fs.dot(fs.nabla_grad(p_n), fs.nabla_grad(q))*fs.dx \ - (1/k)*fs.div(u_)*q*fs.dx # Define variational problem for step 3 (Velocity correction step) a3 = fs.dot(u, v)*fs.dx L3 = fs.dot(u_, v)*fs.dx - k*fs.dot(fs.nabla_grad(p_ - p_n), v)*fs.dx # Assemble matrices A1 = fs.assemble(a1) A2 = fs.assemble(a2) A3 = fs.assemble(a3)
def solve_flem(model_space, physical_space, flow, u_n, mesh, V, bc, dt, num_steps, out_time, plot, statistics, name): """ Solve for landscape evolution This function does hte hard work. First the model domain is created. Then we loop through time and solve the diffusion equation to solve for landscape evolution. Output can be saved as vtk files at every "out_time" specified. Plots using fenics inbuilt library can be visualised at every "plot_time" This function returns a 1d numpy array of time, sediment flux and if statistics is turned on a 2d numpy array of the final wavelength of the landscape. :param model_space: list of domain variables, [lx,ly,res] :param physical_space: list of physical parameters, [kappa, c, nexp, alpha, U] :param flow: 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell :param u_n: elevation function :param mesh: dolphyn mesh :param V: fenics functionspace :param bc: boundary conditions :param dt: time step size in years :param num_steps: number of time steps :param out_time: time steps to output vtk files (0=none) :param plot: plot sediment flux (0=off,1=on) :param statistics: output statistics of landscape (0=off,1=on) :param name: directory name for output vtk files :return: sed_flux, time, wavelength """ # Domain dimensions lx = model_space[0] ly = model_space[1] # Physical parameters kappa = physical_space[0] # diffusion coefficient c = physical_space[1] # discharge transport coefficient nexp = physical_space[2] # discharge exponent alpha = physical_space[3] # precipitation rate De = c * pow(alpha * ly, nexp) / kappa uamp = physical_space[4] * ly / kappa # uplift dt = dt * kappa / (ly * ly) # time step size sed_flux = np.zeros(num_steps) # array to store sediment flux time = np.zeros(num_steps) # Define variational problem u = TrialFunction(V) v = TestFunction(V) f = Constant(uamp) # 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell if flow == 0: q_n = mfd_nodenode(mesh, V, u_n, De, nexp) if flow == 1: q_n = mfd_cellcell(mesh, V, u_n, De, nexp) if flow == 2: q_n = sd_nodenode(mesh, V, u_n, De, nexp) if flow == 3: q_n = sd_cellcell(mesh, V, u_n, De, nexp) F = u * v * dx + dt * q_n * dot(grad(u), grad(v)) * dx - (u_n + dt * f) * v * dx a, L = lhs(F), rhs(F) # Solution and sediment flux u = Function(V) q_s = Expression('u0 + displ - u1', u0=u_n, displ=Constant(uamp * dt), u1=u, degree=2) # Iterate t = 0 i = 0 for n in range(num_steps): # This needs to become an option! # Double rain fall # if n == 501: # alpha = 2 # De = c*pow(alpha*ly,nexp)/kappa # Update current time t += dt # Compute solution solve(a == L, u, bc) # Calculate sediment flux sed_flux[i] = assemble(q_s * dx(mesh)) time[i] = t i += 1 # Update previous solution u_n.assign(u) # Update flux # 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell if flow == 0: q = mfd_nodenode(mesh, V, u_n, De, nexp) if flow == 1: q = mfd_cellcell(mesh, V, u_n, De, nexp) if flow == 2: q = sd_nodenode(mesh, V, u_n, De, nexp) if flow == 3: q = sd_cellcell(mesh, V, u_n, De, nexp) q_n.assign(q) # Output solutions if out_time != 0: if np.mod(n, out_time) == 0: filename = '%s/u_solution_%d.pvd' % (name, n) vtkfile = File(filename) vtkfile << u filename = '%s/q_solution_%d.pvd' % (name, n) vtkfile = File(filename) vtkfile << q # Post processing if plot != 0: plt.plot(time * 1e-6 * ly * ly / kappa, sed_flux / dt * kappa, 'k', linewidth=2) plt.xlabel('Time (Myr)') plt.ylabel('Sediment Flux (m^2/yr)') sedname = '%s/sed_flux_%d.svg' % (name, model_space[2]) plt.savefig(sedname, format='svg') plt.clf() if out_time != 0: # Output last elevation filename = '%s/u_solution_%d_%d.pvd' % (name, model_space[2], n) vtkfile = File(filename) u.rename("elv", "elevation") vtkfile << u # Output last water flux filename = '%s/q_solution_%d_%d.pvd' % (name, model_space[2], n) vtkfile = File(filename) q.rename("flx", "flux") vtkfile << q # Calculate valley spacing from peak to peak in water flux tol = 0.001 # avoid hitting points outside the domain y = np.linspace(0 + tol, 1 - tol, 100) x = np.linspace(0.01, lx / ly - 0.01, 20) wavelength = np.zeros(len(x)) if statistics != 0: i = 0 for ix in x: points = [(ix, y_) for y_ in y] # 2D points q_line = np.array([q(point) for point in points]) indexes = peakutils.indexes(q_line, thres=0.05, min_dist=5) if len(indexes) > 1: wavelength[i] = sum(np.diff(y[indexes])) / (len(indexes) - 1) else: wavelength[i] = 0 i += 1 if plot != 0: plt.plot(y * 1e-3 * ly, q_line * kappa / ly, 'k', linewidth=2) plt.plot(y[indexes] * 1e-3 * ly, q_line[indexes] * kappa / ly, '+r') plt.xlabel('Distance (km)') plt.ylabel('Water Flux (m/yr)') watername = '%s/water_flux_spacing_%d.svg' % (name, model_space[2]) plt.savefig(watername, format='svg') plt.clf() return sed_flux, time, wavelength
def main(): """Main function. Organizes workflow.""" fname = str(INPUTS['filename']) term = Terminal() print( term.yellow + "Working on file {}.".format(fname) + term.normal ) # Load mesh and physical domains from file. mesh = fe.Mesh(fname + ".xml") if INPUTS['saving']['mesh']: fe.File(fname + "_mesh.pvd") << mesh if INPUTS['plotting']['mesh']: fe.plot(mesh, title='Mesh') subdomains = fe.MeshFunction( 'size_t', mesh, fname + '_physical_region.xml') if INPUTS['saving']['subdomains']: fe.File(fname + "_subdomains.pvd") << subdomains if INPUTS['plotting']['subdomains']: fe.plot(subdomains, title='Subdomains') # function space for temperature/concentration func_space = fe.FunctionSpace( mesh, INPUTS['element_type'], INPUTS['element_degree'], constrained_domain=PeriodicDomain() ) # discontinuous function space for visualization dis_func_space = fe.FunctionSpace( mesh, 'DG', INPUTS['element_degree'], constrained_domain=PeriodicDomain() ) if ARGS['--verbose']: print('Number of cells:', mesh.num_cells()) print('Number of faces:', mesh.num_faces()) print('Number of edges:', mesh.num_edges()) print('Number of vertices:', mesh.num_vertices()) print('Number of DOFs:', len(func_space.dofmap().dofs())) # temperature/concentration field field = fe.TrialFunction(func_space) # test function test_func = fe.TestFunction(func_space) # function, which is equal to 1 everywhere unit_function = fe.Function(func_space) unit_function.assign(fe.Constant(1.0)) # assign material properties to each domain if INPUTS['mode'] == 'conductivity': mat_prop = SubdomainConstant( subdomains, fe.Constant(INPUTS['conductivity']['gas']), fe.Constant(INPUTS['conductivity']['solid']), degree=0 ) elif INPUTS['mode'] == 'diffusivity': mat_prop = SubdomainConstant( subdomains, fe.Constant(INPUTS['diffusivity']['gas']), fe.Constant(INPUTS['diffusivity']['solid']) * fe.Constant(INPUTS['solubility'] * gas_constant * INPUTS['temperature']), degree=0 ) # assign 1 to gas domain, and 0 to solid domain gas_content = SubdomainConstant( subdomains, fe.Constant(1.0), fe.Constant(0.0), degree=0 ) # define structure of foam over whole domain structure = fe.project(unit_function * gas_content, dis_func_space) # calculate porosity and wall thickness porosity = fe.assemble(structure * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN) * (ZMAX - ZMIN)) print('Porosity: {0}'.format(porosity)) dwall = wall_thickness( porosity, INPUTS['morphology']['cell_size'], INPUTS['morphology']['strut_content']) print('Wall thickness: {0} m'.format(dwall)) # calculate effective conductivity/diffusivity by analytical model if INPUTS['mode'] == 'conductivity': eff_prop = analytical_conductivity( INPUTS['conductivity']['gas'], INPUTS['conductivity']['solid'], porosity, INPUTS['morphology']['strut_content']) print('Analytical model: {0} W/(mK)'.format(eff_prop)) elif INPUTS['mode'] == 'diffusivity': eff_prop = analytical_diffusivity( INPUTS['diffusivity']['solid'] * INPUTS['solubility'], INPUTS['solubility'], porosity, INPUTS['morphology']['cell_size'], dwall, INPUTS['temperature'], INPUTS['morphology']['enhancement_par']) print('Analytical model: {0} m^2/s'.format(eff_prop)) # create system matrix system_matrix = -mat_prop * \ fe.inner(fe.grad(field), fe.grad(test_func)) * fe.dx left_side, right_side = fe.lhs(system_matrix), fe.rhs(system_matrix) # define boundary conditions bcs = [ fe.DirichletBC(func_space, fe.Constant( INPUTS['boundary_conditions']['top']), top_bc), fe.DirichletBC(func_space, fe.Constant( INPUTS['boundary_conditions']['bottom']), bottom_bc) ] # compute solution field = fe.Function(func_space) fe.solve(left_side == right_side, field, bcs) # output temperature/concentration at the boundaries if ARGS['--verbose']: print('Checking periodicity:') print('Value at XMIN:', field(XMIN, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at XMAX:', field(XMAX, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at YMIN:', field((XMIN + XMAX) / 3, YMIN, (ZMIN + ZMAX) / 3)) print('Value at YMAX:', field((XMIN + XMAX) / 3, YMAX, (ZMIN + ZMAX) / 3)) print('Value at ZMIN:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMIN)) print('Value at ZMAX:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMAX)) # calculate flux, and effective properties vec_func_space = fe.VectorFunctionSpace( mesh, INPUTS['element_type'], INPUTS['element_degree'] ) flux = fe.project(-mat_prop * fe.grad(field), vec_func_space) divergence = fe.project(-fe.div(mat_prop * fe.grad(field)), func_space) flux_x, flux_y, flux_z = flux.split() av_flux = fe.assemble(flux_z * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN)) eff_prop = av_flux * (ZMAX - ZMIN) / ( INPUTS['boundary_conditions']['top'] - INPUTS['boundary_conditions']['bottom'] ) if INPUTS['mode'] == 'conductivity': print('Numerical model: {0} W/(mK)'.format(eff_prop)) elif INPUTS['mode'] == 'diffusivity': print('Numerical model: {0} m^2/s'.format(eff_prop)) # projection of concentration has to be in discontinuous function space if INPUTS['mode'] == 'diffusivity': sol_field = SubdomainConstant( subdomains, fe.Constant(1.0), fe.Constant(INPUTS['solubility'] * gas_constant * INPUTS['temperature']), degree=0 ) field = fe.project(field * sol_field, dis_func_space) # save results with open(fname + "_eff_prop.csv", 'w') as textfile: textfile.write('eff_prop\n') textfile.write('{0}\n'.format(eff_prop)) fe.File(fname + "_solution.pvd") << field fe.File(fname + "_structure.pvd") << structure if INPUTS['saving']['flux']: fe.File(fname + "_flux.pvd") << flux if INPUTS['saving']['flux_divergence']: fe.File(fname + "_flux_divergence.pvd") << divergence if INPUTS['saving']['flux_components']: fe.File(fname + "_flux_x.pvd") << flux_x fe.File(fname + "_flux_y.pvd") << flux_y fe.File(fname + "_flux_z.pvd") << flux_z # plot results if INPUTS['plotting']['solution']: fe.plot(field, title="Solution") if INPUTS['plotting']['flux']: fe.plot(flux, title="Flux") if INPUTS['plotting']['flux_divergence']: fe.plot(divergence, title="Divergence") if INPUTS['plotting']['flux_components']: fe.plot(flux_x, title='x-component of flux (-kappa*grad(u))') fe.plot(flux_y, title='y-component of flux (-kappa*grad(u))') fe.plot(flux_z, title='z-component of flux (-kappa*grad(u))') if True in INPUTS['plotting'].values(): fe.interactive() print( term.yellow + "End." + term.normal )
def compute_conv_diff_reac_video(self, initial_condition=None, video_ref=None, video_size=None): names = {'Cl', 'K'} P1 = FiniteElement('P', fe.triangle, 1) element = fe.MixedElement([P1, P1]) V_single = FunctionSpace(self.mesh, P1) V = FunctionSpace(self.mesh, element) self.V_conc = V # load video video = VideoData(element=P1) video.load_video(self.video_filename) if( video_ref is not None and video_size is not None): video.set_reference_frame(video_ref, video_size) print(video) dt = 0.05 t = 0. t_end = 20. u_init = Function(V) (u_cl, u_k) = TrialFunction(V) (v_cl, v_k) = TestFunction(V) #u_na = video if initial_condition is None: #initial_condition = Expression(("f*exp(-0.5*((x[0]-a)*(x[0]-a)+(x[1]-b)*(x[1]-b))/var)/(sqrt(2*pi)*var)", # "0."), a = 80, b= 55, var=10, f=10, pi=fe.pi, element=element) initial_condition = Expression(("f", "0."), a=80, b=55, var=0.1, f=0.1, pi=fe.pi, element=element) u_init = fe.interpolate(initial_condition, V) u_init_cl = u_init[0] u_init_k = u_init[1] u_init_na : VideoData= video assert (self.flow is not None) n = fe.FacetNormal(self.mesh) dx, ds = self.dx, self.ds flow = 5. * self.flow f_in = fe.Constant(0.00) f_in_cl = fe.Constant(-0.05) D = fe.Constant(0.1) C_na = fe.Constant(0.1) k1 = fe.Constant(0.2) k_1 = fe.Constant(0.00001) # explicit F = ( (u_cl - u_init_cl) * v_cl * dx + dt * D * inner(grad(u_cl), grad(v_cl)) * dx + dt * inner(flow, grad(u_cl)) * v_cl * dx #+ (u_na - u_init_na) * v_na * dx #+ dt * D * inner(grad(u_na), grad(v_na)) * dx #+ dt * inner(flow, grad(u_na)) * v_na * dx + (u_k - u_init_k) * v_k * dx + dt * D * inner(grad(u_k), grad(v_k)) * dx + dt * inner(flow, grad(u_k)) * v_k * dx + f_in_cl * v_cl * dx #+ f_in * v_na * dx + f_in * v_k * dx + dt * k1 * u_init_cl * C_na * u_init_na * v_cl * dx #+ dt * k1 * u_init_cl * u_init_na * v_na * dx - dt * k1 * u_init_cl * C_na * u_init_na * v_k * dx - dt * k_1 * u_init_k * v_cl * dx #- dt * k_1 * u_init_k * v_na * dx + dt * k_1 * u_init_k * v_k * dx ) # implicit F = ( (u_cl - u_init_cl) * v_cl * dx + dt * D * inner(grad(u_cl), grad(v_cl)) * dx + dt * inner(flow, grad(u_cl)) * v_cl * dx # + (u_na - u_init_na) * v_na * dx # + dt * D * inner(grad(u_na), grad(v_na)) * dx # + dt * inner(flow, grad(u_na)) * v_na * dx + (u_k - u_init_k) * v_k * dx + dt * D * inner(grad(u_k), grad(v_k)) * dx + dt * inner(flow, grad(u_k)) * v_k * dx + f_in_cl * v_cl * dx # + f_in * v_na * dx + f_in * v_k * dx + dt * k1 * u_cl * C_na * u_init_na * v_cl * dx # + dt * k1 * u_init_cl * u_init_na * v_na * dx - dt * k1 * u_cl * C_na * u_init_na * v_k * dx - dt * k_1 * u_k * v_cl * dx # - dt * k_1 * u_init_k * v_na * dx + dt * k_1 * u_k * v_k * dx ) self.F = F a, L = fe.lhs(F), fe.rhs(F) a_mat = fe.assemble(a) L_vec = fe.assemble(L) output1 = fe.File('/tmp/cl_dyn.pvd') output2 = fe.File('/tmp/na_dyn.pvd') output3 = fe.File('/tmp/k_dyn.pvd') output4 = fe.File('/tmp/all_dyn.pvd') # solve self.sol = [] u_na = Function(V_single) u_na = fe.interpolate(u_init_na,V_single) na_inflow = 0 t_plot = 0.5 t_last_plot = 0 while t < t_end: t = t + dt t_last_plot += dt print(t) u = Function(V) u_init_na.set_time(5*t) a_mat = fe.assemble(a) L_vec = fe.assemble(L) fe.solve(a_mat, u.vector(), L_vec) # NonlinearVariationalProblem(F,u) u_init.assign(u) u_cl, u_k = u.split() # u_init_cl.assign(u_cl) # u_init_na.assign(u_na) # u_init_k.assign(u_k) u_na = fe.interpolate(u_init_na, V_single) u_cl.rename("cl", "cl") u_na.rename("na", "na") u_k.rename("k", "k") output1 << u_cl, t output2 << u_na, t output3 << u_k, t self.sol.append((u_cl, u_na, u_k)) print( fe.assemble(u_cl*self.dx)) if t_last_plot > t_plot: t_last_plot = 0 plt.figure(figsize=(8,16)) plt.subplot(211) fe.plot(u_cl) plt.subplot(212) fe.plot(u_k) plt.show() self.u_cl = u_cl #self.u_na = u_na self.u_k = u_k
def solve_linear_pde( u_D_array, T, D=1, C1=0, num_r=100, min_r=0.001, tol=1e-14, degree=1, ): # disable logging set_log_active(False) num_t = len(u_D_array) dt = T / num_t # time step size mesh = IntervalMesh(num_r, min_r, 1) r = mesh.coordinates().flatten() r_args = np.argsort(r) V = FunctionSpace(mesh, "P", 1) # Define boundary conditions # Dirichlet condition at R def boundary_at_R(x, on_boundary): return on_boundary and near(x[0], 1, tol) D = Constant(D) u_D = Constant(u_D_array[0]) bc_at_R = DirichletBC(V, u_D, boundary_at_R) # Define initial values for free c c_0 = Expression("C1", C1=C1, degree=degree) c_n = interpolate(c_0, V) # Define variational problem c = TrialFunction(V) v = TestFunction(V) # define Constants r_squ = Expression("4*pi*pow(x[0],2)", degree=degree) F_tmp = (D * dt * inner(grad(c), grad(v)) * r_squ * dx + c * v * r_squ * dx - c_n * v * r_squ * dx) a, L = lhs(F_tmp), rhs(F_tmp) u = Function(V) data_c = np.zeros((num_t, len(r)), dtype=np.double) for n in range(num_t): u_D.assign(u_D_array[n]) # Compute solution solve(a == L, u, bc_at_R) data_c[n, :] = u.vector().vec().array c_n.assign(u) data_c = data_c[:, r_args[::-1]] r = r[r_args] return data_c, r
def explicit_relax_dyn(w0, kappa=1e5, dt=1.e-5, t_end=1.e-4, show_plots=False): (u0, p0, v0) = fe.split(w0) bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_upv.sub(0), V_upv.sub(1), V_upv.sub(2), boundaries) kappa = fe.Constant(kappa) F = deformation_grad(u0) I_1, I_2, J = invariants(F) F_iso = isochronic_deformation_grad(F, J) #I_1_iso, I_2_iso = invariants(F_iso)[0:2] W = material_mooney_rivlin(I_1, I_2, c_10, c_01) + incompr_relaxation( p0, kappa) g = incompr_constr(J) # Lagrange function (without constraint) L = -W P = first_piola_stress(L, F) G = incompr_stress(g, F) (u1, p1, v1) = fe.TrialFunctions(V_upv) (eta, q, xi) = fe.TestFunctions(V_upv) a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v1, eta) * dx a_dyn_p = (p1 - p0) * q * dx - dt * kappa * div(v1) * J * q * dx #a_dyn_v = rho*inner(v1-v0, xi)*dx + dt*(inner(P + p0*G, grad(xi))*dx - inner(B, xi)*dx) a_dyn_v = rho * inner(v1 - v0, xi) * dx + dt * (inner( P, grad(xi)) * dx + inner(p0 * G, grad(xi)) * dx - inner(B, xi) * dx) a = fe.lhs(a_dyn_u + a_dyn_p + a_dyn_v) l = fe.rhs(a_dyn_u + a_dyn_p + a_dyn_v) w1 = fe.Function(V_upv) w2 = fe.Function(V_upv) sol = [] vol = fe.assemble(1. * dx) t = 0 while t < t_end: print("progress: %f" % (100. * t / t_end)) A = fe.assemble(a) L = fe.assemble(l) for bc in bcs_u + bcs_p + bcs_v: bc.apply(A, L) fe.solve(A, w1.vector(), L) if fe.norm(w1.vector()) > 1e7: print('ERROR: norm explosion') break # update initial values for next step w0.assign(w1) t += dt if show_plots: # plot result fe.plot(w0.sub(0), mode='displacement') plt.show() # save solutions sol.append(Solution(t=t)) sol[-1].upv.assign(w0) return sol, W, kappa
'beta + gamma * x[0] * x[0] - 2 * gamma * t - 2 * (1-gamma) - 2 * alpha', degree=2, alpha=alpha, beta=beta, gamma=gamma, t=0) F = u * v / dt * dx + dot(grad(u), grad(v)) * dx - (u_n / dt + f) * v * dx if problem is ProblemType.DIRICHLET: # apply Dirichlet boundary condition on coupling interface bcs.append(precice.create_coupling_dirichlet_boundary_condition(V)) if problem is ProblemType.NEUMANN: # apply Neumann boundary condition on coupling interface, modify weak form correspondingly F += precice.create_coupling_neumann_boundary_condition(v) a, L = lhs(F), rhs(F) # Time-stepping u_np1 = Function(V) u_np1.rename("Temperature", "") t = 0 # reference solution at t=0 u_ref = interpolate(u_D, V) u_ref.rename("reference", " ") temperature_out = File("out/%s.pvd" % precice.get_solver_name()) ref_out = File("out/ref%s.pvd" % precice.get_solver_name()) error_out = File("out/error%s.pvd" % precice.get_solver_name()) # output solution and reference solution at t=0, n=0
def run_solver_time_dependent( ndim, length, length_unit, bcs, layout_list, u0, powers, nx, coordinates=False, is_plot=False, F=None, vtk=False, ): """求解器主函数. Args: ndim (int): 2 or 3, 问题维数 length (float): board length length_unit (float): unit length bcs (list): bcs layout_list (list): unit 位置 u0 (float): Dirichlet bc 上的值 powers (list): 功率 list nx (int): x 方向上的单元数 coordinates (bool, optional): 是否返回坐标矩阵. Defaults to False. is_plot (bool, optional): 是否画图. Defaults to False. F (ndarray, optional): 热源布局矩阵 F. Defaults to None. vtk (bool): 是否输出 vtk 文件. Returns: tuple: U, xs, ys, zs """ T = 100.0 # final time num_steps = 200 # number of time steps dt = T / num_steps # time step size degree = 1 # degree of function space alpha = 50 # parameter alpha # Create mesh and define function space ny = nx nz = nx if ndim == 3 else None mesh = get_mesh(length, nx, ny, nz) V = fs.FunctionSpace(mesh, "P", degree) # Define boundary condition if len(bcs) > 0 and bcs[0] != []: if ndim == 2: bc_funs = [LineBoundary(line).get_boundary() for line in bcs] else: bc_funs = [RecBoundary(rec).get_boundary() for rec in bcs] else: bc_funs = [lambda x, on_boundary: on_boundary] # 边界都为 Dirichlet # u_D = fs.Constant(u0) u_D = fs.Expression('10 * sin(t / alpha) + u0', degree=2, alpha=alpha, t=0, u0=u0) bcs = [fs.DirichletBC(V, u_D, bc) for bc in bc_funs] # Define initial value u_n = fs.interpolate(u_D, V) # Define viriational problem # 刚的密度和比热容7.9g/cm3和0.46kJ/Kg*C p, c = 7.9, 0.46 pc = p * c * 1000 u = fs.TrialFunction(V) v = fs.TestFunction(V) if F is None: f = Source(layout_list, length, length_unit, powers) else: f = SourceF(F, length) FF = dt * fs.dot(fs.grad(u), fs.grad(v)) * fs.dx + pc * u * v * fs.dx - ( dt * f + pc * u_n) * v * fs.dx a, L = fs.lhs(FF), fs.rhs(FF) # Time-stepping u = fs.Function(V) t = 0 if vtk: vtkfile = fs.File("poisson/solution.pvd") for n in range(num_steps): # Update current time t += dt # Update boundary condition u_D.t = t bcs = [fs.DirichletBC(V, u_D, bc) for bc in bc_funs] # Compute solution fs.solve(a == L, u, bcs) # Save to file and plot solution if vtk: vtkfile << u if is_plot: fs.plot(u) plt.show() # plt.colorbar() # Update previous solution u_n.assign(u) # if ndim == 2: # U = u.compute_vertex_values().reshape(nx + 1, nx + 1) # else: # U = u.compute_vertex_values().reshape(nx + 1, nx + 1, nx + 1) # if coordinates: # xs, ys, zs = get_mesh_grid(length, nx, ny, nz) # else: # xs, ys, zs = None, None, None return u # U, xs, ys, zs