PySDM_examples.utils.kinematic_2d.simulation

  1import numpy as np
  2from PySDM_examples.utils.kinematic_2d.make_default_product_collection import (
  3    make_default_product_collection,
  4)
  5from PySDM_examples.utils.kinematic_2d.mpdata_2d import MPDATA_2D
  6from PySDM_examples.utils import DummyController
  7
  8from PySDM.backends import CPU
  9from PySDM.builder import Builder
 10from PySDM.dynamics import (
 11    AmbientThermodynamics,
 12    Coalescence,
 13    Collision,
 14    Condensation,
 15    Displacement,
 16    EulerianAdvection,
 17    Freezing,
 18)
 19from PySDM.environments import Kinematic2D
 20from PySDM.initialisation.sampling import spatial_sampling
 21
 22
 23class Simulation:
 24    def __init__(self, settings, storage, SpinUp, backend_class=CPU):
 25        self.settings = settings
 26        self.storage = storage
 27        self.particulator = None
 28        self.backend_class = backend_class
 29        self.SpinUp = SpinUp
 30
 31    @property
 32    def products(self):
 33        return self.particulator.products
 34
 35    def reinit(self, products=None):
 36        formulae = self.settings.formulae
 37        backend = self.backend_class(formulae=formulae)
 38        environment = Kinematic2D(
 39            dt=self.settings.dt,
 40            grid=self.settings.grid,
 41            size=self.settings.size,
 42            rhod_of=self.settings.rhod_of_zZ,
 43            mixed_phase=self.settings.processes["freezing"],
 44        )
 45
 46        dynamics = []
 47
 48        if products is not None:
 49            products = list(products)
 50        else:
 51            products = make_default_product_collection(self.settings)
 52
 53        if self.settings.processes["fluid advection"]:
 54            dynamics.append(AmbientThermodynamics())
 55        if self.settings.processes["condensation"]:
 56            kwargs = {}
 57            if not self.settings.condensation_adaptive:
 58                kwargs["substeps"] = (self.settings.condensation_substeps,)
 59            condensation = Condensation(
 60                rtol_x=self.settings.condensation_rtol_x,
 61                rtol_thd=self.settings.condensation_rtol_thd,
 62                adaptive=self.settings.condensation_adaptive,
 63                dt_cond_range=self.settings.condensation_dt_cond_range,
 64                schedule=self.settings.condensation_schedule,
 65                **kwargs,
 66            )
 67            dynamics.append(condensation)
 68        if self.settings.processes["fluid advection"]:
 69            initial_profiles = {
 70                "th": self.settings.initial_dry_potential_temperature_profile,
 71                "water_vapour_mixing_ratio": self.settings.initial_vapour_mixing_ratio_profile,
 72            }
 73            advectees = dict(
 74                (
 75                    key,
 76                    np.repeat(
 77                        profile.reshape(1, -1),
 78                        self.settings.grid[0],
 79                        axis=0,
 80                    ),
 81                )
 82                for key, profile in initial_profiles.items()
 83            )
 84            solver = MPDATA_2D(
 85                advectees=advectees,
 86                stream_function=self.settings.stream_function,
 87                rhod_of_zZ=self.settings.rhod_of_zZ,
 88                dt=self.settings.dt,
 89                grid=self.settings.grid,
 90                size=self.settings.size,
 91                n_iters=self.settings.mpdata_iters,
 92                infinite_gauge=self.settings.mpdata_iga,
 93                nonoscillatory=self.settings.mpdata_fct,
 94                third_order_terms=self.settings.mpdata_tot,
 95            )
 96            dynamics.append(EulerianAdvection(solver))
 97        if self.settings.processes["particle advection"]:
 98            dynamics.append(
 99                Displacement(
100                    enable_sedimentation=self.settings.processes["sedimentation"],
101                    adaptive=self.settings.displacement_adaptive,
102                    rtol=self.settings.displacement_rtol,
103                )
104            )
105        if (
106            self.settings.processes["coalescence"]
107            and self.settings.processes["breakup"]
108        ):
109            dynamics.append(
110                Collision(
111                    collision_kernel=self.settings.kernel,
112                    enable_breakup=self.settings.processes["breakup"],
113                    coalescence_efficiency=self.settings.coalescence_efficiency,
114                    breakup_efficiency=self.settings.breakup_efficiency,
115                    fragmentation_function=self.settings.breakup_fragmentation,
116                    adaptive=self.settings.coalescence_adaptive,
117                    dt_coal_range=self.settings.coalescence_dt_coal_range,
118                    substeps=self.settings.coalescence_substeps,
119                    optimized_random=self.settings.coalescence_optimized_random,
120                )
121            )
122        elif (
123            self.settings.processes["coalescence"]
124            and not self.settings.processes["breakup"]
125        ):
126            dynamics.append(
127                Coalescence(
128                    collision_kernel=self.settings.kernel,
129                    adaptive=self.settings.coalescence_adaptive,
130                    dt_coal_range=self.settings.coalescence_dt_coal_range,
131                    substeps=self.settings.coalescence_substeps,
132                    optimized_random=self.settings.coalescence_optimized_random,
133                )
134            )
135        assert not (
136            self.settings.processes["breakup"]
137            and not self.settings.processes["coalescence"]
138        )
139        if self.settings.processes["freezing"]:
140            dynamics.append(
141                Freezing(
142                    immersion_freezing=self.settings.freezing_immersion,
143                    thaw=self.settings.freezing_thaw,
144                )
145            )
146
147        builder = Builder(
148            n_sd=self.settings.n_sd,
149            backend=backend,
150            environment=environment,
151            dynamics=dynamics,
152        )
153
154        attributes = builder.particulator.environment.init_attributes(
155            spatial_discretisation=spatial_sampling.Pseudorandom(),
156            dry_radius_spectrum=self.settings.spectrum_per_mass_of_dry_air,
157            kappa=self.settings.kappa,
158            n_sd=self.settings.n_sd
159            // (2 if self.settings.freezing_inp_frac != 1 else 1),
160        )
161
162        if self.settings.processes["freezing"]:
163            attributes["signed water mass"] = attributes.pop("water mass")
164
165            if self.settings.freezing_inp_spec is None:
166                immersed_surface_area = formulae.trivia.sphere_surface(
167                    diameter=2 * formulae.trivia.radius(volume=attributes["dry volume"])
168                )
169            else:
170                immersed_surface_area = self.settings.freezing_inp_spec.percentiles(
171                    np.random.random(attributes["dry volume"].size),  # TODO #599: seed
172                )
173
174            if self.settings.freezing_immersion == "singular":
175                attributes["freezing temperature"] = (
176                    formulae.freezing_temperature_spectrum.invcdf(
177                        np.random.random(immersed_surface_area.size),  # TODO #599: seed
178                        immersed_surface_area,
179                    )
180                )
181            else:
182                attributes["immersed surface area"] = immersed_surface_area
183
184            if self.settings.freezing_inp_frac != 1:
185                assert self.settings.n_sd % 2 == 0
186                assert 0 < self.settings.freezing_inp_frac < 1
187                freezing_attribute = {
188                    "singular": "freezing temperature",
189                    "time-dependent": "immersed surface area",
190                }[self.settings.freezing_immersion]
191                for name, array in attributes.items():
192                    if array.shape[-1] != self.settings.n_sd // 2:
193                        raise AssertionError(f"attribute >>{name}<< has wrong size")
194                    array = array.copy()
195                    full_shape = list(array.shape)
196                    orig = slice(None, full_shape[-1])
197                    copy = slice(orig.stop, None)
198                    full_shape[-1] *= 2
199                    attributes[name] = np.empty(full_shape, dtype=array.dtype)
200                    if name == freezing_attribute:
201                        attributes[name][orig] = array
202                        attributes[name][copy] = 0
203                    elif name == "multiplicity":
204                        attributes[name][orig] = array * self.settings.freezing_inp_frac
205                        attributes[name][copy] = array * (
206                            1 - self.settings.freezing_inp_frac
207                        )
208                    elif len(array.shape) > 1:  # particle positions
209                        # TODO #599: seed
210                        for dim, _ in enumerate(array.shape):
211                            # only to make particles not shadow each other in visualisations
212                            attributes[name][dim, orig] = array[dim, :]
213                            attributes[name][dim, copy] = np.random.permutation(
214                                array[dim, :]
215                            )
216                    else:
217                        attributes[name][orig] = array
218                        attributes[name][copy] = array
219
220                non_zero_per_gridbox = np.count_nonzero(
221                    attributes[freezing_attribute]
222                ) / np.prod(self.settings.grid)
223                assert non_zero_per_gridbox == self.settings.n_sd_per_gridbox / 2
224
225        self.particulator = builder.build(attributes, tuple(products))
226
227        if self.SpinUp is not None:
228            self.SpinUp(self.particulator, self.settings.n_spin_up)
229        if self.storage is not None:
230            self.storage.init(self.settings)
231
232    def run(self, controller=DummyController(), vtk_exporter=None):
233        with controller:
234            for step in self.settings.output_steps:
235                if controller.panic:
236                    break
237
238                self.particulator.run(step - self.particulator.n_steps)
239
240                self.store(step)
241
242                if vtk_exporter is not None:
243                    vtk_exporter.export_attributes(self.particulator)
244                    vtk_exporter.export_products(self.particulator)
245
246                controller.set_percent(step / self.settings.output_steps[-1])
247
248    def store(self, step):
249        for name, product in self.particulator.products.items():
250            self.storage.save(product.get(), step, name)
class Simulation:
 24class Simulation:
 25    def __init__(self, settings, storage, SpinUp, backend_class=CPU):
 26        self.settings = settings
 27        self.storage = storage
 28        self.particulator = None
 29        self.backend_class = backend_class
 30        self.SpinUp = SpinUp
 31
 32    @property
 33    def products(self):
 34        return self.particulator.products
 35
 36    def reinit(self, products=None):
 37        formulae = self.settings.formulae
 38        backend = self.backend_class(formulae=formulae)
 39        environment = Kinematic2D(
 40            dt=self.settings.dt,
 41            grid=self.settings.grid,
 42            size=self.settings.size,
 43            rhod_of=self.settings.rhod_of_zZ,
 44            mixed_phase=self.settings.processes["freezing"],
 45        )
 46
 47        dynamics = []
 48
 49        if products is not None:
 50            products = list(products)
 51        else:
 52            products = make_default_product_collection(self.settings)
 53
 54        if self.settings.processes["fluid advection"]:
 55            dynamics.append(AmbientThermodynamics())
 56        if self.settings.processes["condensation"]:
 57            kwargs = {}
 58            if not self.settings.condensation_adaptive:
 59                kwargs["substeps"] = (self.settings.condensation_substeps,)
 60            condensation = Condensation(
 61                rtol_x=self.settings.condensation_rtol_x,
 62                rtol_thd=self.settings.condensation_rtol_thd,
 63                adaptive=self.settings.condensation_adaptive,
 64                dt_cond_range=self.settings.condensation_dt_cond_range,
 65                schedule=self.settings.condensation_schedule,
 66                **kwargs,
 67            )
 68            dynamics.append(condensation)
 69        if self.settings.processes["fluid advection"]:
 70            initial_profiles = {
 71                "th": self.settings.initial_dry_potential_temperature_profile,
 72                "water_vapour_mixing_ratio": self.settings.initial_vapour_mixing_ratio_profile,
 73            }
 74            advectees = dict(
 75                (
 76                    key,
 77                    np.repeat(
 78                        profile.reshape(1, -1),
 79                        self.settings.grid[0],
 80                        axis=0,
 81                    ),
 82                )
 83                for key, profile in initial_profiles.items()
 84            )
 85            solver = MPDATA_2D(
 86                advectees=advectees,
 87                stream_function=self.settings.stream_function,
 88                rhod_of_zZ=self.settings.rhod_of_zZ,
 89                dt=self.settings.dt,
 90                grid=self.settings.grid,
 91                size=self.settings.size,
 92                n_iters=self.settings.mpdata_iters,
 93                infinite_gauge=self.settings.mpdata_iga,
 94                nonoscillatory=self.settings.mpdata_fct,
 95                third_order_terms=self.settings.mpdata_tot,
 96            )
 97            dynamics.append(EulerianAdvection(solver))
 98        if self.settings.processes["particle advection"]:
 99            dynamics.append(
100                Displacement(
101                    enable_sedimentation=self.settings.processes["sedimentation"],
102                    adaptive=self.settings.displacement_adaptive,
103                    rtol=self.settings.displacement_rtol,
104                )
105            )
106        if (
107            self.settings.processes["coalescence"]
108            and self.settings.processes["breakup"]
109        ):
110            dynamics.append(
111                Collision(
112                    collision_kernel=self.settings.kernel,
113                    enable_breakup=self.settings.processes["breakup"],
114                    coalescence_efficiency=self.settings.coalescence_efficiency,
115                    breakup_efficiency=self.settings.breakup_efficiency,
116                    fragmentation_function=self.settings.breakup_fragmentation,
117                    adaptive=self.settings.coalescence_adaptive,
118                    dt_coal_range=self.settings.coalescence_dt_coal_range,
119                    substeps=self.settings.coalescence_substeps,
120                    optimized_random=self.settings.coalescence_optimized_random,
121                )
122            )
123        elif (
124            self.settings.processes["coalescence"]
125            and not self.settings.processes["breakup"]
126        ):
127            dynamics.append(
128                Coalescence(
129                    collision_kernel=self.settings.kernel,
130                    adaptive=self.settings.coalescence_adaptive,
131                    dt_coal_range=self.settings.coalescence_dt_coal_range,
132                    substeps=self.settings.coalescence_substeps,
133                    optimized_random=self.settings.coalescence_optimized_random,
134                )
135            )
136        assert not (
137            self.settings.processes["breakup"]
138            and not self.settings.processes["coalescence"]
139        )
140        if self.settings.processes["freezing"]:
141            dynamics.append(
142                Freezing(
143                    immersion_freezing=self.settings.freezing_immersion,
144                    thaw=self.settings.freezing_thaw,
145                )
146            )
147
148        builder = Builder(
149            n_sd=self.settings.n_sd,
150            backend=backend,
151            environment=environment,
152            dynamics=dynamics,
153        )
154
155        attributes = builder.particulator.environment.init_attributes(
156            spatial_discretisation=spatial_sampling.Pseudorandom(),
157            dry_radius_spectrum=self.settings.spectrum_per_mass_of_dry_air,
158            kappa=self.settings.kappa,
159            n_sd=self.settings.n_sd
160            // (2 if self.settings.freezing_inp_frac != 1 else 1),
161        )
162
163        if self.settings.processes["freezing"]:
164            attributes["signed water mass"] = attributes.pop("water mass")
165
166            if self.settings.freezing_inp_spec is None:
167                immersed_surface_area = formulae.trivia.sphere_surface(
168                    diameter=2 * formulae.trivia.radius(volume=attributes["dry volume"])
169                )
170            else:
171                immersed_surface_area = self.settings.freezing_inp_spec.percentiles(
172                    np.random.random(attributes["dry volume"].size),  # TODO #599: seed
173                )
174
175            if self.settings.freezing_immersion == "singular":
176                attributes["freezing temperature"] = (
177                    formulae.freezing_temperature_spectrum.invcdf(
178                        np.random.random(immersed_surface_area.size),  # TODO #599: seed
179                        immersed_surface_area,
180                    )
181                )
182            else:
183                attributes["immersed surface area"] = immersed_surface_area
184
185            if self.settings.freezing_inp_frac != 1:
186                assert self.settings.n_sd % 2 == 0
187                assert 0 < self.settings.freezing_inp_frac < 1
188                freezing_attribute = {
189                    "singular": "freezing temperature",
190                    "time-dependent": "immersed surface area",
191                }[self.settings.freezing_immersion]
192                for name, array in attributes.items():
193                    if array.shape[-1] != self.settings.n_sd // 2:
194                        raise AssertionError(f"attribute >>{name}<< has wrong size")
195                    array = array.copy()
196                    full_shape = list(array.shape)
197                    orig = slice(None, full_shape[-1])
198                    copy = slice(orig.stop, None)
199                    full_shape[-1] *= 2
200                    attributes[name] = np.empty(full_shape, dtype=array.dtype)
201                    if name == freezing_attribute:
202                        attributes[name][orig] = array
203                        attributes[name][copy] = 0
204                    elif name == "multiplicity":
205                        attributes[name][orig] = array * self.settings.freezing_inp_frac
206                        attributes[name][copy] = array * (
207                            1 - self.settings.freezing_inp_frac
208                        )
209                    elif len(array.shape) > 1:  # particle positions
210                        # TODO #599: seed
211                        for dim, _ in enumerate(array.shape):
212                            # only to make particles not shadow each other in visualisations
213                            attributes[name][dim, orig] = array[dim, :]
214                            attributes[name][dim, copy] = np.random.permutation(
215                                array[dim, :]
216                            )
217                    else:
218                        attributes[name][orig] = array
219                        attributes[name][copy] = array
220
221                non_zero_per_gridbox = np.count_nonzero(
222                    attributes[freezing_attribute]
223                ) / np.prod(self.settings.grid)
224                assert non_zero_per_gridbox == self.settings.n_sd_per_gridbox / 2
225
226        self.particulator = builder.build(attributes, tuple(products))
227
228        if self.SpinUp is not None:
229            self.SpinUp(self.particulator, self.settings.n_spin_up)
230        if self.storage is not None:
231            self.storage.init(self.settings)
232
233    def run(self, controller=DummyController(), vtk_exporter=None):
234        with controller:
235            for step in self.settings.output_steps:
236                if controller.panic:
237                    break
238
239                self.particulator.run(step - self.particulator.n_steps)
240
241                self.store(step)
242
243                if vtk_exporter is not None:
244                    vtk_exporter.export_attributes(self.particulator)
245                    vtk_exporter.export_products(self.particulator)
246
247                controller.set_percent(step / self.settings.output_steps[-1])
248
249    def store(self, step):
250        for name, product in self.particulator.products.items():
251            self.storage.save(product.get(), step, name)
Simulation( settings, storage, SpinUp, backend_class=functools.partial(<function _cached_backend>, backend_class=<class 'PySDM.backends.Numba'>))
25    def __init__(self, settings, storage, SpinUp, backend_class=CPU):
26        self.settings = settings
27        self.storage = storage
28        self.particulator = None
29        self.backend_class = backend_class
30        self.SpinUp = SpinUp
settings
storage
particulator
backend_class
SpinUp
products
32    @property
33    def products(self):
34        return self.particulator.products
def reinit(self, products=None):
 36    def reinit(self, products=None):
 37        formulae = self.settings.formulae
 38        backend = self.backend_class(formulae=formulae)
 39        environment = Kinematic2D(
 40            dt=self.settings.dt,
 41            grid=self.settings.grid,
 42            size=self.settings.size,
 43            rhod_of=self.settings.rhod_of_zZ,
 44            mixed_phase=self.settings.processes["freezing"],
 45        )
 46
 47        dynamics = []
 48
 49        if products is not None:
 50            products = list(products)
 51        else:
 52            products = make_default_product_collection(self.settings)
 53
 54        if self.settings.processes["fluid advection"]:
 55            dynamics.append(AmbientThermodynamics())
 56        if self.settings.processes["condensation"]:
 57            kwargs = {}
 58            if not self.settings.condensation_adaptive:
 59                kwargs["substeps"] = (self.settings.condensation_substeps,)
 60            condensation = Condensation(
 61                rtol_x=self.settings.condensation_rtol_x,
 62                rtol_thd=self.settings.condensation_rtol_thd,
 63                adaptive=self.settings.condensation_adaptive,
 64                dt_cond_range=self.settings.condensation_dt_cond_range,
 65                schedule=self.settings.condensation_schedule,
 66                **kwargs,
 67            )
 68            dynamics.append(condensation)
 69        if self.settings.processes["fluid advection"]:
 70            initial_profiles = {
 71                "th": self.settings.initial_dry_potential_temperature_profile,
 72                "water_vapour_mixing_ratio": self.settings.initial_vapour_mixing_ratio_profile,
 73            }
 74            advectees = dict(
 75                (
 76                    key,
 77                    np.repeat(
 78                        profile.reshape(1, -1),
 79                        self.settings.grid[0],
 80                        axis=0,
 81                    ),
 82                )
 83                for key, profile in initial_profiles.items()
 84            )
 85            solver = MPDATA_2D(
 86                advectees=advectees,
 87                stream_function=self.settings.stream_function,
 88                rhod_of_zZ=self.settings.rhod_of_zZ,
 89                dt=self.settings.dt,
 90                grid=self.settings.grid,
 91                size=self.settings.size,
 92                n_iters=self.settings.mpdata_iters,
 93                infinite_gauge=self.settings.mpdata_iga,
 94                nonoscillatory=self.settings.mpdata_fct,
 95                third_order_terms=self.settings.mpdata_tot,
 96            )
 97            dynamics.append(EulerianAdvection(solver))
 98        if self.settings.processes["particle advection"]:
 99            dynamics.append(
100                Displacement(
101                    enable_sedimentation=self.settings.processes["sedimentation"],
102                    adaptive=self.settings.displacement_adaptive,
103                    rtol=self.settings.displacement_rtol,
104                )
105            )
106        if (
107            self.settings.processes["coalescence"]
108            and self.settings.processes["breakup"]
109        ):
110            dynamics.append(
111                Collision(
112                    collision_kernel=self.settings.kernel,
113                    enable_breakup=self.settings.processes["breakup"],
114                    coalescence_efficiency=self.settings.coalescence_efficiency,
115                    breakup_efficiency=self.settings.breakup_efficiency,
116                    fragmentation_function=self.settings.breakup_fragmentation,
117                    adaptive=self.settings.coalescence_adaptive,
118                    dt_coal_range=self.settings.coalescence_dt_coal_range,
119                    substeps=self.settings.coalescence_substeps,
120                    optimized_random=self.settings.coalescence_optimized_random,
121                )
122            )
123        elif (
124            self.settings.processes["coalescence"]
125            and not self.settings.processes["breakup"]
126        ):
127            dynamics.append(
128                Coalescence(
129                    collision_kernel=self.settings.kernel,
130                    adaptive=self.settings.coalescence_adaptive,
131                    dt_coal_range=self.settings.coalescence_dt_coal_range,
132                    substeps=self.settings.coalescence_substeps,
133                    optimized_random=self.settings.coalescence_optimized_random,
134                )
135            )
136        assert not (
137            self.settings.processes["breakup"]
138            and not self.settings.processes["coalescence"]
139        )
140        if self.settings.processes["freezing"]:
141            dynamics.append(
142                Freezing(
143                    immersion_freezing=self.settings.freezing_immersion,
144                    thaw=self.settings.freezing_thaw,
145                )
146            )
147
148        builder = Builder(
149            n_sd=self.settings.n_sd,
150            backend=backend,
151            environment=environment,
152            dynamics=dynamics,
153        )
154
155        attributes = builder.particulator.environment.init_attributes(
156            spatial_discretisation=spatial_sampling.Pseudorandom(),
157            dry_radius_spectrum=self.settings.spectrum_per_mass_of_dry_air,
158            kappa=self.settings.kappa,
159            n_sd=self.settings.n_sd
160            // (2 if self.settings.freezing_inp_frac != 1 else 1),
161        )
162
163        if self.settings.processes["freezing"]:
164            attributes["signed water mass"] = attributes.pop("water mass")
165
166            if self.settings.freezing_inp_spec is None:
167                immersed_surface_area = formulae.trivia.sphere_surface(
168                    diameter=2 * formulae.trivia.radius(volume=attributes["dry volume"])
169                )
170            else:
171                immersed_surface_area = self.settings.freezing_inp_spec.percentiles(
172                    np.random.random(attributes["dry volume"].size),  # TODO #599: seed
173                )
174
175            if self.settings.freezing_immersion == "singular":
176                attributes["freezing temperature"] = (
177                    formulae.freezing_temperature_spectrum.invcdf(
178                        np.random.random(immersed_surface_area.size),  # TODO #599: seed
179                        immersed_surface_area,
180                    )
181                )
182            else:
183                attributes["immersed surface area"] = immersed_surface_area
184
185            if self.settings.freezing_inp_frac != 1:
186                assert self.settings.n_sd % 2 == 0
187                assert 0 < self.settings.freezing_inp_frac < 1
188                freezing_attribute = {
189                    "singular": "freezing temperature",
190                    "time-dependent": "immersed surface area",
191                }[self.settings.freezing_immersion]
192                for name, array in attributes.items():
193                    if array.shape[-1] != self.settings.n_sd // 2:
194                        raise AssertionError(f"attribute >>{name}<< has wrong size")
195                    array = array.copy()
196                    full_shape = list(array.shape)
197                    orig = slice(None, full_shape[-1])
198                    copy = slice(orig.stop, None)
199                    full_shape[-1] *= 2
200                    attributes[name] = np.empty(full_shape, dtype=array.dtype)
201                    if name == freezing_attribute:
202                        attributes[name][orig] = array
203                        attributes[name][copy] = 0
204                    elif name == "multiplicity":
205                        attributes[name][orig] = array * self.settings.freezing_inp_frac
206                        attributes[name][copy] = array * (
207                            1 - self.settings.freezing_inp_frac
208                        )
209                    elif len(array.shape) > 1:  # particle positions
210                        # TODO #599: seed
211                        for dim, _ in enumerate(array.shape):
212                            # only to make particles not shadow each other in visualisations
213                            attributes[name][dim, orig] = array[dim, :]
214                            attributes[name][dim, copy] = np.random.permutation(
215                                array[dim, :]
216                            )
217                    else:
218                        attributes[name][orig] = array
219                        attributes[name][copy] = array
220
221                non_zero_per_gridbox = np.count_nonzero(
222                    attributes[freezing_attribute]
223                ) / np.prod(self.settings.grid)
224                assert non_zero_per_gridbox == self.settings.n_sd_per_gridbox / 2
225
226        self.particulator = builder.build(attributes, tuple(products))
227
228        if self.SpinUp is not None:
229            self.SpinUp(self.particulator, self.settings.n_spin_up)
230        if self.storage is not None:
231            self.storage.init(self.settings)
def run( self, controller=<PySDM_examples.utils.dummy_controller.DummyController object>, vtk_exporter=None):
233    def run(self, controller=DummyController(), vtk_exporter=None):
234        with controller:
235            for step in self.settings.output_steps:
236                if controller.panic:
237                    break
238
239                self.particulator.run(step - self.particulator.n_steps)
240
241                self.store(step)
242
243                if vtk_exporter is not None:
244                    vtk_exporter.export_attributes(self.particulator)
245                    vtk_exporter.export_products(self.particulator)
246
247                controller.set_percent(step / self.settings.output_steps[-1])
def store(self, step):
249    def store(self, step):
250        for name, product in self.particulator.products.items():
251            self.storage.save(product.get(), step, name)