def set_target_velocity(self, u=None, v=None, U=None): """ Set target velocity. Accepts a list of surface velocity data, and generates a dolfin expression from these. Then projects this onto the velocity function space. The sum square error between this velocity and modelled surface velocity is the objective function. :param u : Surface velocity :param v : Surface velocity perpendicular to :attr:`u` :param U : 2-D surface velocity data """ model = self.model S = model.S Q = model.Q if u != None and v != None: model.u_o = project(u, Q) model.v_o = project(v, Q) elif U != None: Smag = project(sqrt(S.dx(0)**2 + S.dx(1)**2 + 1e-10), Q) model.U_o.interpolate(U) model.u_o = project(-model.U_o * S.dx(0) / Smag, Q) model.v_o = project(-model.U_o * S.dx(1) / Smag, Q)
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 output_fn(domain: UDomain, t): time.append(t) lams.append( fe.project(domain.F[0, 0], domain.S).vector().get_local().mean()) stress.append( fe.project(domain.constitutive_model.stress(domain.u)[0, 0], domain.S).vector().get_local().mean())
def _residual(u_n, u_nm1, u_nm2, f_n): """ Compute the residual of the PDE at time step n. """ # BUG: project into higher order functional space? V = u_n.function_space() mesh = V.mesh() basis_degree = V.ufl_element().degree() U = F.FunctionSpace(mesh, "P", basis_degree + 3) f_n_v = F.project(f_n, U).vector()[:] u_nm1_v = F.project(u_nm1, U).vector()[:] u_nm2_v = F.project(u_nm2, U).vector()[:] u_n_ = F.project(u_n, U) u_n_v = u_n_.vector()[:] ddu_n_v = F.project(u_n_.dx(0).dx(0), U).vector()[:] # or use the same order? # f_n_ = F.project(f_n, V).vector()[:] # u_n_ = F.project(u_n, V).vector()[:] # u_nm1_ = F.project(u_nm1, V).vector()[:] # u_nm2_ = F.project(u_nm2, V).vector()[:] # ddu_n = F.project(u_n.dx(0).dx(0), V).vector()[:] R = np.sum(u_n_v - (dt**2) * (c**2) * ddu_n_v - (dt**2) * f_n_v - 2 * u_nm1_v + u_nm2_v) return R
def residual(u_n, u_nm1, u_nm2, f_n, dt, c): ''' Compute the residual of the PDE at time step n. ''' # Project into higher-order functional space V = u_n.function_space() mesh = V.mesh() basis_degree = V.ufl_element().degree() U = F.FunctionSpace(mesh, 'P', basis_degree + 3) f_n_v = F.project(f_n, U).vector()[:] u_nm1_v = F.project(u_nm1, U).vector()[:] u_nm2_v = F.project(u_nm2, U).vector()[:] u_n_ = F.project(u_n, U) u_n_v = u_n_.vector()[:] ddu_n_v = F.project(u_n_.dx(0).dx(0), U).vector()[:] # Or use the space of same degree # f_n_ = F.project(f_n, V).vector()[:] # u_n_ = F.project(u_n, V).vector()[:] # u_nm1_ = F.project(u_nm1, V).vector()[:] # u_nm2_ = F.project(u_nm2, V).vector()[:] # ddu_n = F.project(u_n.dx(0).dx(0), V).vector()[:] R = np.sum(u_n_v - (dt ** 2) * (c ** 2) * ddu_n_v - (dt ** 2) * f_n_v - 2 * u_nm1_v + u_nm2_v) return R
def compute_operators(self): v = fa.Function(self.V) w = fa.Function(self.W) F00 = [] F01 = [] F10 = [] F11 = [] for i in range(self.num_dofs): v.vector()[:] = 0 v.vector()[i] = 1 F = self.DeformationGradient(v) f00 = fa.project(F[0, 0], self.W) f01 = fa.project(F[0, 1], self.W) f10 = fa.project(F[1, 0], self.W) f11 = fa.project(F[1, 1], self.W) F00.append(np.array(f00.vector())) F01.append(np.array(f01.vector())) F10.append(np.array(f10.vector())) F11.append(np.array(f11.vector())) # Do not forget to add 1 later F00 = np.transpose(np.array(F00)) - 1 F01 = np.transpose(np.array(F01)) F10 = np.transpose(np.array(F10)) F11 = np.transpose(np.array(F11)) - 1 F = [F00, F01, F10, F11] np.save(self.args.root_path + '/' + self.args.numpy_path + '/robot/' + 'F' + '.npy', F) return F
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 J(c_array, *args): """ Solve adjoint model, calculate gradient """ # dolfin.adjoint method: n = len(c_array) / len(config['adjoint']['control_variable']) for ii, c in enumerate(config['adjoint']['control_variable']): set_local_from_global(c, c_array[ii * n:(ii + 1) * n]) self.adjoint_instance.solve() # This is not the best place for this, but we leave it here for now # so that we can see the impact of every line search update on the # variables of interest. Js = [] for JJ in self.adjoint_instance.J: Js.extend(get_global(assemble(JJ))) Js = array(Js) # FIXME: project and extrude ruin the output for paraview, we just # save when finished for now. U = project(as_vector([model.u, model.v, model.w])) dSdt = project(- (model.u*model.S.dx(0) + model.v*model.S.dx(1)) \ + model.w + model.adot) file_b_pvd << model.extrude(model.beta2, 3, 2) file_u_pvd << U file_dSdt_pvd << dSdt return Js
def __init__(self, model, config): """ Calculate each of the component stresses which define the full stress of the ice-sheet. RETURNS: tau_lon - longitudinal stress field tau_lat - lateral stress field tau_bas - frictional sliding stress at the bed tau_drv - driving stress of the system Note: tau_drv = tau_lon + tau_lat + tau_bas """ print "::: initializing 'stokes-balance' solver :::" self.model = model self.config = config Q = model.Q u = model.u v = model.v w = model.w S = model.S B = model.B H = S - B eta = model.eta beta2 = model.beta2 # get the values at the bed : beta2_e = model.extrude(beta2, 3, 2, Q) u_b_e = model.extrude(u, 3, 2, Q) v_b_e = model.extrude(v, 3, 2, Q) # vertically average : etabar = model.vert_integrate(eta, Q) etabar = project(model.extrude(etabar, 2, 2, Q) / H) ubar = model.vert_integrate(u, Q) ubar = project(model.extrude(ubar, 2, 2, Q) / H) vbar = model.vert_integrate(v, Q) vbar = project(model.extrude(vbar, 2, 2, Q) / H) # set the model variables so the physics object can solve it : model.beta2_e = beta2_e model.u_b_e = u_b_e model.v_b_e = v_b_e model.etabar = etabar model.ubar = ubar model.vbar = vbar # calculate the driving stress and basal drag once : model.tau_d = model.calc_tau_drv(Q) model.tau_b = model.calc_tau_bas(Q) self.Q = Q self.stress_balance_instance = StokesBalance(model, config)
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 write_results_table_row(self, table_filepath): with open(table_filepath, "a") as table_file: table_file.write( str(self.pressure_penalty_factor.__float__()) + "," \ + str(self.solid_viscosity.__float__()) + "," \ + str(self.temperature_rayleigh_number.__float__()) + "," \ + str(self.concentration_rayleigh_number.__float__()) + ", " \ + str(self.prandtl_number.__float__()) + ", " \ + str(self.stefan_number.__float__()) + ", " \ + str(self.schmidt_number.__float__()) + ", " \ + str(self.liquidus_slope.__float__()) + ", " \ + str(self.pure_liquidus_temperature.__float__()) + ", " \ + str(self.regularization_central_temperature_offset.__float__()) + ", " \ + str(self.regularization_smoothing_parameter.__float__()) + ", " \ + str(1./float(self.uniform_gridsize)) + ", " \ + str(self.timestep_size.__float__()) + ", " \ + str(self.time_order) + ", " \ + str(self.time) + ", ") solid_area = fenics.assemble(self.solid_area_integrand()) area_above_critical_phi = fenics.assemble( self.area_above_critical_phi_integrand()) solute_mass = fenics.assemble(self.solute_mass_integrand()) p, u, T, C = self.solution.leaf_node().split(deepcopy=True) phi = fenics.project(self.semi_phasefield(T=T, C=C), mesh=self.mesh.leaf_node()) Cbar = fenics.project(C * (1. - phi), mesh=self.mesh.leaf_node()) table_file.write( str(solid_area) + ", " \ + str(area_above_critical_phi) + ", " \ + str(solute_mass) + ", " \ + str(p.vector().min()) + ", " \ + str(p.vector().max()) + ", " \ + str(fenics.norm(u.vector(), "linf")) + ", " \ + str(T.vector().min()) + ", " \ + str(T.vector().max()) + ", " \ + str(Cbar.vector().min()) + ", " \ + str(Cbar.vector().max()) + ", " \ + str(phi.vector().min()) + ", " \ + str(phi.vector().max())) table_file.write("\n")
def solve_pde(self): u = fe.Function(self.function_space) v = fe.TestFunction(self.function_space) u_old = fe.project(self.u_0, self.function_space) # Todo: Average right hand side if we choose it non-constant flux = self.dt * fe.dot( self.composed_diff_coef * (fe.grad(u) + self.drift_function(u)), fe.grad(v)) * fe.dx bilin_part = u * v * fe.dx + flux funtional_part = self.rhs * v * self.dt * fe.dx + u_old * v * fe.dx full_form = bilin_part - funtional_part num_steps = int(self.T / self.dt) + 1 bc = fe.DirichletBC(self.function_space, self.u_boundary, MembraneSimulator.full_boundary) for n in range(num_steps): print("Step %d" % n) self.time += self.dt fe.solve(full_form == 0, u, bc) # fe.plot(u) # plt.show() # print(fe.errornorm(u_old, u)) u_old.assign(u) self.file << (u, self.time) f = fe.plot(u) plt.rc('text', usetex=True) plt.colorbar(f, format='%.0e') plt.title(r'Macroscopic density profile of $u(x,t)$ at $t=1$') plt.xlabel(r'$x_1$') plt.ylabel(r'$x_2$') plt.show()
def set_initial_conditions(self): self.current_time = self.initial_time #Initial condition #self.u_n = fe.project(self.boundary_fun, self.function_space) if self.mode == 'test': print('Setting initial conditions') self.boundary_fun.t = self.current_time self.u_n = fe.interpolate(self.boundary_fun, self.function_space) else: if self.dimension == 2: self.u_n = fe.project(self.ic_fun, self.function_space) if self.dimension == 1: #self.u_n = fe.interpolate(fe.Constant(0), self.function_space) #self.u_n.vector()[self.dof_map[0]] = 1 self.boundary_fun.t = self.current_time self.u_n = fe.interpolate(self.boundary_fun, self.function_space) self.u = fe.Function(self.function_space) self.compute_error() self.save_snapshot()
def problem(f, nx=8, ny=8, degrees=[1, 2]): """ Plot u along x=const or y=const for Lagrange elements, of given degrees, on a nx times ny mesh. f is a SymPy expression. """ f = sym.printing.ccode(f) f = fe.Expression(f, degree=2) mesh = fe.RectangleMesh(fe.Point(-1, 0), fe.Point(1, 2), 2, 2) for degree in degrees: if degree == 0: # The P0 element is specified like this in FEniCS V = fe.FunctionSpace(mesh, 'DG', 0) else: # The Lagrange Pd family of elements, d=1,2,3,... V = fe.FunctionSpace(mesh, 'P', degree) u = fe.project(f, V) u_error = fe.errornorm(f, u, 'L2') print('||u-f||=%g' % u_error, degree) comparison_plot2D(u, f, n=50, value=0.4, variation='x', plottitle='Approximation by P%d elements' % degree, filename='approx_fenics_by_P%d' % degree, tol=1E-3)
def compute_gradient(u, mesh): """Computes the gradient of the value field at the mesh points""" W = fen.VectorFunctionSpace(mesh, 'P', 1) gradient = fen.project(fen.grad(u), W) return gradient
def problem(f, nx=8, ny=8, degrees=[1,2]): """ Plot u along x=const or y=const for Lagrange elements, of given degrees, on a nx times ny mesh. f is a SymPy expression. """ f = sym.printing.ccode(f) f = fe.Expression(f) mesh = fe.RectangleMesh( fe.Point(-1, 0), fe.Point(1, 2), 2, 2) for degree in degrees: if degree == 0: # The P0 element is specified like this in FEniCS V = fe.FunctionSpace(mesh, 'DG', 0) else: # The Lagrange Pd family of elements, d=1,2,3,... V = fe.FunctionSpace(mesh, 'P', degree) u = fe.project(f, V) u_error = fe.errornorm(f, u, 'L2') print '||u-f||=%g' % u_error, degree comparison_plot2D( u, f, n=50, value=0.4, variation='x', plottitle='Approximation by P%d elements' % degree, filename='approx_fenics_by_P%d' % degree, tol=1E-3)
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 plot_result(self): # Calculate preliminary relationships dofmap = self.DV.dofmap() cell_dofs = N.array([ dofmap.cell_dofs(c)[0] for c in N.arange(self.mesh.num_cells()) if (self.subdomains[c] in v.tissues["tumour"]["indices"]) ]) volumes = N.array([ d.Cell(self.mesh, c).volume() for c in N.arange(self.mesh.num_cells()) if (self.subdomains[c] in v.tissues["tumour"]["indices"]) ]) # Create a horizontal axis cc_haxis = N.linspace(5000, 1e5, 200) # Calculate the tumour volume; this is what we will compare against tumour_volume = self.get_tumour_volume() # Initialize the output_arrays vector a rescale the x to V/cm output_arrays = [cc_haxis / 100] # Loop through the electrode pairs for i, triple in enumerate(v.electrode_triples): # Project the max e values for this triple to DG0 - this forces an evaluation of the function at the mid-point of each tet, DG0's only DOF e_dg = d.project(self.max_es[i], self.DV) # Calculate the "max e" contribution for each cell contributor = N.vectorize(lambda c: e_dg.vector()[c]) contributions = contributor(cell_dofs) # Sum the tet volumes for tets with a midpoint value greater than x, looping over x as e-norm thresholds (also scale to tumour volume) elim = N.vectorize( lambda x: volumes[contributions > x].sum() / tumour_volume) output_arrays.append(elim(cc_haxis)) # Compile into a convenient array output = N.array(zip(*output_arrays)) # Output cumulative coverage curves as CSV N.savetxt('../%s-coverage_curves.csv' % input_mesh, output) # Plot the coverage curves for (anode, cathode, voltage), a in zip(v.electrode_triples, output_arrays[1:]): P.plot(output_arrays[0], a, label="%d - %d" % (anode, cathode)) # Draw the plot P.draw() P.xlabel(r"Threshold level of $|E|$ ($\mathrm{J}$)") P.ylabel(r"Fraction of tumour beneath level") # Show a legend for the plot P.legend(loc=3) # Display the plot P.savefig('%s-coverage_curves' % input_mesh)
def increase_conductivity(self, cond, e): # Set up the three way choice function intermediate = e * self.k + self.h not_less_than = ufl.conditional(ufl.gt(e, self.threshold_irreversible), self.sigma_end, intermediate) cond_expression = ufl.conditional(ufl.lt(e, self.threshold_reversible), self.sigma_start, not_less_than) # Project this onto the function space cond_function = d.project(ufl.Max(cond_expression, cond), cond.function_space()) cond.assign(cond_function)
def adapt_coarse_solution_to_fine_solution(scalar, coarse_solution, fine_solution, element, absolute_tolerance=1.e-2, maximum_refinement_cycles=6, circumradius_threshold=0.01): """ Refine the mesh of the coarse solution until the interpolation error tolerance is met. """ adapted_coarse_mesh = fenics.Mesh(coarse_solution.function_space().mesh()) adapted_coarse_function_space = fenics.FunctionSpace( adapted_coarse_mesh, element) adapted_coarse_solution = fenics.Function(adapted_coarse_function_space) adapted_coarse_solution.leaf_node().vector( )[:] = coarse_solution.leaf_node().vector() for refinement_cycle in range(maximum_refinement_cycles): cell_markers = fenics.MeshFunction( "bool", adapted_coarse_mesh.leaf_node(), adapted_coarse_mesh.topology().dim(), False) for coarse_cell in fenics.cells(adapted_coarse_mesh.leaf_node()): coarse_value = scalar(adapted_coarse_solution.leaf_node(), coarse_cell.midpoint()) fine_value = scalar(fine_solution.leaf_node(), coarse_cell.midpoint()) if (abs(coarse_value - fine_value) > absolute_tolerance): cell_markers[coarse_cell] = True cell_markers = unmark_cells_below_circumradius( adapted_coarse_mesh.leaf_node(), cell_markers, circumradius_threshold) if any(cell_markers): adapted_coarse_mesh = fenics.refine(adapted_coarse_mesh, cell_markers) adapted_coarse_function_space = fenics.FunctionSpace( adapted_coarse_mesh, element) adapted_coarse_solution = fenics.project( fine_solution.leaf_node(), adapted_coarse_function_space.leaf_node()) else: break return adapted_coarse_solution, adapted_coarse_function_space, adapted_coarse_mesh
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 fenics_p_electric(self, my_d): """ @description: Solve poisson equation to get potential and electric field @Modify: 2021/08/31 """ if "plugin3D" in self.det_model: bc_l = [] bc_l = self.boundary_definition_3D(my_d, "Possion") elif "planar3D" in self.det_model: bc_l = self.boundary_definition_2D(my_d, "Possion") u = fenics.TrialFunction(self.V) v = fenics.TestFunction(self.V) if self.det_dic['name'] == "lgad3D": if self.det_dic['part'] == 2: bond = self.det_dic['bond1'] doping_avalanche = self.f_value(my_d, self.det_dic['doping1']) doping = self.f_value(my_d, self.det_dic['doping2']) f = fenics.Expression('x[2] < width ? doping1 : doping2', degree=1, width=bond, doping1=doping_avalanche, doping2=doping) elif self.det_dic['part'] == 3: bond1 = self.det_dic['bond1'] bond2 = self.det_dic['bond2'] doping1 = self.f_value(my_d, self.det_dic['doping1']) doping2 = self.f_value(my_d, self.det_dic['doping2']) doping3 = self.f_value(my_d, self.det_dic['doping3']) f = fenics.Expression( 'x[2] < bonda ? dopinga : x[2] > bondb ? dopingc : dopingb', degree=1, bonda=bond1, bondb=bond2, dopinga=doping1, dopingb=doping2, dopingc=doping3) else: print("The structure of lgad is wrong.") else: f = fenics.Constant(self.f_value(my_d)) a = fenics.dot(fenics.grad(u), fenics.grad(v)) * fenics.dx L = f * v * fenics.dx # Compute solution self.u = fenics.Function(self.V) fenics.solve(a == L, self.u, bc_l, solver_parameters=dict(linear_solver='gmres', preconditioner='ilu')) #calculate electric field W = fenics.VectorFunctionSpace(self.mesh3D, 'P', 1) self.E_field = fenics.project( fenics.as_vector((self.u.dx(0), self.u.dx(1), self.u.dx(2))), W)
def coarsen(self): """ Remesh and refine the new mesh until the interpolation error tolerance is met. For simplicity, for now we'll consider only one scalar component of the solution. """ time = 0. + self.old_state.time fine_solution = self.state.solution.copy(deepcopy=True) self.setup_coarse_mesh() for refinement_cycle in range( self.coarsening_maximum_refinement_cycles): self.setup_function_space() self.setup_states() self.old_state.time = 0. + time self.old_state.solution = fenics.project( fine_solution.leaf_node(), self.function_space.leaf_node()) if refinement_cycle == self.coarsening_maximum_refinement_cycles: break exceeds_tolerance = fenics.MeshFunction("bool", self.mesh.leaf_node(), self.mesh.topology().dim(), False) exceeds_tolerance.set_all(False) for cell in fenics.cells(self.mesh.leaf_node()): coarse_value = self.old_state.solution.leaf_node()(cell.midpoint())\ [self.coarsening_scalar_solution_component_index] fine_value = fine_solution.leaf_node()(cell.midpoint())\ [self.coarsening_scalar_solution_component_index] if (abs(coarse_value - fine_value) > self.coarsening_absolute_tolerance): exceeds_tolerance[cell] = True if any(exceeds_tolerance): self.mesh = fenics.refine(self.mesh, exceeds_tolerance) else: break self.setup_problem_and_solver() # We broke important references.
def _compute_effective_diffusion(self): # Uses the solutions of the cell problems to compute the harmonic average of the diffusivity for i, j in np.ndindex((self.dim, self.dim)): integrand_ij = fe.project( self.a_y * fe.dot(self.e_is[i] + fe.grad(self.cell_solutions[i]), self.e_is[j] + fe.grad(self.cell_solutions[j])), self.function_space) self.eff_diff[i, j] = fe.assemble(integrand_ij * fe.dx) return fe.Constant(self.eff_diff)
def save_strain_and_params(self, iteration: int) -> None: strain_vec = fenics.project(fenics.sym(fenics.grad(self.fields.u_new)), V=self.tensor_space).vector()[:] strain_tens = np.reshape(strain_vec, newshape=(self.number_of_vertices, 2, 2)) parameters = fenics.project( self.fields.new_constitutive_relation_multiplicative_parameters, V=self.fields.new_constitutive_relation_multiplicative_parameters. function_space()).vector()[:] if self.fields.new_constitutive_relation_multiplicative_parameters.function_space( ).dim() == self.fields.tensor_space.dim(): parameters = np.reshape(parameters, newshape=(self.number_of_vertices, 2, 2)) self.np_files.write(prefix='strain', iteration=iteration, array=strain_tens) self.np_files.write(prefix='params', iteration=iteration, array=parameters)
def mfem(): files = glob.glob('data/pvd/mfem/*') for f in files: try: os.remove(f) except Exception as e: print('Failed to delete {}, reason: {}' % (f, e)) plate = mshr.Rectangle(fe.Point(0, 0), fe.Point(100, 100)) mesh = mshr.generate_mesh(plate, 50) # mesh = fe.RectangleMesh(fe.Point(-2, -2), fe.Point(2, 2), 50, 50) x_hat = fe.SpatialCoordinate(mesh) U = fe.VectorFunctionSpace(mesh, 'CG', 2) V = fe.FunctionSpace(mesh, "CG", 1) W = fe.FunctionSpace(mesh, "DG", 0) # n = 21 # control_points = np.stack((np.linspace(0, 1, n), np.linspace(0, 1, n)), axis=1) # impact_radii = np.linspace(0., 0.5, n) rho_default = 25. / np.sqrt(5) * 2 control_points = np.array([[50., 50.], [62.5, 25.]]) impact_radii = np.array([rho_default, rho_default]) mid_point = np.array([75., 0.]) mid_point1 = np.array([100., 0.]) mid_point2 = np.array([50., 0.]) points = [mid_point, mid_point1, mid_point2] direct_vec = np.array([1., -2]) rotated_vec = np.array([2., 1.]) direct_vec /= np.linalg.norm(direct_vec) rotated_vec /= np.linalg.norm(rotated_vec) directions = [direct_vec, rotated_vec] boundary_info = [points, directions, rho_default] # df, xi = distance_function_segments_ufl(x_hat, control_points, impact_radii) # d = fe.project(df, V) delta_x = map_function_ufl(x_hat, control_points, impact_radii, boundary_info) - x_hat u = fe.project(delta_x, U) # e = fe.Function(U) # int_exp = InterpolateExpression(u, control_points, impact_radii) # e = fe.interpolate(int_exp, U) # int_exp = InterpolateExpression(e, control_points, impact_radii) # e = fe.project(int_exp, U) vtkfile_u = fe.File('data/pvd/mfem/u.pvd') u.rename("u", "u") vtkfile_u << u
def extrapolate_list_forward( space: Space, space_timeline: TimeLine, space_interface: Space, space_interface_timeline: TimeLine, function_name, param: Parameters, transfer_function, subspace_index, ): array = [] space_macrotimestep = space_timeline.head space_interface_macrotimestep = space_interface_timeline.head function = space_interface_macrotimestep.head.functions[function_name] array.append( transfer_function(function, space, space_interface, param, subspace_index)) global_size = space_timeline.size for n in range(global_size): space_microtimestep = space_macrotimestep.head local_size = space_macrotimestep.size - 1 for m in range(local_size): extrapolation_proportion = ( space_macrotimestep.tail.point - space_microtimestep.after.point) / space_macrotimestep.dt function_old = space_interface_macrotimestep.head.functions[ function_name] function_new = space_interface_macrotimestep.tail.functions[ function_name] array.append( project( extrapolation_proportion * transfer_function( function_old, space, space_interface, param, subspace_index, ) + (1.0 - extrapolation_proportion) * transfer_function( function_new, space, space_interface, param, subspace_index, ), space.function_space_split[subspace_index], )) space_microtimestep = space_microtimestep.after space_macrotimestep = space_macrotimestep.after space_interface_macrotimestep = space_interface_macrotimestep.after return array
def project_function(self, v, **kwargs): """ Project v onto the job's element, V. Args: v (?): The function to project. **kwargs: Valid `fenics.project` kwargs (except `V`, which is provided automatically). Returns: (?): Projected function. """ return FEN.project(v, V=self.V, **kwargs)
def compute_errors(u_approx, u_ref, V, total_error_tol=10**-4): error_normalized = (u_ref - u_approx) / u_ref # compute pointwise L2 error error_pointwise = project(abs(error_normalized), V) # project onto function space error_total = sqrt( assemble(inner(error_pointwise, error_pointwise) * dx)) # determine L2 norm to estimate total error error_pointwise.rename("error", " ") assert (error_total < total_error_tol) return error_total, error_pointwise
def postprocess(fname, field, cond): """Postprocessing of the simulation.""" func_space = field.function_space() mesh = func_space.mesh() degree = func_space.ufl_element().degree() vec_func_space = fe.VectorFunctionSpace(mesh, INPUTS['element_type'], degree) flux = fe.project(-cond * fe.grad(field), vec_func_space) divergence = fe.project(-fe.div(cond * 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)) keff = av_flux * (ZMAX - ZMIN) / (INPUTS['boundary_conditions']['top'] - INPUTS['boundary_conditions']['bottom']) print('Effective conductivity: {0}'.format(keff)) with open(fname + "_keff.csv", 'w') as textfile: textfile.write('keff\n') textfile.write('{0}\n'.format(keff)) fe.File(fname + "_solution.pvd") << field 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 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()
def Vufl(soln, t): "Make a UFL object for plotting V" split = fe.split(soln.function) irho = split[0] iUs = split[1:] soln.ksdg.set_time(t) V = (soln.V(iUs, irho, params=soln.ksdg.iparams) / (soln.ksdg.iparams['sigma']**2 / 2)) fs = soln.function.function_space() cell = fs.ufl_cell() CE = fe.FiniteElement('CG', cell, soln.degree) CS = fe.FunctionSpace(fs.mesh(), CE) pV = fe.project(V, CS, solver_type='petsc') return pV
def plot_result(self): # Calculate preliminary relationships dofmap = self.DV.dofmap() cell_dofs = N.array([dofmap.cell_dofs(c)[0] for c in N.arange(self.mesh.num_cells()) if (self.subdomains[c] in v.tissues["tumour"]["indices"])]) volumes = N.array([d.Cell(self.mesh, c).volume() for c in N.arange(self.mesh.num_cells()) if (self.subdomains[c] in v.tissues["tumour"]["indices"])]) # Create a horizontal axis cc_haxis = N.linspace(5000, 1e5, 200) # Calculate the tumour volume; this is what we will compare against tumour_volume = self.get_tumour_volume() # Initialize the output_arrays vector a rescale the x to V/cm output_arrays = [cc_haxis / 100] # Loop through the electrode pairs for i, triple in enumerate(v.electrode_triples): # Project the max e values for this triple to DG0 - this forces an evaluation of the function at the mid-point of each tet, DG0's only DOF e_dg = d.project(self.max_es[i], self.DV) # Calculate the "max e" contribution for each cell contributor = N.vectorize(lambda c: e_dg.vector()[c]) contributions = contributor(cell_dofs) # Sum the tet volumes for tets with a midpoint value greater than x, looping over x as e-norm thresholds (also scale to tumour volume) elim = N.vectorize(lambda x: volumes[contributions > x].sum() / tumour_volume) output_arrays.append(elim(cc_haxis)) # Compile into a convenient array output = N.array(zip(*output_arrays)) # Output cumulative coverage curves as CSV N.savetxt('results/%s-coverage_curves.csv' % input_mesh, output) # Plot the coverage curves for (anode, cathode, voltage), a in zip(v.electrode_triples, output_arrays[1:]): P.plot(output_arrays[0], a, label="%d - %d" % (anode, cathode)) # Draw the plot P.draw() P.xlabel(r"Threshold level of $|E|$ ($\mathrm{J}$)") P.ylabel(r"Fraction of tumour beneath level") # Show a legend for the plot P.legend(loc=3) # Display the plot P.savefig('%s-coverage_curves' % input_mesh)
def solve(self): # TODO: when FEniCS ported to Python3, this should be exist_ok try: os.makedirs('results') except OSError: pass z, w = (self.z, self.w) u0 = d.Constant(0.0) # Define the linear and bilinear forms L = u0 * w * dx # Define useful functions cond = d.Function(self.DV) U = d.Function(self.V) # Initialize the max_e vector, that will store the cumulative max e values max_e = d.Function(self.V) max_e.vector()[:] = 0.0 max_e.rename("max_E", "Maximum energy deposition by location") max_e_file = d.File("results/%s-max_e.pvd" % input_mesh) max_e_per_step = d.Function(self.V) max_e_per_step_file = d.File("results/%s-max_e_per_step.pvd" % input_mesh) self.es = {} self.max_es = {} fi = d.File("results/%s-cond.pvd" % input_mesh) potential_file = d.File("results/%s-potential.pvd" % input_mesh) # Loop through the voltages and electrode combinations for i, (anode, cathode, voltage) in enumerate(v.electrode_triples): print("Electrodes %d (%lf) -> %d (0)" % (anode, voltage, cathode)) cond = d.project(self.sigma_start, V=self.DV) # Define the Dirichlet boundary conditions on the active needles uV = d.Constant(voltage) term1_bc = d.DirichletBC(self.V, uV, self.patches, v.needles[anode]) term2_bc = d.DirichletBC(self.V, u0, self.patches, v.needles[cathode]) e = d.Function(self.V) e.vector()[:] = max_e.vector() # Re-evaluate conductivity self.increase_conductivity(cond, e) for j in range(v.max_restarts): # Update the bilinear form a = d.inner(d.nabla_grad(z), cond * d.nabla_grad(w)) * dx # Solve again print(" [solving...") d.solve(a == L, U, bcs=[term1_bc, term2_bc]) print(" ....solved]") # Extract electric field norm for k in range(len(U.vector())): if N.isnan(U.vector()[k]): U.vector()[k] = 1e5 e_new = d.project(d.sqrt(d.dot(d.grad(U), d.grad(U))), self.V) # Take the max of the new field and the established electric field e.vector()[:] = N.array([max(*X) for X in zip(e.vector(), e_new.vector())]) # Re-evaluate conductivity fi << cond self.increase_conductivity(cond, e) potential_file << U # Save the max e function to a VTU max_e_per_step.vector()[:] = e.vector()[:] max_e_per_step_file << max_e_per_step # Store this electric field norm, for this triple, for later reference self.es[i] = e # Store the max of this electric field norm and that for all previous triples max_e_array = N.array([max(*X) for X in zip(max_e.vector(), e.vector())]) max_e.vector()[:] = max_e_array # Create a new max_e function for storage, or it will be overwritten by the next iteration max_e_new = d.Function(self.V) max_e_new.vector()[:] = max_e_array # Store this max e function for the cumulative coverage curve calculation later self.max_es[i] = max_e_new # Save the max e function to a VTU max_e_file << max_e self.max_e_count = i
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 )