diff options
-rw-r--r-- | Examples/Tests/reduced_diags/PICMI_inputs_loadbalancecosts.py | 28 | ||||
-rw-r--r-- | Python/pywarpx/WarpX.py | 3 | ||||
-rw-r--r-- | Python/pywarpx/picmi.py | 130 |
3 files changed, 137 insertions, 24 deletions
diff --git a/Examples/Tests/reduced_diags/PICMI_inputs_loadbalancecosts.py b/Examples/Tests/reduced_diags/PICMI_inputs_loadbalancecosts.py index 569262b83..a8c74bf62 100644 --- a/Examples/Tests/reduced_diags/PICMI_inputs_loadbalancecosts.py +++ b/Examples/Tests/reduced_diags/PICMI_inputs_loadbalancecosts.py @@ -50,11 +50,32 @@ layout = picmi.GriddedLayout( ) # Reduced diagnostic -reduced_diag = picmi.ReducedDiagnostic( +reduced_diags = [] +reduced_diags.append(picmi.ReducedDiagnostic( diag_type='LoadBalanceCosts', period=1, name='LBC' -) +)) + +reduced_diags.append(picmi.ReducedDiagnostic( + diag_type='FieldReduction', + period=1, + name='FR', + reduction_type='Maximum', + reduced_function = 'Ez' +)) + +reduced_diags.append(picmi.ReducedDiagnostic( + diag_type='ParticleHistogram', + period=1, + name='PH', + species = electrons, + bin_number = 10, + bin_min=0., + bin_max = xmax, + normalization = 'unity_particle_weight', + histogram_function = 'x' +)) # Diagnostic diag = picmi.FieldDiagnostic( @@ -79,7 +100,8 @@ sim = picmi.Simulation( sim.add_species(electrons, layout=layout) # Add reduced diagnostics -sim.add_diagnostic(reduced_diag) +for reduced_diag in reduced_diags: + sim.add_diagnostic(reduced_diag) # Add diagnostics sim.add_diagnostic(diag) diff --git a/Python/pywarpx/WarpX.py b/Python/pywarpx/WarpX.py index 76f66c6d2..d03ddcef6 100644 --- a/Python/pywarpx/WarpX.py +++ b/Python/pywarpx/WarpX.py @@ -84,10 +84,7 @@ class WarpX(Bucket): reduced_diagnostics.reduced_diags_names = reduced_diagnostics._diagnostics_dict.keys() argv += reduced_diagnostics.attrlist() for diagnostic in reduced_diagnostics._diagnostics_dict.values(): - diagnostic.species = diagnostic._species_dict.keys() argv += diagnostic.attrlist() - for species_diagnostic in diagnostic._species_dict.values(): - argv += species_diagnostic.attrlist() return argv diff --git a/Python/pywarpx/picmi.py b/Python/pywarpx/picmi.py index 11f331e3c..2ebd161b7 100644 --- a/Python/pywarpx/picmi.py +++ b/Python/pywarpx/picmi.py @@ -1678,8 +1678,6 @@ class WarpXDiagnosticBase(object): ) bucket._diagnostics_dict[self.name] = self.diagnostic - - def set_write_dir(self): if self.write_dir is not None or self.file_prefix is not None: write_dir = (self.write_dir or 'diags') @@ -2075,6 +2073,65 @@ class ReducedDiagnostic(picmistandard.base._ClassWithInit, WarpXDiagnosticBase): separator: string The separator between row values in the output file. + + species: species instance + The name of the species for which to calculate the diagnostic, required for + diagnostic types 'BeamRelevant', 'ParticleHistogram', and 'ParticleExtrema' + + bin_number: integer + For diagnostic type 'ParticleHistogram', the number of bins used for the histogram + + bin_max: float + For diagnostic type 'ParticleHistogram', the maximum value of the bins + + bin_min: float + For diagnostic type 'ParticleHistogram', the minimum value of the bins + + normalization: {'unity_particle_weight', 'max_to_unity', 'area_to_unity'}, optional + For diagnostic type 'ParticleHistogram', normalization method of the histogram. + + histogram_function: string + For diagnostic type 'ParticleHistogram', the function evaluated to produce the histogram data + + filter_function: string, optional + For diagnostic type 'ParticleHistogram', the function to filter whether particles are included in the histogram + + reduced_function: string + For diagnostic type 'FieldReduction', the function of the fields to evaluate + + reduction_type: {'Maximum', 'Minimum', or 'Integral'} + For diagnostic type 'FieldReduction', the type of reduction + + probe_geometry: {'Point', 'Line', 'Plane'}, defaut='Point' + For diagnostic type 'FieldProbe', the geometry of the probe + + integrate: bool, default=false + For diagnostic type 'FieldProbe', whether the field is integrated + + do_moving_window_FP: bool, default=False + For diagnostic type 'FieldProbe', whether the moving window is followed + + x_probe, y_probe, z_probe: floats + For diagnostic type 'FieldProbe', a probe location. For 'Point', the location of the point. For 'Line', the start of the + line. For 'Plane', the center of the square detector. + + interp_order: integer + For diagnostic type 'FieldProbe', the interpolation order for 'Line' and 'Plane' + + resolution: integer + For diagnostic type 'FieldProbe', the number of points along the 'Line' or along each edge of the square 'Plane' + + x1_probe, y1_probe, z1_probe: floats + For diagnostic type 'FieldProbe', the end point for 'Line' + + detector_radius: float + For diagnostic type 'FieldProbe', the detector "radius" (half edge length) of the 'Plane' + + target_normal_x, target_normal_y, target_normal_z: floats + For diagnostic type 'FieldProbe', the normal vector to the 'Plane'. Only applicable in 3D + + target_up_x, target_up_y, target_up_z: floats + For diagnostic type 'FieldProbe', the vector specifying up in the 'Plane' """ def __init__(self, diag_type, name=None, period=1, path=None, @@ -2087,11 +2144,10 @@ class ReducedDiagnostic(picmistandard.base._ClassWithInit, WarpXDiagnosticBase): self.extension = extension self.separator = separator - self._species = kw.pop('species', None) + self.user_defined_kw = {} # Now we need to handle all the specific inputs required for the # different reduced diagnostic types. - # Note: only a limited number are presently supported. # The simple diagnostics do not require any additional arguments self._simple_reduced_diagnostics = [ @@ -2107,17 +2163,14 @@ class ReducedDiagnostic(picmistandard.base._ClassWithInit, WarpXDiagnosticBase): if self.type in self._simple_reduced_diagnostics: pass elif self.type in self._species_reduced_diagnostics: - if self._species is None: - raise AttributeError( - f"{self.type} reduced diagnostic requires a species." - ) + species = kw.pop('species') + self.species = species.name if self.type == 'ParticleHistogram': - raise NotImplementedError( - f"{self.type} reduced diagnostic is not yet supported " - "in pywarpx." - ) + kw = self._handle_particle_histogram(**kw) elif self.type == "FieldProbe": kw = self._handle_field_probe(**kw) + elif self.type == "FieldReduction": + kw = self._handle_field_reduction(**kw) else: raise RuntimeError( f"{self.type} reduced diagnostic is not yet supported " @@ -2158,14 +2211,55 @@ class ReducedDiagnostic(picmistandard.base._ClassWithInit, WarpXDiagnosticBase): return kw + def _handle_particle_histogram(self, **kw): + self.bin_number = kw.pop("bin_number") + self.bin_max = kw.pop("bin_max") + self.bin_min = kw.pop("bin_min") + self.normalization = kw.pop("normalization", None) + if self.normalization not in [None, "unity_particle_weight", "max_to_unity", "area_to_unity"]: + raise AttributeError( + "The ParticleHistogram normalization must be one of 'unity_particle_weight', 'max_to_unity', or 'area_to_unity'") + + histogram_function = kw.pop("histogram_function") + filter_function = kw.pop("filter_function", None) + + self.__setattr__("histogram_function(t,x,y,z,ux,uy,uz)", histogram_function) + self.__setattr__("filter_function(t,x,y,z,ux,uy,uz)", filter_function) + + # Check the reduced function expressions for constants + for k in list(kw.keys()): + if (re.search(r'\b%s\b'%k, histogram_function) or + (filter_function is not None and re.search(r'\b%s\b'%k, filter_function))): + self.user_defined_kw[k] = kw[k] + del kw[k] + + return kw + + def _handle_field_reduction(self, **kw): + self.reduction_type = kw.pop("reduction_type") + reduced_function = kw.pop("reduced_function") + + self.__setattr__("reduced_function(x,y,z,Ex,Ey,Ez,Bx,By,Bz)", reduced_function) + + # Check the reduced function expression for constants + for k in list(kw.keys()): + if re.search(r'\b%s\b'%k, reduced_function): + self.user_defined_kw[k] = kw[k] + del kw[k] + + return kw + def initialize_inputs(self): self.add_diagnostic() - for key in self.__dict__.keys(): - if not key.startswith('_') and key not in ['name', 'diagnostic']: - self.diagnostic.__setattr__(key, self.__dict__[key]) + self.mangle_dict = pywarpx.my_constants.add_keywords(self.user_defined_kw) - if self._species is not None: - diag = pywarpx.Bucket.Bucket(self.name + '.' + self._species.name) - self.diagnostic._species_dict[self._species.name] = diag + for key, value in self.__dict__.items(): + if not key.startswith('_') and key not in ['name', 'diagnostic']: + if key.endswith(")"): + # Analytic expressions require processing to deal with constants + expression = pywarpx.my_constants.mangle_expression(value, self.mangle_dict) + self.diagnostic.__setattr__(key, expression) + else: + self.diagnostic.__setattr__(key, value) |