Skip to content

particula.particles.representation

representation

Legacy particle representation facade.

Provides a deprecated facade over :class:ParticleData while preserving the legacy API for distribution strategies, activities, and surfaces.

ParticleRepresentation

ParticleRepresentation(strategy: DistributionStrategy, activity: ActivityStrategy, surface: SurfaceStrategy, distribution: NDArray[float64] | float, density: NDArray[float64] | float, concentration: NDArray[float64] | float, charge: NDArray[float64] | float | None, volume: float = 1)

Everything needed to represent a particle or a collection of particles.

Attributes:

  • strategy

    Distribution strategy for particle representation.

  • activity

    Activity strategy for partial pressure calculations.

  • surface

    Surface strategy for surface tension/Kelvin effects.

  • distribution (NDArray[float64]) –

    Distribution data for the particles.

  • density (NDArray[float64]) –

    Density array for the particles.

  • concentration (NDArray[float64]) –

    Concentration data for the particles.

  • charge (NDArray[float64] | None) –

    Charge per particle.

  • volume (float) –

    Simulation volume for the representation.

Initialize the legacy particle representation facade.

Parameters:

  • strategy (DistributionStrategy) –

    Distribution strategy for the representation.

  • activity (ActivityStrategy) –

    Activity strategy for particle-phase calculations.

  • surface (SurfaceStrategy) –

    Surface strategy for surface-property calculations.

  • distribution (NDArray[float64] | float) –

    Distribution data interpreted by strategy.

  • density (NDArray[float64] | float) –

    Particle density values.

  • concentration (NDArray[float64] | float) –

    Particle concentration values.

  • charge (NDArray[float64] | float | None) –

    Optional particle charge values.

  • volume (float, default: 1 ) –

    Simulation volume in m^3. Defaults to 1.

Notes

This legacy facade emits a deprecation log message and stores its state in an underlying :class:ParticleData container.

Source code in particula/particles/representation.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def __init__(
    self,
    strategy: DistributionStrategy,
    activity: ActivityStrategy,
    surface: SurfaceStrategy,
    distribution: NDArray[np.float64] | float,
    density: NDArray[np.float64] | float,
    concentration: NDArray[np.float64] | float,
    charge: NDArray[np.float64] | float | None,
    volume: float = 1,
):  # pylint: disable=too-many-positional-arguments, too-many-arguments
    """Initialize the legacy particle representation facade.

    Args:
        strategy: Distribution strategy for the representation.
        activity: Activity strategy for particle-phase calculations.
        surface: Surface strategy for surface-property calculations.
        distribution: Distribution data interpreted by ``strategy``.
        density: Particle density values.
        concentration: Particle concentration values.
        charge: Optional particle charge values.
        volume: Simulation volume in m^3. Defaults to 1.

    Notes:
        This legacy facade emits a deprecation log message and stores its
        state in an underlying :class:`ParticleData` container.
    """
    _warn_deprecated(stacklevel=2)

    self.strategy = strategy
    self.activity = activity
    self.surface = surface

    self._distribution = np.asarray(distribution, dtype=np.float64)
    density_array = _normalize_density_array(density)
    concentration_array = np.asarray(concentration, dtype=np.float64)
    if concentration_array.ndim == 0:
        concentration_array = np.atleast_1d(concentration_array)
    if self._distribution.ndim > 1 and concentration_array.ndim == 1:
        if concentration_array.size == 1:
            concentration_array = np.full(
                self._distribution.shape[0],
                concentration_array.item(),
                dtype=np.float64,
            )
    self._charge_is_none = charge is None
    self._charge_value = None
    if charge is not None:
        self._charge_value = self._coerce_array(
            charge,
            concentration_array,
        )
    self._charge_array = None
    self._species_mass_is_1d = False

    (
        self._data,
        self._species_mass_is_1d,
        self._charge_array,
    ) = self._build_data(
        distribution=self._distribution,
        density_array=density_array,
        concentration_array=concentration_array,
        charge_value=None if self._charge_is_none else self._charge_value,
        volume_value=float(volume),
        strategy=self.strategy,
    )

charge property writable

charge: NDArray[float64] | None

Return charge array or None when charge is disabled.

concentration property writable

concentration: NDArray[float64]

Return the concentration array for box 0.

data property

data: ParticleData

Return the underlying ParticleData container.

density property

density: NDArray[float64]

Return the density array.

distribution property writable

distribution: NDArray[float64]

Return the cached distribution array.

volume property writable

volume: float

Return the representation volume in m^3.

__str__

__str__() -> str

Return a human-readable summary of the representation.

Returns:

  • str

    Multi-line string describing the configured strategies and bulk

  • str

    concentrations.

Source code in particula/particles/representation.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
def __str__(self) -> str:
    """Return a human-readable summary of the representation.

    Returns:
        Multi-line string describing the configured strategies and bulk
        concentrations.
    """
    return (
        f"Particle Representation:\n"
        f"\tStrategy: {self.get_strategy_name()}\n"
        f"\tActivity: {self.get_activity_name()}\n"
        f"\tSurface: {self.get_surface_name()}\n"
        f"\tMass Concentration: "
        f"{self.get_mass_concentration():.3e} [kg/m^3]\n"
        f"\tNumber Concentration: "
        f"{self.get_total_concentration():.3e} [#/m^3]"
    )

add_concentration

add_concentration(added_concentration: NDArray[float64], added_distribution: Optional[NDArray[float64]] = None, *, added_charge: Optional[NDArray[float64]] = None) -> None

Add concentration to the particle distribution.

Parameters:

  • added_concentration (NDArray[float64]) –

    Concentration increment per distribution bin.

  • added_distribution (Optional[NDArray[float64]], default: None ) –

    Optional distribution array to merge into the current distribution. When omitted, the existing distribution is reused.

  • added_charge (Optional[NDArray[float64]], default: None ) –

    Optional charge array for newly added particles.

Raises:

  • ValueError

    If charge tracking is disabled but the strategy returns charge data, or if charge tracking is enabled but no updated charge data is returned.

Source code in particula/particles/representation.py
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
def add_concentration(
    self,
    added_concentration: NDArray[np.float64],
    added_distribution: Optional[NDArray[np.float64]] = None,
    *,
    added_charge: Optional[NDArray[np.float64]] = None,
) -> None:
    """Add concentration to the particle distribution.

    Args:
        added_concentration: Concentration increment per distribution bin.
        added_distribution: Optional distribution array to merge into the
            current distribution. When omitted, the existing distribution is
            reused.
        added_charge: Optional charge array for newly added particles.

    Raises:
        ValueError: If charge tracking is disabled but the strategy returns
            charge data, or if charge tracking is enabled but no updated
            charge data is returned.
    """
    _warn_deprecated(stacklevel=2)
    # if added_distribution is None, then it will be calculated
    if added_distribution is None:
        message = "Added distribution is value None."
        logger.warning(message)
        added_distribution = self.get_distribution()
    (
        distribution,
        concentration,
        updated_charge,
    ) = self.strategy.add_concentration(
        distribution=self.get_distribution(),
        concentration=self.get_concentration(),
        added_distribution=added_distribution,
        added_concentration=added_concentration,
        charge=self._charge_array,
        added_charge=added_charge,
    )
    if self._charge_is_none:
        if updated_charge is not None:
            raise ValueError(
                "updated_charge must be None when charge is disabled"
            )
        charge_array = None
    elif updated_charge is None:
        raise ValueError(
            "updated_charge must not be None when charge is set"
        )
    else:
        charge_array = updated_charge
    self._update_state(
        distribution=distribution,
        concentration=concentration,
        charge_array=charge_array,
    )
    self._enforce_increasing_bins()

add_mass

add_mass(added_mass: NDArray[float64]) -> None

Add mass to the particle distribution and update parameters.

Parameters:

  • added_mass (NDArray[float64]) –

    Mass increment per distribution bin in kg.

Source code in particula/particles/representation.py
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
def add_mass(self, added_mass: NDArray[np.float64]) -> None:
    """Add mass to the particle distribution and update parameters.

    Args:
        added_mass: Mass increment per distribution bin in ``kg``.
    """
    _warn_deprecated(stacklevel=2)
    distribution, _ = self.strategy.add_mass(
        self.get_distribution(),
        self.get_concentration(),
        self.get_density(),
        added_mass,
    )
    self._update_state(
        distribution=distribution,
        concentration=self._data.concentration[0],
        charge_array=self._charge_array,
    )
    self._enforce_increasing_bins()

collide_pairs

collide_pairs(indices: NDArray[int64]) -> None

Collide particle pairs for particle-resolved strategies.

Performs coagulation between particle pairs by delegating to the distribution strategy's collide_pairs method. The smaller particle (first index in each pair) is merged into the larger particle (second index). Mass, concentration, and charge are all updated accordingly.

Charge conservation is handled automatically: if the particles have non-zero charges, they are summed during collisions. This enables physically accurate charge conservation in particle-resolved coagulation simulations.

Parameters:

  • indices (NDArray[int64]) –

    Array of particle pair indices with shape (K, 2) where each row is [small_index, large_index].

Source code in particula/particles/representation.py
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
def collide_pairs(self, indices: NDArray[np.int64]) -> None:
    """Collide particle pairs for particle-resolved strategies.

    Performs coagulation between particle pairs by delegating to the
    distribution strategy's collide_pairs method. The smaller particle
    (first index in each pair) is merged into the larger particle (second
    index). Mass, concentration, and charge are all updated accordingly.

    Charge conservation is handled automatically: if the particles have
    non-zero charges, they are summed during collisions. This enables
    physically accurate charge conservation in particle-resolved
    coagulation simulations.

    Args:
        indices: Array of particle pair indices with shape ``(K, 2)`` where
            each row is ``[small_index, large_index]``.
    """
    _warn_deprecated(stacklevel=2)
    updated_distribution, updated_concentration, updated_charge = (
        self.strategy.collide_pairs(
            self.distribution,
            self.concentration,
            self.density,
            indices,
            self._charge_array,
        )
    )
    if self._charge_is_none:
        charge_array = None
    elif updated_charge is None:
        charge_array = np.zeros_like(updated_concentration)
    else:
        charge_array = updated_charge
    self._update_state(
        distribution=updated_distribution,
        concentration=updated_concentration,
        charge_array=charge_array,
    )

from_data classmethod

from_data(data: ParticleData, *, strategy: DistributionStrategy, activity: ActivityStrategy, surface: SurfaceStrategy, distribution: NDArray[float64], charge: NDArray[float64] | None = None) -> ParticleRepresentation

Create a facade without emitting a deprecation warning.

Parameters:

  • data (ParticleData) –

    ParticleData instance to wrap.

  • strategy (DistributionStrategy) –

    Distribution strategy for this facade.

  • activity (ActivityStrategy) –

    Activity strategy for this facade.

  • surface (SurfaceStrategy) –

    Surface strategy for this facade.

  • distribution (NDArray[float64]) –

    Cached distribution values for the facade.

  • charge (NDArray[float64] | None, default: None ) –

    Optional charge array to preserve legacy API.

Returns:

Source code in particula/particles/representation.py
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
@classmethod
def from_data(
    cls,
    data: "ParticleData",
    *,
    strategy: DistributionStrategy,
    activity: ActivityStrategy,
    surface: SurfaceStrategy,
    distribution: NDArray[np.float64],
    charge: NDArray[np.float64] | None = None,
) -> "ParticleRepresentation":
    """Create a facade without emitting a deprecation warning.

    Args:
        data: ParticleData instance to wrap.
        strategy: Distribution strategy for this facade.
        activity: Activity strategy for this facade.
        surface: Surface strategy for this facade.
        distribution: Cached distribution values for the facade.
        charge: Optional charge array to preserve legacy API.

    Returns:
        ParticleRepresentation instance wrapping ``data``.
    """
    instance = cls.__new__(cls)
    instance.strategy = strategy
    instance.activity = activity
    instance.surface = surface
    instance._data = data
    instance._distribution = np.asarray(distribution, dtype=np.float64)
    instance._charge_value = None
    instance._charge_array = None
    if charge is not None:
        instance._charge_value = np.asarray(charge, dtype=np.float64)
        instance._charge_array = instance._charge_value
    instance._species_mass_is_1d = data.masses.shape[-1] == 1
    instance._charge_is_none = instance._charge_array is None
    return instance

get_activity

get_activity(clone: bool = False) -> ActivityStrategy

Return the activity strategy used for partial pressure calculations.

Parameters:

  • clone (bool, default: False ) –

    If True, return a deep copy of the activity strategy.

Returns:

  • ActivityStrategy

    The activity strategy used for particle-phase calculations.

Source code in particula/particles/representation.py
472
473
474
475
476
477
478
479
480
481
482
483
def get_activity(self, clone: bool = False) -> ActivityStrategy:
    """Return the activity strategy used for partial pressure calculations.

    Args:
        clone: If ``True``, return a deep copy of the activity strategy.

    Returns:
        The activity strategy used for particle-phase calculations.
    """
    if clone:
        return deepcopy(self.activity)
    return self.activity

get_activity_name

get_activity_name() -> str

Return the name of the activity strategy used for partial pressure calculations.

Returns:

  • str

    The activity strategy name.

Source code in particula/particles/representation.py
485
486
487
488
489
490
491
492
def get_activity_name(self) -> str:
    """Return the name of the activity strategy used for partial pressure
    calculations.

    Returns:
        The activity strategy name.
    """
    return self.activity.get_name()

get_charge

get_charge(clone: bool = False) -> NDArray[np.float64] | None

Return the charge per particle.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the charge array.

Returns:

  • NDArray[float64] | None

    Particle charge array, or None when charge tracking is disabled.

Source code in particula/particles/representation.py
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
def get_charge(
    self,
    clone: bool = False,
) -> NDArray[np.float64] | None:
    """Return the charge per particle.

    Args:
        clone: If ``True``, return a copy of the charge array.

    Returns:
        Particle charge array, or ``None`` when charge tracking is disabled.
    """
    charge = self.charge
    if charge is None:
        return None
    if clone:
        return np.copy(charge)
    return charge

get_concentration

get_concentration(clone: bool = False) -> NDArray[np.float64]

Return the volume concentration of the particles.

For ParticleResolved Strategies, this is the number of particles per self.volume. Otherwise, it's per 1/m^3.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the concentration array.

Returns:

  • NDArray[float64]

    Particle concentration in 1/m^3.

Source code in particula/particles/representation.py
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
def get_concentration(self, clone: bool = False) -> NDArray[np.float64]:
    """Return the volume concentration of the particles.

    For ParticleResolved Strategies, this is the number of
    particles per self.volume. Otherwise, it's per 1/m^3.

    Args:
        clone: If ``True``, return a copy of the concentration array.

    Returns:
        Particle concentration in ``1/m^3``.
    """
    concentration = self._data.concentration[0] / self._data.volume[0]
    if clone:
        return np.copy(concentration)
    return concentration

get_density

get_density(clone: bool = False) -> NDArray[np.float64]

Return the density of the particles.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the density array.

Returns:

  • NDArray[float64]

    The particle density array.

Source code in particula/particles/representation.py
529
530
531
532
533
534
535
536
537
538
539
540
def get_density(self, clone: bool = False) -> NDArray[np.float64]:
    """Return the density of the particles.

    Args:
        clone: If ``True``, return a copy of the density array.

    Returns:
        The particle density array.
    """
    if clone:
        return np.copy(self.density)
    return self.density

get_distribution

get_distribution(clone: bool = False) -> NDArray[np.float64]

Return the distribution of the particles.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the distribution array.

Returns:

  • NDArray[float64]

    The particle distribution array.

Source code in particula/particles/representation.py
516
517
518
519
520
521
522
523
524
525
526
527
def get_distribution(self, clone: bool = False) -> NDArray[np.float64]:
    """Return the distribution of the particles.

    Args:
        clone: If ``True``, return a copy of the distribution array.

    Returns:
        The particle distribution array.
    """
    if clone:
        return np.copy(self.distribution)
    return self.distribution

get_effective_density

get_effective_density() -> NDArray[np.float64]

Return the effective density of the particles, weighted by the mass.

Returns:

  • NDArray[float64]

    Effective particle densities derived from species masses.

Source code in particula/particles/representation.py
542
543
544
545
546
547
548
549
550
551
def get_effective_density(self) -> NDArray[np.float64]:
    """Return the effective density of the particles, weighted by the mass.

    Returns:
        Effective particle densities derived from species masses.
    """
    densities = self.get_density()
    if np.size(densities) == 1:
        return np.ones_like(self.get_species_mass()) * densities
    return np.copy(self._data.effective_density[0])

get_mass

get_mass(clone: bool = False) -> NDArray[np.float64]

Return the mass of the particles as calculated by the strategy.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the mass array.

Returns:

  • NDArray[float64]

    Total particle masses in kg.

Source code in particula/particles/representation.py
642
643
644
645
646
647
648
649
650
651
652
653
654
def get_mass(self, clone: bool = False) -> NDArray[np.float64]:
    """Return the mass of the particles as calculated by the strategy.

    Args:
        clone: If ``True``, return a copy of the mass array.

    Returns:
        Total particle masses in ``kg``.
    """
    mass = self._data.total_mass[0]
    if clone:
        return np.copy(mass)
    return mass

get_mass_concentration

get_mass_concentration(clone: bool = False) -> np.float64

Return the total mass per volume of the simulated particles.

The mass concentration is calculated from the distribution and concentration arrays.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the mass concentration value.

Returns:

  • float64

    Total particle mass concentration in kg/m^3.

Source code in particula/particles/representation.py
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
def get_mass_concentration(self, clone: bool = False) -> np.float64:
    """Return the total mass per volume of the simulated particles.

    The mass concentration is calculated from the distribution
    and concentration arrays.

    Args:
        clone: If ``True``, return a copy of the mass concentration value.

    Returns:
        Total particle mass concentration in ``kg/m^3``.
    """
    mass_concentration = np.sum(self.get_mass() * self.get_concentration())
    if clone:
        return deepcopy(mass_concentration)
    return mass_concentration

get_mean_effective_density

get_mean_effective_density() -> float

Return the mean effective density of the particles.

Returns:

  • float

    Mean effective density across nonzero-density particles.

Source code in particula/particles/representation.py
553
554
555
556
557
558
559
560
561
562
563
564
def get_mean_effective_density(self) -> float:
    """Return the mean effective density of the particles.

    Returns:
        Mean effective density across nonzero-density particles.
    """
    # filter out zero densities for no mass in bin/particle
    effective_density = self.get_effective_density()
    effective_density = effective_density[effective_density != 0]
    if effective_density.size == 0:
        return 0.0
    return float(np.mean(effective_density))

get_radius

get_radius(clone: bool = False) -> NDArray[np.float64]

Return the radius of the particles as calculated by the strategy.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the radius array.

Returns:

  • NDArray[float64]

    Particle radii in meters.

Source code in particula/particles/representation.py
673
674
675
676
677
678
679
680
681
682
683
684
685
def get_radius(self, clone: bool = False) -> NDArray[np.float64]:
    """Return the radius of the particles as calculated by the strategy.

    Args:
        clone: If ``True``, return a copy of the radius array.

    Returns:
        Particle radii in meters.
    """
    radius = self._data.radii[0]
    if clone:
        return np.copy(radius)
    return radius

get_species_mass

get_species_mass(clone: bool = False) -> NDArray[np.float64]

Return the masses per species in the particles.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the computed mass array.

Returns:

  • NDArray[float64]

    Per-species particle masses in kg.

Source code in particula/particles/representation.py
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
def get_species_mass(self, clone: bool = False) -> NDArray[np.float64]:
    """Return the masses per species in the particles.

    Args:
        clone: If ``True``, return a copy of the computed mass array.

    Returns:
        Per-species particle masses in ``kg``.
    """
    masses = self._data.masses[0]
    if self._species_mass_is_1d:
        masses = masses[:, 0]
    if clone:
        return np.copy(masses)
    return masses

get_strategy

get_strategy(clone: bool = False) -> DistributionStrategy

Return the strategy used for particle representation.

Parameters:

  • clone (bool, default: False ) –

    If True, return a deep copy of the strategy.

Returns:

Source code in particula/particles/representation.py
451
452
453
454
455
456
457
458
459
460
461
462
def get_strategy(self, clone: bool = False) -> DistributionStrategy:
    """Return the strategy used for particle representation.

    Args:
        clone: If ``True``, return a deep copy of the strategy.

    Returns:
        The distribution strategy used by this representation.
    """
    if clone:
        return deepcopy(self.strategy)
    return self.strategy

get_strategy_name

get_strategy_name() -> str

Return the name of the strategy used for particle representation.

Returns:

  • str

    The distribution strategy name.

Source code in particula/particles/representation.py
464
465
466
467
468
469
470
def get_strategy_name(self) -> str:
    """Return the name of the strategy used for particle representation.

    Returns:
        The distribution strategy name.
    """
    return self.strategy.get_name()

get_surface

get_surface(clone: bool = False) -> SurfaceStrategy

Return surface strategy for surface tension and Kelvin effect.

Parameters:

  • clone (bool, default: False ) –

    If True, return a deep copy of the surface strategy.

Returns:

  • SurfaceStrategy

    The surface strategy used for Kelvin and surface-tension effects.

Source code in particula/particles/representation.py
494
495
496
497
498
499
500
501
502
503
504
505
def get_surface(self, clone: bool = False) -> SurfaceStrategy:
    """Return surface strategy for surface tension and Kelvin effect.

    Args:
        clone: If ``True``, return a deep copy of the surface strategy.

    Returns:
        The surface strategy used for Kelvin and surface-tension effects.
    """
    if clone:
        return deepcopy(self.surface)
    return self.surface

get_surface_name

get_surface_name() -> str

Return the name of the surface strategy used for surface tension and Kelvin effect.

Returns:

  • str

    The surface strategy name.

Source code in particula/particles/representation.py
507
508
509
510
511
512
513
514
def get_surface_name(self) -> str:
    """Return the name of the surface strategy used for surface tension and
    Kelvin effect.

    Returns:
        The surface strategy name.
    """
    return self.surface.get_name()

get_total_concentration

get_total_concentration(clone: bool = False) -> np.float64

Return the total concentration of the particles.

Parameters:

  • clone (bool, default: False ) –

    If True, operate on a copied concentration array.

Returns:

  • float64

    Total number concentration in 1/m^3.

Source code in particula/particles/representation.py
583
584
585
586
587
588
589
590
591
592
def get_total_concentration(self, clone: bool = False) -> np.float64:
    """Return the total concentration of the particles.

    Args:
        clone: If ``True``, operate on a copied concentration array.

    Returns:
        Total number concentration in ``1/m^3``.
    """
    return np.sum(self.get_concentration(clone=clone))

get_volume

get_volume(clone: bool = False) -> float

Return the volume used for the particle representation.

Parameters:

  • clone (bool, default: False ) –

    If True, return a copy of the volume value.

Returns:

  • float

    Representation volume in m^3.

Source code in particula/particles/representation.py
613
614
615
616
617
618
619
620
621
622
623
624
def get_volume(self, clone: bool = False) -> float:
    """Return the volume used for the particle representation.

    Args:
        clone: If ``True``, return a copy of the volume value.

    Returns:
        Representation volume in ``m^3``.
    """
    if clone:
        return deepcopy(self.volume)
    return self.volume