def create_initial_folders(folder, restart_folder, sys_comp, tstep, info_red, scalar_components, output_timeseries_as_vector, **NS_namespace): """Create necessary folders.""" info_red("Creating initial folders") # To avoid writing over old data create a new folder for each run if MPI.rank(MPI.comm_world) == 0: try: makedirs(folder) except OSError: pass MPI.barrier(MPI.comm_world) newfolder = path.join(folder, 'data') if restart_folder: newfolder = path.join(newfolder, restart_folder.split('/')[-2]) else: if not path.exists(newfolder): newfolder = path.join(newfolder, '1') else: previous = listdir(newfolder) previous = max(map(eval, previous)) if previous else 0 newfolder = path.join(newfolder, str(previous + 1)) MPI.barrier(MPI.comm_world) if MPI.rank(MPI.comm_world) == 0: if not restart_folder: #makedirs(path.join(newfolder, "Voluviz")) #makedirs(path.join(newfolder, "Stats")) #makedirs(path.join(newfolder, "VTK")) makedirs(path.join(newfolder, "Timeseries")) makedirs(path.join(newfolder, "Checkpoint")) tstepfolder = path.join(newfolder, "Timeseries") tstepfiles = {} comps = sys_comp if output_timeseries_as_vector: comps = ['p', 'u'] + scalar_components for ui in comps: tstepfiles[ui] = XDMFFile(MPI.comm_world, path.join( tstepfolder, ui + '_from_tstep_{}.xdmf'.format(tstep))) tstepfiles[ui].parameters["rewrite_function_mesh"] = False tstepfiles[ui].parameters["flush_output"] = True return newfolder, tstepfiles
def compute_potential(coils, V, dx, mu, sigma, omega, convections, verbose=True, io_submesh=None ): '''Compute the magnetic potential :math:`\Phi` with :math:`A = \exp(i \omega t) \Phi e_{\\theta}` for a number of coils. ''' # Index all coil rings consecutively, starting with 0. # This makes them easier to handle for the equation system. physical_indices = [] new_coils = [] k = 0 for coil in coils: new_coils.append([]) for coil_ring in coil['rings']: new_coils[-1].append(k) physical_indices.append(coil_ring) k += 1 # Set arbitrary reference voltage. v_ref = 1.0 r = Expression('x[0]', degree=1, domain=V.mesh()) # Compute reference potentials for all coil rings. # Prepare the right-hand sides according to :cite:`Cha97`. f_list = [] for k in physical_indices: # Real an imaginary parts. f_list.append({k: (v_ref * sigma[k] / (2 * pi * r), Constant(0.0))}) # Solve. phi_list = solve_maxwell(V, dx, mu, sigma, omega, f_list, convections, tol=1.0e-12, compute_residuals=False, verbose=True ) # Write out these phi's to files. if io_submesh: V_submesh = FunctionSpace(io_submesh, 'CG', 1) W_submesh = V_submesh * V_submesh from dolfin import interpolate, XDMFFile for k, phi in enumerate(phi_list): # Restrict to workpiece submesh. phi_out = interpolate(phi, W_submesh) phi_out.rename('phi%02d' % k, 'phi%02d' % k) # Write to file phi_file = XDMFFile(io_submesh.mpi_comm(), 'phi%02d.xdmf' % k) phi_file.parameters['flush_output'] = True phi_file << phi_out #plot(phi_out) #interactive() # Compute weights for the individual coils. # First get the voltage--coil-current mapping. J = get_voltage_current_matrix(phi_list, physical_indices, dx, sigma, omega, v_ref ) num_coil_rings = len(phi_list) A = numpy.empty((num_coil_rings, num_coil_rings), dtype=J.dtype) b = numpy.empty(num_coil_rings, dtype=J.dtype) for k, coil in enumerate(new_coils): weight_type = coils[k]['c_type'] target_value = coils[k]['c_value'] if weight_type == 'current': A, b = prescribe_current(A, b, coil, target_value) elif weight_type == 'voltage': A, b = prescribe_voltage(A, b, coil, target_value, v_ref, J) else: raise RuntimeError('Illegal weight type \'%r\'.' % weight_type) # TODO write out the equation system to a file if io_submesh: numpy.savetxt('matrix.dat', A) # Solve the system for the weights. weights = numpy.linalg.solve(A, b) ## Prescribe total power. #target_total_power = 4.0e3 ## Compute all coils with reference voltage. #num_coil_rings = J.shape[0] #A = numpy.empty((num_coil_rings, num_coil_rings), dtype=J.dtype) #b = numpy.empty(num_coil_rings) #for k, coil in enumerate(new_coils): # target_value = v_ref # A, b = prescribe_voltage(A, b, coil, target_value, v_ref, J) #weights = numpy.linalg.solve(A, b) #preliminary_voltages = v_ref * weights #preliminary_currents = numpy.dot(J, weights) ## Compute resulting total power. #total_power = 0.0 #for coil_loops in new_coils: # # Currents should be the same all over the entire coil, # # so take currents[coil_loops[0]]. # total_power += 0.5 \ # * numpy.sum(preliminary_voltages[coil_loops]) \ # * preliminary_currents[coil_loops[0]].real # # TODO no abs here ## Scale all voltages by necessary factor. #weights *= numpy.sqrt(target_total_power / total_power) if verbose: info('') info('Resulting voltages, V/sqrt(2):') voltages = v_ref * weights info(' %r' % (abs(voltages) / numpy.sqrt(2))) info('Resulting currents, I/sqrt(2):') currents = numpy.dot(J, weights) info(' %r' % (abs(currents) / numpy.sqrt(2))) info('Resulting apparent powers (per coil):') for coil_loops in new_coils: # With # # v(t) = Im(exp(i omega t) v), # i(t) = Im(exp(i omega t) i), # # the average apparent power over one period is # # P_av = omega/(2 pi) int_0^{2 pi/omega} v(t) i(t) # = 1/2 Re(v i*). # # Currents should be the same all over, so take currents[coil[0]]. # alpha = sum(voltages[coil_loops]) \ * currents[coil_loops[0]].conjugate() power = 0.5 * alpha.real info(' %r' % power) info('') # Compute Phi as the linear combination \sum C_i*phi_i. # The function Phi is guaranteed to fulfill the PDE as well (iff the # the boundary conditions are linear in phi too). # # Form $\sum_l c_l \phi_l$. # https://answers.launchpad.net/dolfin/+question/214172 # # Unfortunately, one cannot just use # Phi[0].vector()[:] += c.real * phi[0].vector() # since phi is from the FunctionSpace V*V and thus .vector() is not # available for the individual components. # Phi = [Constant(0.0), Constant(0.0)] for phi, c in zip(phi_list, weights): # Phi += c * phi Phi[0] += c.real * phi[0] - c.imag * phi[1] Phi[1] += c.imag * phi[0] + c.real * phi[1] # Project the components down to V. This makes various subsequent # computations with Phi faster. Phi[0] = project(Phi[0], V) Phi[0].rename('Re(Phi)', 'Re(Phi)') Phi[1] = project(Phi[1], V) Phi[1].rename('Im(Phi)', 'Im(Phi)') return Phi, voltages
def create_xdmf(path, file_name): f = XDMFFile(COMM, path + '/' + file_name + '.xdmf') # Write out data at every step, at a small performance cost f.parameters['flush_output'] = True f.parameters['rewrite_function_mesh'] = False return f
def forward(mu_expression, lmbda_expression, rho, Lx=10, Ly=10, t_end=1, omega_p=5, amplitude=5000, center=0, target=False): Lpml = Lx / 10 #c_p = cp(mu.vector(), lmbda.vector(), rho) max_velocity = 200 #c_p.max() stable_hx = stable_dx(max_velocity, omega_p) nx = int(Lx / stable_hx) + 1 #nx = max(nx, 60) ny = int(Ly * nx / Lx) + 1 mesh = mesh_generator(Lx, Ly, Lpml, nx, ny) used_hx = Lx / nx dt = stable_dt(used_hx, max_velocity) cfl_ct = cfl_constant(max_velocity, dt, used_hx) print(used_hx, stable_hx) print(cfl_ct) #time.sleep(10) PE = FunctionSpace(mesh, "DG", 0) mu = interpolate(mu_expression, PE) lmbda = interpolate(lmbda_expression, PE) m = 2 R = 10e-8 t = 0.0 gamma = 0.50 beta = 0.25 ff = MeshFunction("size_t", mesh, mesh.geometry().dim() - 1) Dirichlet(Lx, Ly, Lpml).mark(ff, 1) # Create function spaces VE = VectorElement("CG", mesh.ufl_cell(), 1, dim=2) TE = TensorElement("DG", mesh.ufl_cell(), 0, shape=(2, 2), symmetry=True) W = FunctionSpace(mesh, MixedElement([VE, TE])) F = FunctionSpace(mesh, "CG", 2) V = W.sub(0).collapse() M = W.sub(1).collapse() alpha_0 = Alpha_0(m, stable_hx, R, Lpml) alpha_1 = Alpha_1(alpha_0, Lx, Lpml, degree=2) alpha_2 = Alpha_2(alpha_0, Ly, Lpml, degree=2) beta_0 = Beta_0(m, max_velocity, R, Lpml) beta_1 = Beta_1(beta_0, Lx, Lpml, degree=2) beta_2 = Beta_2(beta_0, Ly, Lpml, degree=2) alpha_1 = interpolate(alpha_1, F) alpha_2 = interpolate(alpha_2, F) beta_1 = interpolate(beta_1, F) beta_2 = interpolate(beta_2, F) a_ = alpha_1 * alpha_2 b_ = alpha_1 * beta_2 + alpha_2 * beta_1 c_ = beta_1 * beta_2 Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]]) Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]]) a_ = alpha_1 * alpha_2 b_ = alpha_1 * beta_2 + alpha_2 * beta_1 c_ = beta_1 * beta_2 Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]]) Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]]) # Set up boundary condition bc = DirichletBC(W.sub(0), Constant(("0.0", "0.0")), ff, 1) # Create measure for the source term dx = Measure("dx", domain=mesh) ds = Measure("ds", domain=mesh, subdomain_data=ff) # Set up initial values u0 = Function(V) u0.set_allow_extrapolation(True) v0 = Function(V) a0 = Function(V) U0 = Function(M) V0 = Function(M) A0 = Function(M) # Test and trial functions (u, S) = TrialFunctions(W) (w, T) = TestFunctions(W) g = ModifiedRickerPulse(0, omega_p, amplitude, center) F = rho * inner(a_ * N_ddot(u, u0, a0, v0, dt, beta) \ + b_ * N_dot(u, u0, v0, a0, dt, beta, gamma) + c_ * u, w) * dx \ + inner(N_dot(S, U0, V0, A0, dt, beta, gamma).T * Lambda_e + S.T * Lambda_p, grad(w)) * dx \ - inner(g, w) * ds \ + inner(compliance(a_ * N_ddot(S, U0, A0, V0, dt, beta) + b_ * N_dot(S, U0, V0, A0, dt, beta, gamma) + c_ * S, u, mu, lmbda), T) * dx \ - 0.5 * inner(grad(u) * Lambda_p + Lambda_p * grad(u).T + grad(N_dot(u, u0, v0, a0, dt, beta, gamma)) * Lambda_e \ + Lambda_e * grad(N_dot(u, u0, v0, a0, dt, beta, gamma)).T, T) * dx \ a, L = lhs(F), rhs(F) # Assemble rhs (once) A = assemble(a) # Create GMRES Krylov solver solver = KrylovSolver(A, "gmres") # Create solution function S = Function(W) if target: xdmffile_u = XDMFFile("inversion_temporal_file/target/u.xdmf") pvd = File("inversion_temporal_file/target/u.pvd") xdmffile_u.write(u0, t) timeseries_u = TimeSeries( "inversion_temporal_file/target/u_timeseries") else: xdmffile_u = XDMFFile("inversion_temporal_file/obs/u.xdmf") xdmffile_u.write(u0, t) timeseries_u = TimeSeries("inversion_temporal_file/obs/u_timeseries") rec_counter = 0 while t < t_end - 0.5 * dt: t += float(dt) if rec_counter % 10 == 0: print( '\n\rtime: {:.3f} (Progress: {:.2f}%)'.format( t, 100 * t / t_end), ) g.t = t # Assemble rhs and apply boundary condition b = assemble(L) bc.apply(A, b) # Compute solution solver.solve(S.vector(), b) (u, U) = S.split(True) # Update previous time step update(u, u0, v0, a0, beta, gamma, dt) update(U, U0, V0, A0, beta, gamma, dt) xdmffile_u.write(u, t) pvd << (u, t) timeseries_u.store(u.vector(), t) energy = inner(u, u) * dx E = assemble(energy) print("E = ", E) print(u.vector().max())
# Timestepping Tend = 2.0 dt = Constant(0.02) num_steps = np.rint(Tend / float(dt)) # Output directory store_step = 1 outdir = "./../../results/SlottedDisk_Rotation_AddDelete/" # Mesh mesh = Mesh("./../../meshes/circle_0.xml") mesh = refine(mesh) mesh = refine(mesh) mesh = refine(mesh) outfile = XDMFFile(mesh.mpi_comm(), outdir + "psi_h.xdmf") # Set slotted disk psi0_expr = SlottedDisk(radius=rdisk, center=[xc, yc], width=rwidth, depth=0.0, degree=3, lb=lb, ub=ub) # Function space and velocity field W = FunctionSpace(mesh, "DG", k) psi_h = Function(W) V = VectorFunctionSpace(mesh, "DG", 3)
class Solver: def __init__(self, fbvp, howard_inf=True, return_result=False, output_mode=True, get_error=False, save_dir=None, linear_mode=False, verbose=True, record_control=True): self.fbvp = fbvp self.solver = fbvp.parameters.solver self.howard_inf = howard_inf self.output_mode = output_mode self.get_error = get_error self.return_result = return_result self.linear_mode = linear_mode self.record_control = record_control if self.linear_mode: self.linear_control = 0 self.verbose = verbose # Initialize solution vector with final time data self.v = interpolate(fbvp.parameters.ft, fbvp.V) self.control = interpolate(Constant(0), fbvp.V) if not save_dir: save_dir = f'out/{fbvp.parameters.experiment}/'\ f'{fbvp.parameters.domain}/{fbvp.mesh_name}/v.xdmf' if self.output_mode: self.file = XDMFFile(save_dir) self.file.parameters['rewrite_function_mesh'] = False self.file.write_checkpoint(self.v, 'value_func', fbvp.parameters.T) print('Ready to begin calculation') def time_iter(self): alpha = [0] * self.fbvp.dim # initialize control for k in range(self.fbvp.timesteps - 1, -1, -1): time_start = time.perf_counter() t = k * self.fbvp.timestep_size # Current time # update dirichlet boundary conditions if necessary # TODO: Similar update for Robin boundaries if any(elem in self.fbvp.parameters.time_dependent['boundary'] for elem in self.fbvp.parameters.regions['Dirichlet']): self.update_dirichlet_boundary(t) if self.fbvp.parameters.time_dependent['rhs']: self.fbvp.assemble_RHS(t) if self.fbvp.parameters.time_dependent['pde']: self.fbvp.assemble_HJBe(t + self.fbvp.timestep_size) self.fbvp.assemble_HJBi(t) if self.linear_mode: A = self.fbvp.Ilist[self.linear_control] b = self.v.vector().copy() b[:] = (self.fbvp.Flist[self.linear_control] - self.fbvp.Elist[self.linear_control].dot( np.array(self.v.vector()[:]))) for bc in self.fbvp.dirichlet_bcs: bc.apply(A, b) howit = self.v.vector().copy() self.solver.solve(A, howit, b) else: ell = 0 # iteration counter while ell < self.fbvp.parameters.howmaxit: ell += 1 howit, alpha = self.Howard(self.v.vector(), alpha) self.v.vector()[:] = howit if self.output_mode and k % self.fbvp.parameters.save_interval == 0: self.file.write_checkpoint(self.v, 'value_func', t, XDMFFile.Encoding.HDF5, True) if self.record_control: self.control.vector()[:] = alpha self.file.write_checkpoint(self.control, 'control', t, XDMFFile.Encoding.HDF5, True) time_elapsed = (time.perf_counter() - time_start) if self.verbose: print(f'Time step {self.fbvp.timesteps - k} out of' f' {self.fbvp.timesteps} took {time_elapsed}') if self.return_result: return self.v if self.get_error: error_file_path = (f'out/{self.fbvp.parameters.experiment}/' f'{self.fbvp.parameters.domain}/errors.json') error_calc(self.v, self.fbvp.parameters.v_e, self.fbvp.mesh, self.fbvp.mesh_name, error_file_path) def Howard(self, v, alpha): # v coresponds to v^{k+1}, save it to numpy array spv = np.array(v[:]) Ev = [E.dot(spv) for E in self.fbvp.explicit_matrices] # construct RHS under input control alfa rhs = v.copy() rhs[:] = [ self.fbvp.forcing_terms[control][i] - Ev[control][i] for i, control in enumerate(alpha) ] # initialise vector with correct dimension to store solution how = v.copy() # initalise matrix with a suitable sparameterssity pattern lhs = self.fbvp.implicit_matrices[0].copy() # construct implicit matrix from control alpha for i, control in enumerate(alpha): lhs.set([self.fbvp.implicit_matrices[control].getrow(i)[1]], [i], self.fbvp.implicit_matrices[control].getrow(i)[0]) lhs.apply('insert') # solve linear problem to get next iterate of u for bc in self.fbvp.dirichlet_bcs: bc.apply(lhs, rhs) self.solver.solve(lhs, how, rhs) # Create list of vectors (I*v^k+E*v^{k+1} -F) under different controls spw = np.array(how[:]) multlist = (Imp.dot(spw) + Exp - F for Imp, Exp, F in zip( self.fbvp.scipy_implicit_matrices, Ev, self.fbvp.forcing_terms)) # Loop over vectors of values of (I*v^k+E*v^{k+1} -F) at each node and # record control which optimizes each of them if self.howard_inf: next_ctr = [np.argmin(vector) for vector in zip(*multlist)] else: next_ctr = [np.argmax(vector) for vector in zip(*multlist)] return (how, next_ctr) def update_dirichlet_boundary(self, t): new_dirichlet_bcs = [] for i, region in enumerate(self.fbvp.parameters.regions['Dirichlet']): if region in self.fbvp.parameters.time_dependent['boundary']: new_dirichlet_bcs.append( self.fbvp.parameters.update_dispenser[region](self.fbvp, t)) else: new_dirichlet_bcs.append(self.fbvp.dirichlet_bcs[i]) self.fbvp.dirichlet_bcs = new_dirichlet_bcs
class SolutionFileXDMF(SolutionFile_Base): # DOLFIN 2018.1.0.dev added (throughout the developement cycle) an optional append # attribute to XDMFFile.write_checkpoint, which should be set to its non-default value, # thus breaking backwards compatibility append_attribute = XDMFFile.write_checkpoint.__doc__.find( "append: bool") > -1 def __init__(self, directory, filename): SolutionFile_Base.__init__(self, directory, filename) self._visualization_file = XDMFFile(self._full_filename + ".xdmf") self._visualization_file.parameters["flush_output"] = True self._restart_filename = self._full_filename + "_checkpoint.xdmf" self._restart_file = XDMFFile(self._restart_filename) self._restart_file.parameters["flush_output"] = True @staticmethod def remove_files(directory, filename): SolutionFile_Base.remove_files(directory, filename) # full_filename = os.path.join(str(directory), filename) def remove_files_task(): if os.path.exists(full_filename + ".xdmf"): os.remove(full_filename + ".xdmf") os.remove(full_filename + ".h5") os.remove(full_filename + "_checkpoint.xdmf") os.remove(full_filename + "_checkpoint.h5") parallel_io(remove_files_task) def write(self, function, name, index): time = float(index) # Write visualization file (no append available, will overwrite) self._update_function_container(function) self._visualization_file.write(self._function_container, time) # Write restart file. It might be possible that the solution was written to file in a previous run # and the execution was interrupted before last written index was updated. In this corner case # there would be two functions corresponding to the same time, with two consecutive indices. # For now the inelegant way is to try to read: if that works, assume that we are in the corner case; # otherwise, we are in the standard case and we should write to file. try: if os.path.exists(self._restart_filename): self._restart_file.read_checkpoint(self._function_container, name, index) else: raise RuntimeError except RuntimeError: from dolfin.cpp.log import get_log_level, LogLevel, set_log_level self._update_function_container(function) bak_log_level = get_log_level() set_log_level(int(LogLevel.WARNING) + 1) # disable xdmf logs if self.append_attribute: self._restart_file.write_checkpoint(self._function_container, name, time, append=True) else: self._restart_file.write_checkpoint(self._function_container, name, time) set_log_level(bak_log_level) # Once solutions have been written to file, update last written index self._write_last_index(index) def read(self, function, name, index): if index <= self._last_index: time = float(index) assert os.path.exists(self._restart_filename) self._restart_file.read_checkpoint(function, name, index) self._update_function_container(function) self._visualization_file.write( self._function_container, time) # because no append option is available else: raise OSError
# Helper functions for shape calculus def tan_div(s, n): return div(s) - dot(dot(grad(s), n), n) def dn_mat(s, n): return dot(outer(grad(s) * n, n).T, n) - dot(grad(s).T, n) # Load meshes and mesh-functions used in the MultiMesh from file multimesh = MultiMesh() mfs = [] meshes = [] for i in range(2): mesh_i = Mesh() with XDMFFile("meshes/multimesh_%d.xdmf" % i) as infile: infile.read(mesh_i) mvc = MeshValueCollection("size_t", mesh_i, 1) with XDMFFile("meshes/mf_%d.xdmf" % i) as infile: infile.read(mvc, "name_to_read") mfs.append(cpp.mesh.MeshFunctionSizet(mesh_i, mvc)) meshes.append(mesh_i) multimesh.add(mesh_i) multimesh.build() multimesh.auto_cover(0, Point(1.25, 0.875)) # Create Spatial Coordinates for each mesh x0 = SpatialCoordinate(meshes[0]) x1 = SpatialCoordinate(meshes[1]) def deformation_vector():
def __init__(self, mesh_name, parameters, alpha_range=None): # LOAD MESH AND PARAMETERS self.parameters = parameters self.mesh_name = mesh_name if not alpha_range: self.alpha_range = parameters.alpha_range else: self.alpha_range = alpha_range mesh_path = self.parameters.get_mesh_path() self.mesh = Mesh() with XDMFFile(mesh_path) as f: f.read(self.mesh) print(f'Mesh size= {self.mesh.hmax()}') # dimension of approximation space self.dim = len(self.mesh.coordinates()) print(f'Dimension of solution space is {self.dim}') self.V = FunctionSpace(self.mesh, 'CG', 1) # CG = P1 self.coords = self.mesh.coordinates()[dof_to_vertex_map(self.V)] self.T = self.parameters.T # final time self.w = TrialFunction(self.V) self.u = TestFunction(self.V) ####################################################################### # CONTROL SET CREATION self.control_set = np.linspace(self.alpha_range[0], self.alpha_range[1], self.parameters.control_set_size) self.control_set_size = len(self.control_set) print(f'Discretized control set has size {self.control_set_size}') ####################################################################### # BOUNDARY CONDITIONS parameters.set_boundary_conditions(self.mesh) self.boundary_markers = MeshFunction('size_t', self.mesh, 1) self.boundary_markers.set_all(4) # pylint: disable=no-member for i, omega in self.parameters.omegas.items(): omega.mark(self.boundary_markers, i) self.ds = Measure('ds', domain=self.mesh, subdomain_data=self.boundary_markers) self.dirichlet_bcs = [ DirichletBC(self.V, parameters.RHS_bound[j], self.boundary_markers, j) for j in self.parameters.regions["Dirichlet"] ] # Get indices of dirichlet and robin dofs self.dirichlet_nodes_list = set() self.dirichlet_nodes_dict = {} for j in self.parameters.regions["Dirichlet"]: bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j) self.dirichlet_nodes_list |= set(bc.get_boundary_values().keys()) self.dirichlet_nodes_dict[j] = list( bc.get_boundary_values().keys()) self.robin_nodes_list = set() self.robin_nodes_dict = {} for j in self.parameters.regions["Robin"]: bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j) self.robin_nodes_list |= set(bc.get_boundary_values().keys()) self.robin_nodes_dict[j] = list(bc.get_boundary_values().keys()) bc = DirichletBC(self.V, Constant(0), 'on_boundary') self.boundary_nodes_list = bc.get_boundary_values().keys() self.robint_nodes_list = set() self.robint_nodes_dict = {} for j in self.parameters.regions["RobinTime"]: bc = DirichletBC(self.V, Constant(0), self.boundary_markers, j) self.robint_nodes_list |= set(bc.get_boundary_values().keys()) self.robint_nodes_dict[j] = list(bc.get_boundary_values().keys()) ####################################################################### # ASSEMBLY time_start = time.process_time() self.assemble_diagonal_matrix() # auxilliary generic diagonal matrix # used for vector*matrix multiplication of dolfin matrices self.assemble_lumpedmm() # lumped mass matrix # which serves the role of identity operator self.assemble_laplacian() # discrete laplacian self.ad_data_path = f'out/{self.parameters.experiment}' Path(self.ad_data_path).mkdir(parents=True, exist_ok=True) self.timesteps = self.parameters.get_number_of_timesteps() self.assemble_HJBe() # assembly of explicit operators self.assemble_HJBi() # assembly of implicit operators self.assemble_RHS() # assembly of forcing term print('Final time assembly complete') print(f'Assembly took {time.process_time() - time_start} seconds') print('===========================================================')
def model(self, parameters=None, logger=None): def format(arr): return np.array(arr) # Setup parameters, logger self.set_parameters(parameters) self.set_logger(logger) # Get parameters parameters = self.get_parameters() #SS#if not parameters.get('simulate'): #SS# return # Setup data self.set_data(reset=True) self.set_observables(reset=True) # Show simulation settings self.get_logger()('\n\t'.join([ 'Simulating:', *[ '%s : %r' % (param, parameters[param] if not isinstance( parameters[param], dict) else list(parameters[param])) for param in ['fields', 'num_elem', 'N', 'dt', 'D', 'alpha', 'tol'] ] ])) # Data mesh mesh = IntervalMesh(MPI.comm_world, parameters['num_elem'], parameters['L_0'], parameters['L_1']) # Fields V = {} W = {} fields_n = {} fields = {} w = {} fields_0 = {} potential = {} potential_derivative = {} bcs = {} R = {} J = {} # v2d_vector = {} observables = {} for field in parameters['fields']: # Define functions V[field] = {} w[field] = {} for space in parameters['spaces']: V[field][space] = getattr( dolfin, parameters['spaces'][space]['type'])( mesh, parameters['spaces'][space]['family'], parameters['spaces'][space]['degree']) w[field][space] = TestFunction(V[field][space]) space = V[field][parameters['fields'][field]['space']] test = w[field][parameters['fields'][field]['space']] fields_n[field] = Function(space, name='%sn' % (field)) fields[field] = Function(space, name=field) # Inital condition fields_0[field] = Expression( parameters['fields'][field]['initial'], element=space.ufl_element()) fields_n[field] = project(fields_0[field], space) fields[field].assign(fields_n[field]) # Define potential if parameters['potential'].get('kwargs') is None: parameters['potential']['kwargs'] = {} for k in parameters['potential']['kwargs']: if parameters['potential']['kwargs'][k] is None: parameters['potential']['kwargs'][k] = fields[k] potential[field] = Expression( parameters['potential']['expression'], degree=parameters['potential']['degree'], **parameters['potential']['kwargs']) potential_derivative[field] = Expression( parameters['potential']['derivative'], degree=parameters['potential']['degree'] - 1, **parameters['potential']['kwargs']) #Subdomain for defining Positive grain sub_domains = MeshFunction('size_t', mesh, mesh.topology().dim(), 0) #BC condition bcs[field] = [] if parameters['fields'][field]['bcs'] == 'dirichlet': BC_l = CompiledSubDomain('near(x[0], side) && on_boundary', side=parameters['L_0']) BC_r = CompiledSubDomain('near(x[0], side) && on_boundary', side=parameters['L_1']) bcl = DirichletBC(V, fields_n[field], BC_l) bcr = DirichletBC(V, fields_n[field], BC_r) bcs[field].extend([bcl, bcr]) elif parameters['fields'][field]['bcs'] == 'neumann': bcs[field].extend([]) # Residual and Jacobian R[field] = ( ((fields[field] - fields_n[field]) / parameters['dt'] * test * dx) + (inner(parameters['D'] * grad(test), grad(fields[field])) * dx) + (parameters['alpha'] * potential_derivative[field] * test * dx)) J[field] = derivative(R[field], fields[field]) # Observables observables[field] = {} files = { 'xdmf': XDMFFile(MPI.comm_world, self.get_paths()['xdmf']), 'hdf5': HDF5File(MPI.comm_world, self.get_paths()['hdf5'], 'w'), } files['hdf5'].write(mesh, '/mesh') eps = lambda n, key, field, observables, tol: ( n == 0) or (abs(observables[key]['total_energy'][n] - observables[ key]['total_energy'][n - 1]) / (observables[key]['total_energy'][0]) > tol) flag = {field: True for field in parameters['fields']} tol = { field: parameters['tol'][field] if isinstance( parameters['tol'], dict) else parameters['tol'] for field in parameters['fields'] } phases = {'p': 1, 'm': 2} n = 0 problem = {} solver = {} while (n < parameters['N'] and any([flag[field] for field in parameters['fields']])): self.get_logger()('Time: %d' % (n)) for field in parameters['fields']: if not flag[field]: continue # Solve problem[field] = NonlinearVariationalProblem( R[field], fields[field], bcs[field], J[field]) solver[field] = NonlinearVariationalSolver(problem[field]) solver[field].solve() # Get field array array = assemble( (1 / CellVolume(mesh)) * inner(fields[field], w[field]['Z']) * dx).get_local() # Observables observables[field]['Time'] = parameters['dt'] * n # observables[field]['energy_density'] = format(0.5*dot(grad(fields[field]),grad(fields[field]))*dx) observables[field]['gradient_energy'] = format( assemble(0.5 * dot(grad(fields[field]), grad(fields[field])) * dx(domain=mesh))) observables[field]['landau_energy'] = format( assemble(potential[field] * dx(domain=mesh))) observables[field]['diffusion_energy'] = format( assemble( project( div(project(grad(fields[field]), V[field]['W'])), V[field]['Z']) * dx(domain=mesh)) ) #Diffusion part of chemical potential observables[field]['spinodal_energy'] = format( assemble( potential_derivative[field] * dx(domain=mesh))) #Spinodal part of chemical potential observables[field]['total_energy'] = parameters[ 'D'] * observables[field]['gradient_energy'] + parameters[ 'alpha'] * observables[field]['landau_energy'] observables[field]['chi'] = parameters['alpha'] * observables[ field]['diffusion_energy'] - parameters['D'] * observables[ field]['spinodal_energy'] # Phase observables sub_domains.set_all(0) sub_domains.array()[:] = np.where(array > 0.0, phases['p'], phases['m']) phases_dxp = Measure('dx', domain=mesh, subdomain_data=sub_domains) for phase in phases: dxp = phases_dxp(phases[phase]) observables[field]['Phi_0%s' % (phase)] = format( assemble(1 * dxp)) observables[field]['Phi_1%s' % (phase)] = format( assemble(fields[field] * dxp)) observables[field]['Phi_2%s' % (phase)] = format( assemble(fields[field] * fields[field] * dxp)) observables[field]['Phi_3%s' % (phase)] = format( assemble(fields[field] * fields[field] * fields[field] * dxp)) observables[field]['Phi_4%s' % (phase)] = format( assemble(fields[field] * fields[field] * fields[field] * fields[field] * dxp)) observables[field]['Phi_5%s' % (phase)] = format( assemble(fields[field] * fields[field] * fields[field] * fields[field] * fields[field] * dxp)) observables[field]['gradient_energy_%s' % (phase)] = format( assemble( 0.5 * dot(grad(fields[field]), grad(fields[field])) * dxp)) observables[field]['landau_energy_%s' % (phase)] = format( assemble(potential[field] * dxp)) observables[field][ 'total_energy_%s' % (phase)] = parameters['D'] * observables[field][ 'gradient_energy_%s' % (phase)] + parameters['alpha'] * observables[ field]['landau_energy_%s' % (phase)] observables[field][ 'diffusion_energy_%s' % (phase)] = format( assemble( project( div( project(grad(fields[field]), V[field]['W'])), V[field]['Z']) * dxp)) #Diffusion part of chemical potential observables[field][ 'spinodal_energy_%s' % (phase)] = format( assemble( potential_derivative[field] * dxp)) #Spinodal part of chemical potential observables[field][ 'chi_%s' % (phase)] = parameters['alpha'] * observables[field][ 'spinodal_energy_%s' % (phase)] - parameters['D'] * observables[field][ 'diffusion_energy_%s' % (phase)] files['hdf5'].write(fields[field], '/%s' % (field), n) files['xdmf'].write(fields[field], n) fields_n[field].assign(fields[field]) self.set_data({field: array}) self.set_observables({field: observables[field]}) flag[field] = eps(n, field, fields[field], self.get_observables(), tol[field]) n += 1 for file in files: files[file].close() return
" 0.", ) u_exact = Expression(U_exact, degree=7, U=float(1.0), nu=float(nu), mode=mode) f = Constant((0.0, 0.0, 0.0)) # Create mesh xmin, ymin, zmin = geometry["xmin"], geometry["ymin"], geometry["zmin"] xmax, ymax, zmax = geometry["xmax"], geometry["ymax"], geometry["zmax"] mesh = BoxMesh(MPI.comm_world, Point(xmin, ymin, zmin), Point(xmax, ymax, zmax), nx, ny, nz) pbc = PeriodicBoundary(geometry) # xdmf output xdmf_u = XDMFFile(mesh.mpi_comm(), outdir_base + "u.xdmf") xdmf_p = XDMFFile(mesh.mpi_comm(), outdir_base + "p.xdmf") xdmf_curl = XDMFFile(mesh.mpi_comm(), outdir_base + "curl.xdmf") # Required elements W_E_2 = VectorElement("DG", mesh.ufl_cell(), k) T_E_2 = VectorElement("DG", mesh.ufl_cell(), 0) Wbar_E_2 = VectorElement("DGT", mesh.ufl_cell(), kbar) Wbar_E_2_H12 = VectorElement("CG", mesh.ufl_cell(), kbar)["facet"] Q_E = FiniteElement("DG", mesh.ufl_cell(), k - 1) Qbar_E = FiniteElement("DGT", mesh.ufl_cell(), k) # Function spaces for projection W_2 = FunctionSpace(mesh, W_E_2) T_2 = FunctionSpace(mesh, T_E_2)
R_path = 'Results' # Path for data storage Data_postprocessing = True # Data storage for later visualization & FEniCS computations. PBR_L = 3.0 # Reactor length, m PBR_R = 0.0127 # Reactor radius, m meszf = 0.001 # mesh element size factor # Mesh generation and formats conversion Wallboundary_id = 12 Inletboundary_id = 13 Boundary_ids = Wallboundary_id, Inletboundary_id pygmsh_mesh, pygmsh_facets = Generate_PBRpygmsh((0., PBR_L), (0., PBR_R), Boundary_ids, meszf) # Reading mesh data stored in .xdmf files. mesh = Mesh() with XDMFFile(pygmsh_mesh) as infile: infile.read(mesh) mvc = MeshValueCollection("size_t", mesh, 1) with XDMFFile(pygmsh_facets) as infile: infile.read(mvc, "name_to_read") mf = cpp.mesh.MeshFunctionSizet(mesh, mvc) # Define function spaces for PDEs variational formulation. P1 = FiniteElement('P', mesh.ufl_cell(), 1) # Lagrange 1-order polynomials family element = MixedElement([P1, P1, P1, P1]) V = FunctionSpace(mesh, element) # Splitting test and trial functions v_A, v_B, v_C, v_T = TestFunctions(V) # Test functions u = Function(V)
def run_simulation( filepath, topology_info: int = None, top_bc: int = None, bot_bc: int = None, left_bc: int = None, right_bc: int = None, geometry: dict = None, kappa=3, #only if geometry is None show=True, save_solution=False): from dolfin import (Mesh, XDMFFile, MeshValueCollection, cpp, FunctionSpace, TrialFunction, TestFunction, DirichletBC, Constant, Measure, inner, nabla_grad, Function, solve, plot, File) mesh = Mesh() with XDMFFile("%s_triangle.xdmf" % filepath.split('.')[0]) as infile: infile.read(mesh) # read the complete mesh mvc_subdo = MeshValueCollection("size_t", mesh, mesh.geometric_dimension() - 1) with XDMFFile("%s_triangle.xdmf" % filepath.split('.')[0]) as infile: infile.read(mvc_subdo, "subdomains") # read the diferent subdomians subdomains = cpp.mesh.MeshFunctionSizet(mesh, mvc_subdo) mvc = MeshValueCollection("size_t", mesh, mesh.geometric_dimension() - 2) with XDMFFile("%s_line.xdmf" % filepath.split('.')[0]) as infile: infile.read(mvc, "boundary_conditions") #read the boundary conditions boundary = cpp.mesh.MeshFunctionSizet(mesh, mvc) # Define function space and basis functions V = FunctionSpace(mesh, "CG", 1) u = TrialFunction(V) v = TestFunction(V) # Boundary conditions bcs = [] for bc_id in topology_info.keys(): if bc_id[-2:] == "bc": if bot_bc is not None and bc_id[:3] == "bot": bcs.append( DirichletBC(V, Constant(bot_bc), boundary, topology_info[bc_id])) elif left_bc is not None and bc_id[:4] == "left": bcs.append( DirichletBC(V, Constant(left_bc), boundary, topology_info[bc_id])) elif top_bc is not None and bc_id[:3] == "top": bcs.append( DirichletBC(V, Constant(top_bc), boundary, topology_info[bc_id])) elif right_bc is not None and bc_id[:5] == "right": bcs.append( DirichletBC(V, Constant(right_bc), boundary, topology_info[bc_id])) else: print(bc_id + " Not assigned as boundary condition ") # raise NotImplementedError # Define new measures associated with the interior domains and # exterior boundaries dx = Measure("dx", subdomain_data=subdomains) ds = Measure("ds", subdomain_data=boundary) f = Constant(0) g = Constant(0) if geometry is not None: # run multipatch implementation (Multiple domains) a = [] L = [] for patch_id in geometry.keys(): kappa = geometry[patch_id].get("kappa") a.append( inner(Constant(kappa) * nabla_grad(u), nabla_grad(v)) * dx(topology_info[patch_id])) L.append(f * v * dx(topology_info[patch_id])) a = sum(a) L = sum(L) else: a = inner(Constant(kappa) * nabla_grad(u), nabla_grad(v)) * dx L = f * v * dx ## Redefine u as a function in function space V for the solution u = Function(V) # Solve solve(a == L, u, bcs) u.rename('u', 'Temperature') # Save solution to file in VTK format print(' [+] Output to %s_solution.pvd' % filepath.split('.')[0]) vtkfile = File('%s_solution.pvd' % filepath.split('.')[0]) vtkfile << u if show: import matplotlib matplotlib.use("Qt5Agg") # Plot solution and gradient plot(u, title="Temperature") plt.gca().view_init(azim=-90, elev=90) plt.show() dofs = V.tabulate_dof_coordinates().reshape( V.dim(), mesh.geometry().dim()) #coordinates of nodes vals = u.vector().get_local() #temperature at nodes if save_solution: from dolfin import HDF5File, MPI output_file = HDF5File(MPI.comm_world, filepath.split('.')[0] + "_solution_field.h5", "w") output_file.write(u, "solution") output_file.close() u.set_allow_extrapolation(True) return dofs, vals, mesh, u
for (nx, dt, pres, store_step) in zip(nx_list, dt_list, pres_list, storestep_list): if comm.Get_rank() == 0: print("Starting computation with grid resolution " + str(nx)) # Compute num steps till completion num_steps = np.rint(Tend / float(dt)) # Generate mesh mesh = Mesh("./../../meshes/circle_0.xml") n = nx while n > 1: mesh = refine(mesh) n /= 2 output_field = XDMFFile(mesh.mpi_comm(), outdir + "psi_h_nx" + str(nx) + ".xdmf") # Velocity and initial condition V = VectorFunctionSpace(mesh, "DG", 3) uh = Function(V) uh.assign(Expression(("-Uh*x[1]", "Uh*x[0]"), Uh=Uh, degree=3)) psi0_expression = GaussianPulse( center=(xc, yc), sigma=float(sigma), U=[Uh, Uh], time=0.0, height=1.0, degree=3 ) # Generate particles x = RandomCircle(Point(x0, y0), r).generate([pres, pres]) s = np.zeros((len(x), 1), dtype=np.float_) # Initialize particles with position x and scalar property s at the mesh