def get_gradient_fields(self, monitor_name): '''Extracts the fields in the optimizable region. These fields are needed to create the gradient fields''' return ls.get_fields(self.fdtd, monitor_name, get_eps=True, get_D=True, nointerpolation=True)
def get_fom(self, simulation): fields = [ ls.get_fields(simulation.fdtd, monitor_name) for monitor_name in self.monitor_names ] if self.normalize_to_source_power: source_power = np.zeros(np.shape(fields[0].wl)) for i, wl in enumerate(fields[0].wl): source_power[i] = ls.get_source_power(simulation.fdtd, wl=wl) self.source_power = source_power self.fields = fields pointfields = [ field.getfield(field.x[0], field.y[0], field.z[0], self.wavelengths[0]) for field in fields ] if self.weight_amplitudes is None: fom = sum([ sum(pointfield * np.conj(pointfield)) for pointfield in pointfields ]) else: sum_of_pointfields = sum([ pointfield * phase_factor for pointfield, phase_factor in zip( pointfields, self.weight_amplitudes) ]) fom = sum(sum_of_pointfields * np.conj(sum_of_pointfields)) if self.normalize_to_source_power: fom = fom / np.array(source_power) return fom
def run_forward_solves(self, params): """ Generates the new forward simulations, runs them and computes the figure of merit and forward fields. """ print('Running forward solves') self.make_forward_sim(params) iter = self.optimizer.iteration if self.store_all_simulations else 0 self.sim.run(name='forward', iter=iter) get_eps = True get_D = not self.use_deps nointerpolation = not self.geometry.use_interpolation() self.forward_fields = get_fields(self.sim.fdtd, monitor_name='opt_fields', field_result_name='forward_fields', get_eps=get_eps, get_D=get_D, get_H=False, nointerpolation=nointerpolation, unfold_symmetry=self.unfold_symmetry) fom = self.fom.get_fom(self.sim) if self.store_all_simulations: self.sim.remove_data_and_save( ) #< Remove the data from the file to save disk space. TODO: Make optional? self.fomHist.append(fom) print('FOM = {}'.format(fom)) return fom
def get_fom(self, simulation): ''' :param simulation: The simulation object of the base simulation :return: The figure of merit ''' field = ls.get_fields(simulation.fdtd, self.monitor_name) self.fields = field pointfield = field.getfield(field.x[0], field.y[0], field.z[0], self.wavelengths[0]) fom = sum(pointfield * np.conj(pointfield)) return fom
def run_forward_solves(self): """ Generates the new forward simulations, runs them and computes the figure of merit and forward fields. """ print('Running forward solves') self.make_forward_sim() self.sim.run(name='forward', iter=self.optimizer.iteration) self.forward_fields = get_fields(self.sim.fdtd, monitor_name='opt_fields', get_eps=True, get_D=True, get_H=True, nointerpolation=True) fom = self.fom.get_fom(self.sim) self.fomHist.append(fom) print('FOM = {}'.format(fom)) return fom
def run_adjoint_solves(self): """ Generates the adjoint simulations, runs them and extacts the adjoint fields. """ print('Running adjoint solves') self.make_forward_sim() self.sim.fdtd.selectpartial('source') self.sim.fdtd.delete() self.fom.add_adjoint_sources(self.sim) self.sim.run(name='adjoint', iter=self.optimizer.iteration) self.adjoint_fields = get_fields(self.sim.fdtd, monitor_name='opt_fields', get_eps=True, get_D=True, get_H=True, nointerpolation=True) self.adjoint_fields.scale(3, self.fom.get_adjoint_field_scaling(self.sim))
def process_forward_sim(self, iter): forward_name = 'forward_{}'.format(iter) self.sim.load(forward_name) Optimization.check_simulation_was_successful(self.sim) if self.fields_on_cad_only: get_fields_on_cad( self.sim.fdtd, monitor_name='opt_fields', field_result_name='forward_fields', get_eps=True, get_D=not self.use_deps, get_H=False, nointerpolation=not self.geometry.use_interpolation(), unfold_symmetry=self.unfold_symmetry) self.forward_fields_wl = get_lambda_from_cad( self.sim.fdtd, field_result_name='forward_fields') else: self.forward_fields = get_fields( self.sim.fdtd, monitor_name='opt_fields', field_result_name='forward_fields', get_eps=True, get_D=not self.use_deps, get_H=False, nointerpolation=not self.geometry.use_interpolation(), unfold_symmetry=self.unfold_symmetry) assert hasattr(self.forward_fields, 'E') self.forward_fields_wl = self.forward_fields.wl self.forward_fields_iter = int(iter) fom = self.fom.get_fom(self.sim) if self.store_all_simulations: self.sim.remove_data_and_save( ) # < Remove the data from the file to save disk space. TODO: Make optional? dist_to_target_fom = self.fom.target_fom - fom # < For plotting/logging we store the distance to a target self.full_fom_hist.append(dist_to_target_fom) if self.fom.target_fom == 0.0: print('FOM = {}'.format(fom)) else: print('FOM = {} ({} - {})'.format(dist_to_target_fom, self.fom.target_fom, fom)) return fom
def get_fom(self, simulation): fields = ls.get_fields(simulation.fdtd, self.monitor_name, get_H=True) source_power = np.zeros(np.shape(fields.wl)) for i, wl in enumerate(fields.wl): source_power[i] = ls.get_source_power(simulation.fdtd, wl=wl) self.fields = fields self.source_power = source_power fom_v_wavelength, phase_preactors = self.mode.calculate_overlap(fields) fom_v_wavelength = np.array(fom_v_wavelength) / np.array(source_power) self.phase_prefactors = np.array(phase_preactors) / np.array( source_power) # TODO This does not properly deal with multiple wavelengths right now return fom_v_wavelength[0]
def get_fom(self, simulation): '''Uploads the fields from a completed forward simulation, and performs the mode overlap integral on them''' fields = ls.get_fields(simulation.fdtd, self.monitor_name, get_H=True) source_power = np.zeros(np.shape(fields.wl)) for i, wl in enumerate(fields.wl): source_power[i] = ls.get_source_power(simulation.fdtd, wl=wl) self.fields = fields self.source_power = source_power fom_v_wavelength, phase_preactors = self.mode.calculate_overlap( fields, remove_H=True) fom_v_wavelength = np.array(fom_v_wavelength) / np.array(source_power) self.phase_prefactors = np.array(phase_preactors) / np.array( source_power) # TODO This does not properly deal with multiple wavelengths right now return fom_v_wavelength[0]
def process_adjoint_sim(self, iter): adjoint_name = 'adjoint_{}'.format(iter) self.sim.load(adjoint_name) if self.sim.fdtd.layoutmode(): self.sim.fdtd.run() Optimization.check_simulation_was_successful(self.sim) if self.fields_on_cad_only: get_fields_on_cad( self.sim.fdtd, monitor_name='opt_fields', field_result_name='adjoint_fields', get_eps=not self.use_deps, get_D=not self.use_deps, get_H=False, nointerpolation=not self.geometry.use_interpolation(), unfold_symmetry=self.unfold_symmetry) else: self.adjoint_fields = get_fields( self.sim.fdtd, monitor_name='opt_fields', field_result_name='adjoint_fields', get_eps=not self.use_deps, get_D=not self.use_deps, get_H=False, nointerpolation=not self.geometry.use_interpolation(), unfold_symmetry=self.unfold_symmetry) assert hasattr(self.adjoint_fields, 'E') self.adjoint_fields.iter = int(iter) self.scaling_factor = self.fom.get_adjoint_field_scaling(self.sim) if not self.fields_on_cad_only: self.adjoint_fields.scale(3, self.scaling_factor) if self.store_all_simulations: self.sim.remove_data_and_save( ) # < Remove the data from the file to save disk space. TODO: Make optional?
def run_adjoint_solves(self, params): """ Generates the adjoint simulations, runs them and extacts the adjoint fields. """ has_forward_fields = hasattr(self, 'forward_fields') and hasattr( self.forward_fields, 'E') params_changed = not np.allclose(params, self.geometry.get_current_params()) if not has_forward_fields or params_changed: fom = self.run_forward_solves(params) print('Running adjoint solves') self.make_adjoint_sim(params) iter = self.optimizer.iteration if self.store_all_simulations else 0 self.sim.run(name='adjoint', iter=iter) get_eps = not self.use_deps get_D = not self.use_deps nointerpolation = not self.geometry.use_interpolation() #< JN: Try on CAD self.adjoint_fields = get_fields(self.sim.fdtd, monitor_name='opt_fields', field_result_name='adjoint_fields', get_eps=get_eps, get_D=get_D, get_H=False, nointerpolation=nointerpolation, unfold_symmetry=self.unfold_symmetry) self.adjoint_fields.scaling_factor = self.fom.get_adjoint_field_scaling( self.sim) self.adjoint_fields.scale(3, self.adjoint_fields.scaling_factor) if self.store_all_simulations: self.sim.remove_data_and_save( ) #< Remove the data from the file to save disk space. TODO: Make optional?
def get_fom(self, simulation): fields = ls.get_fields(simulation.fdtd, self.monitor_name, get_H=True) self.fields = fields source_power = np.zeros(np.shape(fields.wl)) for i, wl in enumerate(fields.wl): source_power[i] = ls.get_source_power(simulation.fdtd, wl=wl) self.source_power = source_power pointfields = [ fields.getfield(pos[0], pos[1], pos[2], self.wavelength) for pos in self.positions ] sum_of_pointfields = sum([ pointfield * phase_factor for pointfield, phase_factor in zip( pointfields, self.phase_factors) ]) fom = sum(sum_of_pointfields * np.conj(sum_of_pointfields)) fom = fom / np.array(source_power) # TODO This does not properly deal with multiple wavelengths right now return fom