def place_adjoint_source(self, dJ): dt = self.sim.fields.dt # the timestep size from sim.fields.dt of the forward sim self.sources = [] dJ = dJ.flatten() #TODO far_pts in 3d or cylindrical, perhaps py_v3_to_vec from simulation.py self.all_nearsrcdata = self.monitor.swigobj.near_sourcedata( mp.vec(self.far_pt.x, self.far_pt.y), dJ) for near_data in self.all_nearsrcdata: cur_comp = near_data.near_fd_comp amp_arr = np.array(near_data.amp_arr).reshape(-1, self.num_freq) scale = amp_arr * adj_src_scale(self, dt, include_resolution=False) if self.num_freq == 1: self.sources += [ mp.IndexedSource(self.time_src, near_data, scale[:, 0]) ] else: src = FilteredSource(self.time_src.frequency, self.frequencies, scale, dt) (num_basis, num_pts) = src.nodes.shape for basis_i in range(num_basis): self.sources += [ mp.IndexedSource(src.time_src_bf[basis_i], near_data, src.nodes[basis_i]) ] return self.sources
def place_adjoint_source(self, dJ): dt = self.sim.fields.dt # the timestep size from sim.fields.dt of the forward sim self.sources = [] if dJ.ndim == 4: dJ = np.sum(dJ, axis=0) dJ = dJ.flatten() farpt_list = np.array([list(pi) for pi in self.far_pts]).flatten() far_pt0 = self.far_pts[0] far_pt_vec = py_v3_to_vec(self.sim.dimensions, far_pt0, self.sim.is_cylindrical) self.all_nearsrcdata = self.monitor.swigobj.near_sourcedata( far_pt_vec, farpt_list, self.nfar_pts, dJ) for near_data in self.all_nearsrcdata: cur_comp = near_data.near_fd_comp amp_arr = np.array(near_data.amp_arr).reshape(-1, self.num_freq) scale = amp_arr * adj_src_scale(self, dt, include_resolution=False) if self.num_freq == 1: self.sources += [ mp.IndexedSource(self.time_src, near_data, scale[:, 0]) ] else: src = FilteredSource(self.time_src.frequency, self.frequencies, scale, dt) (num_basis, num_pts) = src.nodes.shape for basis_i in range(num_basis): self.sources += [ mp.IndexedSource(src.time_src_bf[basis_i], near_data, src.nodes[basis_i]) ] return self.sources
def place_adjoint_source(self, dJ): time_src = self._create_time_profile() sources = [] mon_size = self.sim.fields.dft_monitor_size(self._monitor.swigobj, self.volume.swigobj, self.component) dJ = dJ.astype(np.complex128) if np.prod(mon_size) * self.num_freq != dJ.size and np.prod( mon_size) * self.num_freq**2 != dJ.size: raise ValueError('The format of J is incorrect!') # The objective function J is a vector. Each component corresponds to a frequency. if np.prod( mon_size) * self.num_freq**2 == dJ.size and self.num_freq > 1: dJ = np.sum(dJ, axis=1) '''The adjoint solver requires the objective function to be scalar valued with regard to objective arguments and position, but the function may be vector valued with regard to frequency. In this case, the Jacobian will be of the form [F,F,...] where F is the number of frequencies. Because of linearity, we can sum across the second frequency dimension to calculate a frequency scale factor for each point (rather than a scale vector). ''' self.all_fouriersrcdata = self._monitor.swigobj.fourier_sourcedata( self.volume.swigobj, self.component, self.sim.fields, dJ) for fourier_data in self.all_fouriersrcdata: amp_arr = np.array(fourier_data.amp_arr).reshape(-1, self.num_freq) scale = amp_arr * self._adj_src_scale(include_resolution=False) if self.num_freq == 1: sources += [ mp.IndexedSource(time_src, fourier_data, scale[:, 0], not self.yee_grid) ] else: src = FilteredSource(time_src.frequency, self._frequencies, scale, self.sim.fields.dt) (num_basis, num_pts) = src.nodes.shape for basis_i in range(num_basis): sources += [ mp.IndexedSource(src.time_src_bf[basis_i], fourier_data, src.nodes[basis_i], not self.yee_grid) ] return sources