def image2fct2D(image_select): """ This function converts a 2D slice of a 3D SimpleITK image instance into a 2D FEniCS function. We use this function to extract a 2D 'labelmap' from a 3D segmentation image. :param image_select: slice id in z direction :return: instance of fenics.Function() """ image_select_np = sitk.GetArrayFromImage(image_select) image_select_np_flat = image_select_np.flatten() origin = image_select.GetOrigin() spacing = image_select.GetSpacing() height = image_select.GetHeight() width = image_select.GetWidth() depts = image_select.GetDepth() # construct rectangular mesh with dofs on pixels p1 = fenics.Point(origin[0], origin[1]) p2 = fenics.Point(origin[0] + spacing[0] * width, origin[1] + spacing[1] * height) nx = int(width - 1) ny = int(height - 1) fenics.parameters["reorder_dofs_serial"] = False mesh_image = fenics.RectangleMesh(p1, p2, nx, ny) n_components = image_select.GetNumberOfComponentsPerPixel() if n_components == 1: V = fenics.FunctionSpace(mesh_image, "CG", 1) else: V = fenics.VectorFunctionSpace(mesh_image, "CG", 1) gdim = mesh_image.geometry().dim() coords = V.tabulate_dof_coordinates().reshape((-1, gdim)) f_img = fenics.Function(V) f_img.vector()[:] = image_select_np_flat fenics.parameters["reorder_dofs_serial"] = True return f_img
def create_fenics_function_from_image_quick(image): origin, size, spacing, extent, dim, vdim = get_measures_from_image(image) # fenics expects number of elements as input argument to Rectangle/BoxMesh # i.e., n_nodes - 1 size_new = size - np.ones_like(size, dtype=int) # construct rectangular/box mesh with dofs on pixels p_min = fenics.Point(extent[0, :]) p_max = fenics.Point(extent[1, :]) if dim == 2: mesh_image = fenics.RectangleMesh(p_min, p_max, *list(size_new)) elif dim == 3: mesh_image = fenics.BoxMesh(p_min, p_max, *list(size_new)) # define value dimensionality if vdim == 1: fenics.parameters["reorder_dofs_serial"] = False V = fenics.FunctionSpace(mesh_image, "CG", 1) else: fenics.parameters["reorder_dofs_serial"] = True V = fenics.VectorFunctionSpace(mesh_image, "CG", 1) # get and assign values image_np = sitk.GetArrayFromImage(image) image_np_flat = image_np.flatten() f_img = fenics.Function(V) f_img.vector()[:] = image_np_flat fenics.parameters["reorder_dofs_serial"] = False return f_img
def add_noise(function, noise_level): noise = fenics.Function(function.function_space()) noise.vector()[:] = noise_level * np.random.randn( len(function.function_space().dofmap().dofs())) fun_with_noise = fenics.project(function + noise, function.function_space(), annotate=False) return fun_with_noise
def load_function_from_xdmf(path_to_file, functionname, functionspace, step=0): mpi_comm_world = fenics.mpi_comm_world() function_file = fenics.XDMFFile(mpi_comm_world, path_to_file) mesh = fenics.Mesh() function_file.read(mesh) f = fenics.Function(functionspace) function_file.read_checkpoint(f, functionname, step) return f
def read_function_hdf5(name, functionspace, path_to_file): if os.path.exists(path_to_file): f = fenics.Function(functionspace) hdf = fenics.HDF5File(functionspace.mesh().mpi_comm(), path_to_file, "r") attr = hdf.attributes(name) #nsteps = attr['count'] dataset = name + "/vector_0" hdf.read(f, dataset) hdf.close() return f
def create_fenics_function_from_image(image): origin, size, spacing, extent, dim, vdim = get_measures_from_image(image) # fenics expects number of elements as input argument to Rectangle/BoxMesh # i.e., n_nodes - 1 size_new = size - np.ones_like(size, dtype=int) # construct rectangular/box mesh with dofs on pixels p_min = fenics.Point(extent[0, :]) p_max = fenics.Point(extent[1, :]) if dim == 2: mesh_image = fenics.RectangleMesh(p_min, p_max, *list(size_new)) elif dim == 3: mesh_image = fenics.BoxMesh(p_min, p_max, *list(size_new)) # define value dimensionality if vdim == 1: V = fenics.FunctionSpace(mesh_image, "CG", 1) else: V = fenics.VectorFunctionSpace(mesh_image, "CG", 1, dim=2) # get and assign values f_img = fenics.Function(V) coord_array, value_array = get_coord_value_array_for_image(image, flat=True) unasigned_coords = assign_values_to_fenics_function( f_img, coord_array, value_array) return f_img
def _setup_problem(self, u_previous): dim = self.geometric_dimension dx = self.subdomains.dx ds = self.subdomains.ds dsn = self.subdomains.dsn mu = mle.compute_mu(self.params.E, self.params.poisson) lmbda = mle.compute_lambda(self.params.E, self.params.poisson) diff_const = self.params.diffusion prolif_rate = self.params.proliferation coupling = self.params.coupling # # This is the mechanical body force if not hasattr(self,'body_force'): self.body_force = fenics.Constant(zeros(dim)) # This is the RD source term if not hasattr(self, 'source_term'): self.source_term = fenics.Constant(0.0) du = fenics.TrialFunction(self.functionspace.function_space) v0, v1 = fenics.TestFunctions(self.functionspace.function_space) self.solution = fenics.Function(self.functionspace.function_space, name='solution_function') self.solution.label = 'solution_function' sol0, sol1 = fenics.split(self.solution) u_previous0, u_previous1 = fenics.split(u_previous) self.logger.info(" - Using non-linear solver") dt = fenics.Constant(float(self.params.sim_time_step)) F_m = fenics.inner(mle.compute_stress(sol0, mu, lmbda), mle.compute_strain(v0)) * dx \ - fenics.inner(mle.compute_stress(v0, mu, lmbda), mle.compute_growth_induced_strain(sol1, coupling, dim)) * dx \ - fenics.inner(self.body_force, v0) * dx \ - self.bcs.implement_von_neumann_bc(v0, subspace_id=0) # integral over ds already included F_rd = sol1 * v1 * dx \ + dt * diff_const * fenics.inner(fenics.grad(sol1), fenics.grad(v1)) * dx \ - u_previous1 * v1 * dx \ - dt * mrd.compute_growth_logistic(sol1, prolif_rate, 1.0) * v1 * dx \ - dt * self.source_term * v1 * dx \ - dt * self.bcs.implement_von_neumann_bc(diff_const * v1, subspace_id=1) # integral over ds already included F = F_m + F_rd J = fenics.derivative(F, self.solution, du) problem = fenics.NonlinearVariationalProblem(F, self.solution, bcs=self.bcs.dirichlet_bcs, J=J) solver = fenics.NonlinearVariationalSolver(problem) prm = solver.parameters prm['nonlinear_solver'] = 'snes' prm['snes_solver']['report'] = False # prm.snes_solver.linear_solver = "lu" # prm.snes_solver.maximum_iterations = 20 # prm.snes_solver.report = True # prm.snes_solver.error_on_nonconvergence = False # prm.snes_solver.preconditioner = 'amg' # prm = solver.parameters.newton_solver # short form -> Newton Solver # prm.absolute_tolerance = 1E-11 # prm.relative_tolerance = 1E-8 # prm.maximum_iterations = 1000 self.solver = solver
def _setup_problem(self, u_previous): dx = self.subdomains.dx ds = self.subdomains.ds dsn = self.subdomains.dsn # Parameters mu_GM = mle.compute_mu(self.params.E_GM, self.params.nu_GM) lmbda_GM = mle.compute_lambda(self.params.E_GM, self.params.nu_GM) mu_WM = mle.compute_mu(self.params.E_WM, self.params.nu_WM) lmbda_WM = mle.compute_lambda(self.params.E_WM, self.params.nu_WM) mu_CSF = mle.compute_mu(self.params.E_CSF, self.params.nu_CSF) lmbda_CSF = mle.compute_lambda(self.params.E_CSF, self.params.nu_CSF) mu_VENT = mle.compute_mu(self.params.E_VENT, self.params.nu_VENT) lmbda_VENT = mle.compute_lambda(self.params.E_VENT, self.params.nu_VENT) mu_OUT = mle.compute_mu(10E3, 0.45) lmbda_OUT = mle.compute_lambda(10E3, 0.45) coupling = self.params.coupling # The following terms are added in governing form testing. # They are not strictly part of the problem but need to be defined if not present! if not hasattr(self, 'body_force'): self.body_force = fenics.Constant(zeros(self.geometric_dimension)) if not hasattr(self, 'rd_source_term'): self.rd_source_term = fenics.Constant(0) du = fenics.TrialFunction(self.functionspace.function_space) v0, v1 = fenics.TestFunctions(self.functionspace.function_space) self.solution = fenics.Function(self.functionspace.function_space) self.solution.label = 'solution_function' sol0, sol1 = fenics.split(self.solution) u_previous0, u_previous1 = fenics.split(u_previous) # Implement von Neuman Boundary Conditions #von_neuman_bc_terms = self._implement_von_neumann_bcs([v0, v1]) #von_neuman_bc_term_mech, von_neuman_bc_term_rd = von_neuman_bc_terms # subspace 0 -> displacements # subspace 1 -> concentration dx_CSF = dx(self.subdomains.get_subdomain_id('CSF')) dx_WM = dx(self.subdomains.get_subdomain_id('WM')) dx_GM = dx(self.subdomains.get_subdomain_id('GM')) dx_Ventricles = dx(self.subdomains.get_subdomain_id('Ventricles')) dt = fenics.Constant(float(self.params.sim_time_step)) dim = self.solution.geometric_dimension() if self.subdomains.get_subdomain_id('outside') is not None: dx_outside = dx(self.subdomains.get_subdomain_id('outside')) F_m_outside = fenics.inner(mle.compute_stress(sol0, mu_OUT, lmbda_OUT), mle.compute_strain(v0)) * dx_outside \ - fenics.inner(mle.compute_stress(v0, mu_OUT, lmbda_OUT),mle.compute_growth_induced_strain(sol1, coupling, dim)) * dx_outside F_rd_outside = dt * fenics.Constant(0) * fenics.inner(fenics.grad(sol1), fenics.grad(v1)) * dx_outside \ - dt * fenics.Constant(0) * v1 * dx_outside else: F_m_outside = 0 F_rd_outside = 0 F_m = fenics.inner(mle.compute_stress(sol0, mu_CSF, lmbda_CSF), mle.compute_strain(v0)) * dx_CSF \ - fenics.inner(mle.compute_stress(v0, mu_CSF, lmbda_CSF), mle.compute_growth_induced_strain(sol1, coupling, dim)) * dx_CSF \ + fenics.inner(mle.compute_stress(sol0, mu_WM, lmbda_WM), mle.compute_strain(v0)) * dx_WM \ - fenics.inner(mle.compute_stress(v0, mu_WM, lmbda_WM), mle.compute_growth_induced_strain(sol1, coupling, dim)) * dx_WM \ + fenics.inner(mle.compute_stress(sol0, mu_GM, lmbda_GM), mle.compute_strain(v0)) * dx_GM \ - fenics.inner(mle.compute_stress(v0, mu_GM, lmbda_GM), mle.compute_growth_induced_strain(sol1, coupling, dim)) * dx_GM \ + fenics.inner(mle.compute_stress(sol0, mu_VENT, lmbda_VENT), mle.compute_strain(v0)) * dx_Ventricles \ - fenics.inner(mle.compute_stress(v0, mu_VENT, lmbda_VENT), mle.compute_growth_induced_strain(sol1, coupling, dim)) * dx_Ventricles \ + F_m_outside # NOTE: No Von Neumann BC implemented here! F_rd = sol1 * v1 * dx \ + dt * fenics.Constant(0) * fenics.inner(fenics.grad(sol1), fenics.grad(v1)) * dx_CSF \ + dt * self.params.D_WM * fenics.inner(fenics.grad(sol1), fenics.grad(v1)) * dx_WM \ + dt * self.params.D_GM * fenics.inner(fenics.grad(sol1), fenics.grad(v1)) * dx_GM \ + dt * fenics.Constant(0) * fenics.inner(fenics.grad(sol1), fenics.grad(v1)) * dx_Ventricles \ - u_previous1 * v1 * dx \ - dt * fenics.Constant(0) * v1 * dx_CSF \ - dt * mrd.compute_growth_logistic(sol1, self.params.rho_WM, 1.0) * v1 * dx_WM \ - dt * mrd.compute_growth_logistic(sol1, self.params.rho_GM, 1.0) * v1 * dx_GM \ - dt * fenics.Constant(0) * v1 * dx_Ventricles \ - dt * self.rd_source_term * v1 * dx \ + F_rd_outside # NOTE: No Von Neumann BC implemented here! F = F_m + F_rd J = fenics.derivative(F, self.solution, du) problem = fenics.NonlinearVariationalProblem( F, self.solution, bcs=self.bcs.dirichlet_bcs, J=J) solver = fenics.NonlinearVariationalSolver(problem) prm = solver.parameters prm['nonlinear_solver'] = 'snes' prm['snes_solver']['linear_solver'] = "lu" prm['snes_solver']['report'] = True prm['snes_solver']['error_on_nonconvergence'] = True prm['snes_solver']['preconditioner'] = 'amg' # prm.snes_solver.linear_solver = "lu" # prm.snes_solver.maximum_iterations = 20 # prm.snes_solver.report = True # prm.snes_solver.error_on_nonconvergence = False # prm.snes_solver.preconditioner = 'amg' # prm = solver.parameters.newton_solver # short form -> Newton Solver # prm.absolute_tolerance = 1E-11 # prm.relative_tolerance = 1E-8 # prm.maximum_iterations = 1000 self.solver = solver
# ============================================================================== # OPTIMISATION # ============================================================================== D = fenics.Constant(0.1) rho = fenics.Constant(0.1) c = fenics.Constant(0.2) u = sim.run_for_adjoint([D, rho, c], output_dir=output_path) disp, conc = fenics.split(u) conc_opt = sim.functionspace.project_over_space(conc, subspace_id=1) disp_opt = sim.functionspace.project_over_space(disp, subspace_id=0) disp_sim_reloaded = fenics.Function( fenics.VectorFunctionSpace(mesh, "Lagrange", 1)) conc_sim_reloaded = fenics.Function(fenics.FunctionSpace(mesh, "Lagrange", 1)) # conc_sim = fenics.Function(sim.functionspace.get_functionspace(subspace_id=1)) # disp_sim = fenics.Function(sim.functionspace.get_functionspace(subspace_id=0)) with fenics.XDMFFile(path_to_xdmf) as infile: infile.read_checkpoint(disp_sim_reloaded, "disp") infile.read_checkpoint(conc_sim_reloaded, "conc") #fenics.errornorm(disp_sim, disp_opt) #fenics.errornorm(conc_sim, conc_sim_target) # plott.show_img_seg_f(function=conc_sim, show=True, # path=os.path.join(output_path, 'conc_target_reloaded.png'), # dpi=300)