def add_laser(self, laser, injection_method): # Call method of parent class PICMI_Simulation.add_laser(self, laser, injection_method) # Handle injection method assert type(injection_method) == PICMI_LaserAntenna # Handle laser profile method if type(laser) == PICMI_GaussianLaser: assert laser.propagation_direction[0] == 0. assert laser.propagation_direction[1] == 0. assert (laser.zeta is None) or (laser.zeta == 0) assert (laser.beta is None) or (laser.beta == 0) phi2_chirp = laser.phi2 if phi2_chirp is None: phi2_chirp = 0 polarization_angle = np.arctan2(laser.polarization_direction[1], laser.polarization_direction[0]) laser_profile = GaussianLaser(a0=laser.a0, waist=laser.waist, z0=laser.centroid_position[-1], zf=laser.focal_position[-1], tau=laser.duration, theta_pol=polarization_angle, phi2_chirp=phi2_chirp) else: raise ValueError('Unknown laser profile: %s' % type(injection_method)) # Inject the laser add_laser_pulse(self.fbpic_sim, laser_profile, method='antenna', z0_antenna=injection_method.position[-1], gamma_boost=self.gamma_boost)
def add_species(self, species, layout, initialize_self_field=False): # Call method of parent class PICMI_Simulation.add_species(self, species, layout, initialize_self_field) # Call generic method internally self._add_species_generic(species, layout, injection_plane_position=None, injection_plane_normal_vector=None, initialize_self_field=initialize_self_field)
def add_species(self, species, layout, initialize_self_field=False): # Call method of parent class PICMI_Simulation.add_species(self, species, layout, initialize_self_field) # Extract list of species if type(species) == PICMI_Species: species_instances_list = [species] elif type(species) == PICMI_MultiSpecies: species_instances_list = species.species_instances_list else: raise ValueError('Unknown type: %s' % type(species)) # Loop over species and create FBPIC species for s in species_instances_list: # Get their charge and mass if s.particle_type is not None: s.charge = particle_charge[s.particle_type] s.mass = particle_mass[s.particle_type] # If `charge_state` is set, redefine the charge and mass if s.charge_state is not None: s.charge = s.charge_state * e s.mass -= s.charge_state * m_e # Add the species to the FBPIC simulation fbpic_species = self._create_new_fbpic_species( s, layout, initialize_self_field) # Register a pointer to the FBPIC species in the PICMI species itself # (Useful for particle diagnostics later on) s.fbpic_species = fbpic_species # Loop over species and handle ionization for s in species_instances_list: for interaction in s.interactions: assert interaction[0] == 'ionization' assert interaction[1] == 'ADK' picmi_target = interaction[2] if not hasattr(picmi_target, 'fbpic_species'): raise RuntimeError( 'For ionization with PICMI+FBPIC:\n' 'You need to add the target species to the simulation,' ' before the other species.') fbpic_target = picmi_target.fbpic_species fbpic_source = s.fbpic_species fbpic_source.make_ionizable(element=s.particle_type, level_start=s.charge_state, target_species=fbpic_target)
def add_diagnostic(self, diagnostic): # Call method of parent class PICMI_Simulation.add_diagnostic(self, diagnostic) # Handle diagnostic if diagnostic.step_min is None: iteration_min = 0 else: iteration_min = diagnostic.step_min if diagnostic.step_max is None: iteration_max = np.inf else: iteration_max = diagnostic.step_max # Register field diagnostic if type(diagnostic) == PICMI_FieldDiagnostic: if diagnostic.data_list is None: data_list = ['rho', 'E', 'B', 'J'] else: data_list = diagnostic.data_list diag = FieldDiagnostic(period=diagnostic.period, fldobject=self.fbpic_sim.fld, comm=self.fbpic_sim.comm, fieldtypes=data_list, write_dir=diagnostic.write_dir, iteration_min=iteration_min, iteration_max=iteration_max) # Register particle diagnostic elif type(diagnostic) == PICMI_ParticleDiagnostic: species_dict = {} for s in diagnostic.species: if s.name is None: raise ValueError('When using a species in a diagnostic, ' 'its name must be set.') species_dict[s.name] = s.fbpic_species if diagnostic.data_list is None: data_list = ['position', 'momentum', 'weighting'] else: data_list = diagnostic.data_list diag = ParticleDiagnostic(period=diagnostic.period, species=species_dict, comm=self.fbpic_sim.comm, particle_data=data_list, write_dir=diagnostic.write_dir, iteration_min=iteration_min, iteration_max=iteration_max) # Add it to the FBPIC simulation self.fbpic_sim.diags.append(diag)
def add_applied_field(self, applied_field): # Call method of parent class PICMI_Simulation.add_applied_field(self, applied_field) if type(applied_field) == PICMI_Mirror: assert applied_field.z_front_location is not None mirror = Mirror(z_lab=applied_field.z_front_location, n_cells=applied_field.number_of_cells, gamma_boost=self.fbpic_sim.boost.gamma0) self.fbpic_sim.mirrors.append(mirror) elif type(applied_field) == PICMI_ConstantAppliedField: # TODO: Handle bounds for field_name in ['Ex', 'Ey', 'Ez', 'Bx', 'By', 'Bz']: field_value = getattr(applied_field, field_name) if field_value is None: continue def field_func(F, x, y, z, t, amplitude, length_scale): return (F + amplitude * field_value) # Pass it to FBPIC self.fbpic_sim.external_fields.append( ExternalField(field_func, field_name, 1., 0.)) elif type(applied_field) == PICMI_AnalyticAppliedField: # TODO: Handle bounds for field_name in ['Ex', 'Ey', 'Ez', 'Bx', 'By', 'Bz']: # Extract expression and execute it inside a function definition expression = getattr(applied_field, field_name + '_expression') if expression is None: continue fieldfunc = None define_function_code = \ """def fieldfunc( F, x, y, z, t, amplitude, length_scale ):\n return( F + amplitude * %s )""" %expression # Take into account user-defined variables for k in applied_field.user_defined_kw: define_function_code = \ "%s = %s\n" %(k,applied_field.user_defined_kw[k]) \ + define_function_code exec(define_function_code, globals()) # Pass it to FBPIC self.fbpic_sim.external_fields.append( ExternalField(fieldfunc, field_name, 1., 0.)) else: raise ValueError("Unrecognized `applied_field` type.")
def add_diagnostic(self, diagnostic): # Call method of parent class PICMI_Simulation.add_diagnostic(self, diagnostic) # Handle iteration_min/max in regular diagnostic if type(diagnostic) in [ PICMI_FieldDiagnostic, PICMI_ParticleDiagnostic ]: if diagnostic.step_min is None: iteration_min = 0 else: iteration_min = diagnostic.step_min if diagnostic.step_max is None: iteration_max = np.inf else: iteration_max = diagnostic.step_max # Register field diagnostic if type(diagnostic) in [ PICMI_FieldDiagnostic, PICMI_LabFrameFieldDiagnostic ]: if diagnostic.data_list is None: data_list = ['rho', 'E', 'B', 'J'] else: data_list = set() # Use set to avoid redundancy for data in diagnostic.data_list: if data in ['Ex', 'Ey', 'Ez', 'E']: data_list.add('E') elif data in ['Bx', 'By', 'Bz', 'B']: data_list.add('B') elif data in ['Jx', 'Jy', 'Jz', 'J']: data_list.add('J') elif data == 'rho': data_list.add('rho') data_list = list(data_list) if type(diagnostic) == PICMI_FieldDiagnostic: diag = FieldDiagnostic(period=diagnostic.period, fldobject=self.fbpic_sim.fld, comm=self.fbpic_sim.comm, fieldtypes=data_list, write_dir=diagnostic.write_dir, iteration_min=iteration_min, iteration_max=iteration_max) # Register particle density diagnostic rho_density_list = [] if diagnostic.data_list is not None: for data in diagnostic.data_list: if data.startswith('rho_'): # particle density diagnostics, rho_speciesname rho_density_list.append(data) if rho_density_list: species_dict = {} for data in rho_density_list: sname = data[4:] for s in self.species: if s.name == sname: species_dict[s.name] = s.fbpic_species pdd_diag = ParticleChargeDensityDiagnostic( period=diagnostic.period, sim=self.fbpic_sim, species=species_dict, write_dir=diagnostic.write_dir, iteration_min=iteration_min, iteration_max=iteration_max) self.fbpic_sim.diags.append(pdd_diag) elif type(diagnostic) == PICMI_LabFrameFieldDiagnostic: diag = BackTransformedFieldDiagnostic( zmin_lab=diagnostic.grid.lower_bound[1], zmax_lab=diagnostic.grid.upper_bound[1], v_lab=c, dt_snapshots_lab=diagnostic.dt_snapshots, Ntot_snapshots_lab=diagnostic.num_snapshots, gamma_boost=self.gamma_boost, period=100, fldobject=self.fbpic_sim.fld, comm=self.fbpic_sim.comm, fieldtypes=diagnostic.data_list, write_dir=diagnostic.write_dir) # Register particle diagnostic elif type(diagnostic) in [ PICMI_ParticleDiagnostic, PICMI_LabFrameParticleDiagnostic ]: species_dict = {} for s in diagnostic.species: if s.name is None: raise ValueError('When using a species in a diagnostic, ' 'its name must be set.') species_dict[s.name] = s.fbpic_species if diagnostic.data_list is None: data_list = ['position', 'momentum', 'weighting'] else: data_list = diagnostic.data_list if type(diagnostic) == PICMI_ParticleDiagnostic: diag = ParticleDiagnostic(period=diagnostic.period, species=species_dict, comm=self.fbpic_sim.comm, particle_data=data_list, write_dir=diagnostic.write_dir, iteration_min=iteration_min, iteration_max=iteration_max) else: diag = BackTransformedParticleDiagnostic( zmin_lab=diagnostic.grid.lower_bound[1], zmax_lab=diagnostic.grid.upper_bound[1], v_lab=c, dt_snapshots_lab=diagnostic.dt_snapshots, Ntot_snapshots_lab=diagnostic.num_snapshots, gamma_boost=self.gamma_boost, period=100, fldobject=self.fbpic_sim.fld, species=species_dict, comm=self.fbpic_sim.comm, particle_data=data_list, write_dir=diagnostic.write_dir) # Add it to the FBPIC simulation self.fbpic_sim.diags.append(diag)