def __init__(self, mesh, Vh_STATE, x0): """ Constructor. INPUTS: - mesh: the mesh - Vh_STATE: the finite element space for the state variable - x0: location at which we want to compute the jet-thickness """ Vh_help = dl.FunctionSpace(mesh, "CG", 1) xfun = dl.interpolate(dl.Expression("x[0]", degree=1), Vh_help) x_coord = xfun.vector().gather_on_zero() mpi_comm = mesh.mpi_comm() rank = dl.MPI.rank(mpi_comm) nproc = dl.MPI.size(mpi_comm) # round x0 so that it is aligned with the mesh if nproc > 1: from mpi4py import MPI comm = MPI.COMM_WORLD if rank == 0: idx = (np.abs(x_coord - x0)).argmin() self.x0 = x_coord[idx] else: self.x0 = None self.x0 = comm.bcast(self.x0, root=0) else: idx = (np.abs(x_coord - x0)).argmin() self.x0 = x_coord[idx] line_segment = dl.AutoSubDomain(lambda x: dl.near(x[0], self.x0)) markers_f = dl.FacetFunction("size_t", mesh) markers_f.set_all(0) line_segment.mark(markers_f, 1) dS = dl.dS[markers_f] x_test = dl.TestFunctions(Vh_STATE) u_test = x_test[0] e1 = dl.Constant(("1.", "0.")) self.int_u = dl.assemble(dl.avg(dl.dot(u_test, e1)) * dS(1)) #self.u_cl = dl.assemble( dl.dot(u_test,e1)*dP(1) ) self.u_cl = dl.Function(Vh_STATE).vector() ps = dl.PointSource(Vh_STATE.sub(0).sub(0), dl.Point(self.x0, 0.), 1.) ps.apply(self.u_cl) scaling = self.u_cl.sum() if np.abs(scaling - 1.) > 1e-6: print scaling raise ValueError() self.state = dl.Function(Vh_STATE).vector() self.help = dl.Function(Vh_STATE).vector()
def fem_pts(conductivity, pos_list, save_dest, ele_list=None, sel_idx=None): NPYSave = False HDF5Save = False if save_dest.find('.h5') > -1: HDF5Save = True dump_file = d.HDF5File(d.mpi_comm_world(), save_dest, 'w') elif save_dest.find('.npy') > -1: if not ele_list: print('Expecting ele_list argument') else: NPYSave = True else: print('Only .h5 (entire mesh space), .npy (known ele_pos) supported') print('Will not save anything this time') if not sel_idx: sel_idx = range(len(pos_list)) print('On this process no. pt. srcs = ', len(sel_idx)) mesh, subdomain, boundaries = meshes.load_meshes() sigma = sigma_tensor(mesh, conductivity=conductivity) print('Done loading meshes and conductivity') V = d.FunctionSpace(mesh, "CG", 2) v = d.TestFunction(V) u = d.TrialFunction(V) dx = d.Measure("dx")(subdomain_data=subdomain) # ds = d.Measure("ds")(subdomain_data=boundaries) a = d.inner(sigma * d.grad(u), d.grad(v)) * dx L = d.Constant(0) * v * dx() A = d.assemble(a) # Surface of the grnd ele = 1030 bc = d.DirichletBC(V, d.Constant(0), boundaries, 1030) for curr_idx in sel_idx: solver = set_solver() phi = d.Function(V) x = phi.vector() print('Started computing for,at: ', curr_idx, pos_list[curr_idx]) b = d.assemble(L) bc.apply(A, b) xx, yy, zz = pos_list[curr_idx] point = d.Point(xx, yy, zz) delta = d.PointSource(V, point, 1.) delta.apply(b) solver.solve(A, x, b) # file = d.File("pots_anis.pvd") # file << phi if HDF5Save: dump_file.write(x.array(), str(curr_idx)) dump_file.flush() if NPYSave: vals = extract_pots(phi, np.array(ele_list)) np.save(save_dest, vals) print('Finished computing for :', curr_idx) return
def onclick(event): if print_point: print('(', event.xdata, ',', event.ydata, ')') delta_p = dl.PointSource(function_space_V, dl.Point(event.xdata, event.ydata), 1.0) if event.button == 3: point_source_dual_vector[:] = 0. delta_p.apply(point_source_dual_vector) Adelta.vector()[:] = apply_A(point_source_dual_vector) plt.clf() c = dl.plot(Adelta) plt.colorbar(c) plt.title('left click adds points, right click resets') plt.draw()
def ptsrc(self,u,ord=1): """ Point source of (ord) order derivative of data-misfit function wrt. the solution u. """ assert ord in [1,2], 'Wrong order!' u_vec = self._extr_soloc(u) # define PointSource similar to boundary function, but PointSource is applied to (rhs) vector and is limited to scalar FunctionSpace dfun_vec = u_vec if ord==1: dfun_vec -= self.obs dfun_vec *= self.prec dirac = [df.PointSource(self.pde.W.sub(0),df.Point(p),f) for (p,f) in zip(self.loc,dfun_vec)] # fails in 1.6.0 (mac app) possibly due to swig bug in numpy.i (already fixed in numpy 1.10.2) of the system numpy 1.8.0rc1 return dirac
def accountPointSource(self): #----------------------------------------------------------------------------------- componentIndex = {'real': 0, 'imag': 1} for sourceComponent in ('real', 'imag'): if self.sourceOpt[sourceComponent]['choice'] == 'pointSource': pointSourceMag = self.sourceOpt[sourceComponent][ 'pointSourceMag'] pointSourceLoc = self.sourceOpt[sourceComponent][ 'pointSourceLoc'] for funSpaceComponent in ('real', 'imag'): if sourceComponent == 'imag' and funSpaceComponent == 'imag': pointSourceMag = -pointSourceMag PS = df.PointSource(self.V.sub(componentIndex[funSpaceComponent]),\ df.Point(pointSourceLoc),pointSourceMag) PS.apply(self.rhsVec) return
# Define function space and basis functions # This corresponds to Neumann boundary conditions zero, i.e. all outer boundaries are insulating. L = df.Constant(0) * v * dx # Define Dirichlet boundary conditions at left and right boundaries bcs = [df.DirichletBC(V, 0.0, boundaries, 1)] for t_idx in range(num_tsteps): print("Time step {} of {}".format(t_idx, num_tsteps)) phi = df.Function(V) A = df.assemble(a) b = df.assemble(L) [bc.apply(A, b) for bc in bcs] # Adding point sources from neural simulation for s_idx, s_pos in enumerate(source_pos): point = df.Point(s_pos[0], s_pos[1], s_pos[2]) delta = df.PointSource(V, point, imem[s_idx, t_idx]) delta.apply(b) df.solve(A, phi.vector(), b, 'cg', "ilu") # df.File(join(out_folder, "phi_t_vec_{}.xml".format(t_idx))) << phi np.save(join(out_folder, "phi_t_vec_{}.npy".format(t_idx)), phi.vector()) plot_FEM_results(phi, t_idx)
def run_model(function_space, kappa, forcing, init_condition, dt, final_time, boundary_conditions=None, second_order_timestepping=False, exact_sol=None, velocity=None, point_sources=None, intermediate_times=None): """ Use implicit euler to solve transient advection diffusion equation du/dt = grad (k* grad u) - vel*grad u + f WARNINGarningW: when point sources solution changes significantly when mesh is varied """ mesh = function_space.mesh() time_independent_boundaries = False if boundary_conditions == None: bndry_obj = dl.CompiledSubDomain("on_boundary") boundary_conditions = [['dirichlet', bndry_obj, dl.Constant(0)]] time_independent_boundaries = True num_bndrys = len(boundary_conditions) boundaries = mark_boundaries(mesh, boundary_conditions) dirichlet_bcs = collect_dirichlet_boundaries(function_space, boundary_conditions, boundaries) # To express integrals over the boundary parts using ds(i), we must first # redefine the measure ds in terms of our boundary markers: ds = dl.Measure('ds', domain=mesh, subdomain_data=boundaries) dx = dl.Measure('dx', domain=mesh) # Variational problem at each time u = dl.TrialFunction(function_space) v = dl.TestFunction(function_space) # Previous solution if hasattr(init_condition, 't'): assert init_condition.t == 0 u_1 = dl.interpolate(init_condition, function_space) if not second_order_timestepping: theta = 1 else: theta = 0.5 if hasattr(forcing, 't'): forcing_1 = copy_expression(forcing) else: forcing_1 = forcing def steady_state_form(u, v, f): F = kappa * dl.inner(dl.grad(u), dl.grad(v)) * dx F -= f * v * dx if velocity is not None: F += dl.dot(velocity, dl.grad(u)) * v * dx return F F = u*v*dx-u_1*v*dx + dt*theta*steady_state_form(u,v,forcing) + \ dt*(1.-theta)*steady_state_form(u_1,v,forcing_1) a, L = dl.lhs(F), dl.rhs(F) # a = u*v*dx + theta*dt*kappa*dl.inner(dl.grad(u), dl.grad(v))*dx # L = (u_1 + dt*theta*forcing)*v*dx # if velocity is not None: # a += theta*dt*v*dl.dot(velocity,dl.grad(u))*dx # if second_order_timestepping: # L -= (1-theta)*dt*dl.inner(kappa*dl.grad(u_1), dl.grad(v))*dx # L += (1-theta)*dt*forcing_1*v*dx # if velocity is not None: # L -= (1-theta)*dt*(v*dl.dot(velocity,dl.grad(u_1)))*dx beta_1_list = [] alpha_1_list = [] for ii in range(num_bndrys): if (boundary_conditions[ii][0] == 'robin'): alpha = boundary_conditions[ii][3] a += theta * dt * alpha * u * v * ds(ii) if second_order_timestepping: if hasattr(alpha, 't'): alpha_1 = copy_expression(alpha) alpha_1_list.append(alpha_1) else: alpha_1 = alpha L -= (1 - theta) * dt * alpha_1 * u_1 * v * ds(ii) if ((boundary_conditions[ii][0] == 'robin') or (boundary_conditions[ii][0] == 'neumann')): beta = boundary_conditions[ii][2] L -= theta * dt * beta * v * ds(ii) if second_order_timestepping: if hasattr(beta, 't'): beta_1 = copy_expression(beta) beta_1_list.append(beta_1) else: # boundary condition is constant in time beta_1 = beta L -= (1 - theta) * dt * beta_1 * v * ds(ii) if time_independent_boundaries: # TODO this can be used if dirichlet and robin conditions are not # time dependent. A = dl.assemble(a) for bc in dirichlet_bcs: bc.apply(A) solver = dl.LUSolver(A) #solver.parameters["reuse_factorization"] = True else: solver = None u_2 = dl.Function(function_space) u_2.assign(u_1) t = 0.0 dt_tol = 1e-12 n_time_steps = 0 if intermediate_times is not None: intermediate_u = [] intermediate_cnt = 0 # assert in chronological order assert np.allclose(intermediate_times, np.array(intermediate_times)) assert np.all(intermediate_times < final_time) while t < final_time - dt_tol: # Update current time t += dt forcing.t = t forcing_1.t = t - dt # set current time for time varying boundary conditions for ii in range(num_bndrys): if hasattr(boundary_conditions[ii][2], 't'): boundary_conditions[ii][2].t = t # set previous time for time varying boundary conditions when # using second order timestepping. lists will be empty if using # first order timestepping for jj in range(len(beta_1_list)): beta_1_list[jj].t = t - dt for jj in range(len(alpha_1_list)): alpha_1_list[jj].t = t - dt #A, b = dl.assemble_system(a, L, dirichlet_bcs) #for bc in dirichlet_bcs: # bc.apply(A,b) if boundary_conditions is not None: A = dl.assemble(a) for bc in dirichlet_bcs: bc.apply(A) b = dl.assemble(L) for bc in dirichlet_bcs: bc.apply(b) if point_sources is not None: ps_list = [] for ii in range(len(point_sources)): point, expr = point_sources[ii] ps_list.append((dl.Point(point[0], point[1]), expr(t))) ps = dl.PointSource(function_space, ps_list) ps.apply(b) if solver is None: dl.solve(A, u_2.vector(), b) else: solver.solve(u_2.vector(), b) #print ("t =", t, "end t=", final_time) # Update previous solution u_1.assign(u_2) # import matplotlib.pyplot as plt # plt.subplot(131) # pp=dl.plot(u_1) # plt.subplot(132) # dl.plot(forcing,mesh=mesh) # plt.subplot(133) # dl.plot(forcing_1,mesh=mesh) # plt.colorbar(pp) # plt.show() # compute error if exact_sol is not None: exact_sol.t = t error = dl.errornorm(exact_sol, u_2) print('t = %.2f: error = %.3g' % (t, error)) #dl.plot(exact_sol,mesh=mesh) #plt.show() t = min(t, final_time) if (intermediate_times is not None and intermediate_cnt < intermediate_times.shape[0] and t >= intermediate_times[intermediate_cnt]): #save solution closest to intermediate time u_t = dl.Function(function_space) u_t.assign(u_2) intermediate_u.append(u_t) intermediate_cnt += 1 n_time_steps += 1 #print ("t =", t, "end t=", final_time,"# time steps", n_time_steps) if intermediate_times is None: return u_2 else: return intermediate_u + [u_2]
def simulate_FEM(): import dolfin as df df.parameters['allow_extrapolation'] = False # Define mesh mesh = df.Mesh(join(mesh_folder, "{}.xml".format(mesh_name))) subdomains = df.MeshFunction("size_t", mesh, join(mesh_folder, "{}_physical_region.xml".format(mesh_name))) boundaries = df.MeshFunction("size_t", mesh, join(mesh_folder, "{}_facet_region.xml".format(mesh_name))) print("Number of cells in mesh: ", mesh.num_cells()) np.save(join(out_folder, "mesh_coordinates.npy"), mesh.coordinates()) sigma_vec = df.Constant(sigma) V = df.FunctionSpace(mesh, "CG", 2) v = df.TestFunction(V) u = df.TrialFunction(V) ds = df.Measure("ds", domain=mesh, subdomain_data=boundaries) dx = df.Measure("dx", domain=mesh, subdomain_data=subdomains) a = df.inner(sigma_vec * df.grad(u), df.grad(v)) * dx(1) # This corresponds to Neumann boundary conditions zero, i.e. # all outer boundaries are insulating. L = df.Constant(0) * v * dx # Define Dirichlet boundary conditions outer cylinder boundaries (ground) bcs = [df.DirichletBC(V, 0.0, boundaries, 1)] for t_idx in range(num_tsteps): f_name = join(out_folder, "phi_xz_t_vec_{}.npy".format(t_idx)) # if os.path.isfile(f_name): # print("skipping ", f_name) # continue print("Time step {} of {}".format(t_idx, num_tsteps)) phi = df.Function(V) A = df.assemble(a) b = df.assemble(L) [bc.apply(A, b) for bc in bcs] # Adding point sources from neural simulation for s_idx, s_pos in enumerate(source_pos): point = df.Point(s_pos[0], s_pos[1], s_pos[2]) delta = df.PointSource(V, point, imem[s_idx, t_idx]) delta.apply(b) df.solve(A, phi.vector(), b, 'cg', "ilu") # df.File(join(out_folder, "phi_t_vec_{}.xml".format(t_idx))) << phi # np.save(join(out_folder, "phi_t_vec_{}.npy".format(t_idx)), phi.vector()) plot_and_save_simulation_results(phi, t_idx)
def run(self, species="Oxygen", increment=0): # Specify the test/trial function space df.set_log_active(False) V = df.FunctionSpace(self.mesh, "Lagrange", 1) # Specify the boundary conditions, Dirichlet on all domain faces def u0_boundary(x, on_boundary): return on_boundary # Define the problem u = df.TrialFunction(V) v = df.TestFunction(V) if species == "Oxygen": bc = df.DirichletBC(V, df.Constant(1), u0_boundary) f = df.Constant(0.0) a = self.Dc * df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx L = f * v * df.dx elif species == "Factor": bc = df.DirichletBC(V, df.Constant(0), u0_boundary) f = df.Constant(0) a = (self.decayRate * u * v + self.Dv * df.inner(df.nabla_grad(u), df.nabla_grad(v))) * df.dx L = f * v * df.dx # Assemble the system A, b = df.assemble_system(a, L, bc) if species == "Oxygen": # Add vessel source terms vesselSources = self.sources[1] for eachSource in vesselSources: location = [ point - self.spacing / 2.0 for point in eachSource[0] ] if self.extents[2] > 1: delta = df.PointSource( V, df.Point(location[0], location[1], location[2]), self.permeability * eachSource[1]) else: delta = df.PointSource(V, df.Point(location[0], location[1]), self.permeability * eachSource[1]) try: delta.apply(b) except: pass # Add cell sink terms cellSources = self.sources[0] for eachSource in cellSources: location = [ point - self.spacing / 2.0 for point in eachSource[0] ] if self.extents[2] > 1: delta = df.PointSource( V, df.Point(location[0], location[1], location[2]), -self.consumptionRate * eachSource[1]) else: delta = df.PointSource( V, df.Point(location[0], location[1]), -self.consumptionRate * eachSource[1]) try: delta.apply(b) except: pass elif species == "Factor": # Add cell source terms cellSources = self.sources[0] for eachSource in cellSources: location = [ point - self.spacing / 2.0 for point in eachSource[0] ] if self.extents[2] > 1: delta = df.PointSource( V, df.Point(location[0], location[1], location[2]), self.factorSensitvity * eachSource[1]) else: delta = df.PointSource( V, df.Point(location[0], location[1]), self.factorSensitvity * eachSource[1]) try: delta.apply(b) except: pass # Set up solution vector u = df.Function(V) U = u.vector() # Set up and run solver solver = df.KrylovSolver("cg", "ilu") solver.solve(A, U, b) self.result = [] for eachEntry in self.sources[0]: location = [point - self.spacing / 2.0 for point in eachEntry[0]] if self.extents[2] <= 1: location = location[:2] try: result = u(location) except: if species == "Oxygen": result = 1.0 else: result = 0.0 self.result.append(result) self.write_output(species, increment) return self.result
def solve_adjoint(evo, control, ps_magnitude, target_point, a, V, j): '''Calculates the solution to the adjoint problem. The solution to the adjoint equation is calculated using the explicitly given evolution (solution to the forward problem) and the control. For better understanding of the indeces see docs/indexing-diagram.txt. Parameters: OUTDATED V: dolfin.FunctionSpace The FEM space of the problem being solved. evo: ndarray The coefficients of the solution to the corresponding forward problem in the basis of the space V (see solve_forward). control: ndarray The laser power profile. beta_welding target_point: dolfin.Point threshold_temp penalty_term_combined Returns: evo_adj: ndarray The coefficients of the calculated adjoint solution in the basis of the space V. ''' # initialize state functions theta_km1 = dolfin.Function(V) # stands for theta[k-1] theta_k = dolfin.Function(V) # stands for theta[k] theta_kp1 = dolfin.Function(V) # stands for theta[k+1] # initialize adjoint state functions p_km1 = dolfin.Function(V) # stands for p[k-1] p_k = dolfin.Function(V) # stands for p[k] # FEM equation setup p = dolfin.TrialFunction(V) # stands for unknown p[k-1] v = dolfin.TestFunction(V) Nt = len(control) evo_adj = np.zeros((Nt+1, len(V.dofmap().dofs()))) # preparing for the first iteration theta_k.vector().set_local(evo[Nt]) # solve backward, i.e. p_k -> p = p_km1, k = Nt, Nt-1, Nt-2, ..., 1 for k in range(Nt, 0, -1): theta_km1.vector().set_local(evo[k-1]) F = a(theta_km1, theta_k, p, control[k-1])\ + j(k-1, theta_km1, theta_k) if k < Nt: F += a(theta_k, theta_kp1, p_k, control[k])\ + j(k, theta_k, theta_kp1) dF = dolfin.derivative(F, theta_k, v) # sometimes rhs(dF) is void which leads to a ValueError try: A, b = dolfin.assemble_system(dolfin.lhs(dF), dolfin.rhs(dF)) except ValueError: A, b = dolfin.assemble_system(dolfin.lhs(dF), Constant(0)*v*dx) # apply welding penalty as a point source point_source = dolfin.PointSource(V, target_point, ps_magnitude[k-1]) point_source.apply(b) dolfin.solve(A, p_km1.vector(), b) evo_adj[k-1] = p_km1.vector().get_local() # preparing for the next iteration p_k.assign(p_km1) theta_kp1.assign(theta_k) theta_k.assign(theta_km1) return evo_adj