PySDM.builder
The Builder class handling creation of PySDM.particulator.Particulator instances
1""" 2The Builder class handling creation of `PySDM.particulator.Particulator` instances 3""" 4 5import inspect 6 7import numpy as np 8 9from PySDM.attributes.impl.attribute_registry import get_attribute_class 10from PySDM.impl.particle_attributes_factory import ParticleAttributesFactory 11from PySDM.impl.wall_timer import WallTimer 12from PySDM.initialisation.discretise_multiplicities import ( # TODO #324 13 discretise_multiplicities, 14) 15from PySDM.particulator import Particulator 16from PySDM.physics.particle_shape_and_density import LiquidSpheres, MixedPhaseSpheres 17 18 19class Builder: 20 def __init__(self, n_sd, backend, environment=None): 21 assert not inspect.isclass(backend) 22 self.formulae = backend.formulae 23 self.particulator = Particulator(n_sd, backend) 24 self.req_attr_names = ["multiplicity", "water mass", "cell id"] 25 self.req_attr = None 26 self.aerosol_radius_threshold = 0 27 self.condensation_params = None 28 self.particulator.environment = environment.instantiate(builder=self) 29 30 def _set_condensation_parameters(self, **kwargs): 31 self.condensation_params = kwargs 32 33 def add_dynamic(self, dynamic): 34 assert self.particulator.environment is not None 35 key = inspect.getmro(type(dynamic))[-2].__name__ 36 assert key not in self.particulator.dynamics 37 self.particulator.dynamics[key] = dynamic 38 39 def _register_product(self, product, buffer): 40 if product.name in self.particulator.products: 41 raise ValueError(f'product name "{product.name}" already registered') 42 self.particulator.products[product.name] = product.instantiate( 43 builder=self, buffer=buffer 44 ) 45 46 def _resolve_attribute(self, attr_name): 47 if attr_name not in self.req_attr: 48 self.req_attr[attr_name] = get_attribute_class( 49 attr_name, 50 self.particulator.dynamics.keys(), 51 self.formulae, 52 )(self) 53 assert self.req_attr is not None 54 55 def get_attribute(self, attribute_name): 56 """intended for obtaining attribute instances during build() logic, 57 from within register() methods""" 58 self._resolve_attribute(attribute_name) 59 return self.req_attr[attribute_name] 60 61 def request_attribute(self, attribute_name): 62 """can be called either before or during build()""" 63 if self.req_attr_names is not None: 64 self.req_attr_names.append(attribute_name) 65 else: 66 self._resolve_attribute(attribute_name) 67 68 def build( 69 self, 70 attributes: dict, 71 products: tuple = (), 72 int_caster=discretise_multiplicities, 73 ): 74 assert self.particulator.environment is not None 75 76 if "volume" in attributes and "water mass" not in attributes: 77 assert self.particulator.formulae.particle_shape_and_density.__name__ in ( 78 LiquidSpheres.__name__, 79 MixedPhaseSpheres.__name__, 80 ), "implied volume-to-mass conversion is only supported for spherical particles" 81 attributes["water mass"] = ( 82 self.particulator.formulae.particle_shape_and_density.volume_to_mass( 83 attributes.pop("volume") 84 ) 85 ) 86 self.request_attribute("volume") 87 88 if ( 89 "water mass" in attributes 90 and "signed water mass" not in attributes 91 and not self.particulator.formulae.particle_shape_and_density.supports_mixed_phase() 92 ): 93 attributes["signed water mass"] = attributes.pop("water mass") 94 self.request_attribute("water mass") 95 96 self.req_attr = {} 97 for attr_name in self.req_attr_names: 98 self._resolve_attribute(attr_name) 99 self.req_attr_names = None 100 101 for key, dynamic in self.particulator.dynamics.items(): 102 self.particulator.dynamics[key] = dynamic.instantiate(builder=self) 103 104 single_buffer_for_all_products = np.empty(self.particulator.mesh.grid) 105 for product in products: 106 self._register_product(product, single_buffer_for_all_products) 107 108 for attribute in attributes: 109 self.request_attribute(attribute) 110 if "Condensation" in self.particulator.dynamics: 111 self.particulator.condensation_solver = ( 112 self.particulator.backend.make_condensation_solver( 113 self.particulator.dt, 114 self.particulator.mesh.n_cell, 115 **self.condensation_params, 116 ) 117 ) 118 attributes["multiplicity"] = int_caster(attributes["multiplicity"]) 119 if self.particulator.mesh.dimension == 0: 120 attributes["cell id"] = np.zeros_like( 121 attributes["multiplicity"], dtype=np.int64 122 ) 123 self.particulator.attributes = ParticleAttributesFactory.attributes( 124 self.particulator, self.req_attr, attributes 125 ) 126 self.particulator.recalculate_cell_id() 127 128 for key in self.particulator.dynamics: 129 self.particulator.timers[key] = WallTimer() 130 131 if (attributes["multiplicity"] == 0).any(): 132 self.particulator.attributes.healthy = False 133 self.particulator.attributes.sanitize() 134 135 return self.particulator
class
Builder:
20class Builder: 21 def __init__(self, n_sd, backend, environment=None): 22 assert not inspect.isclass(backend) 23 self.formulae = backend.formulae 24 self.particulator = Particulator(n_sd, backend) 25 self.req_attr_names = ["multiplicity", "water mass", "cell id"] 26 self.req_attr = None 27 self.aerosol_radius_threshold = 0 28 self.condensation_params = None 29 self.particulator.environment = environment.instantiate(builder=self) 30 31 def _set_condensation_parameters(self, **kwargs): 32 self.condensation_params = kwargs 33 34 def add_dynamic(self, dynamic): 35 assert self.particulator.environment is not None 36 key = inspect.getmro(type(dynamic))[-2].__name__ 37 assert key not in self.particulator.dynamics 38 self.particulator.dynamics[key] = dynamic 39 40 def _register_product(self, product, buffer): 41 if product.name in self.particulator.products: 42 raise ValueError(f'product name "{product.name}" already registered') 43 self.particulator.products[product.name] = product.instantiate( 44 builder=self, buffer=buffer 45 ) 46 47 def _resolve_attribute(self, attr_name): 48 if attr_name not in self.req_attr: 49 self.req_attr[attr_name] = get_attribute_class( 50 attr_name, 51 self.particulator.dynamics.keys(), 52 self.formulae, 53 )(self) 54 assert self.req_attr is not None 55 56 def get_attribute(self, attribute_name): 57 """intended for obtaining attribute instances during build() logic, 58 from within register() methods""" 59 self._resolve_attribute(attribute_name) 60 return self.req_attr[attribute_name] 61 62 def request_attribute(self, attribute_name): 63 """can be called either before or during build()""" 64 if self.req_attr_names is not None: 65 self.req_attr_names.append(attribute_name) 66 else: 67 self._resolve_attribute(attribute_name) 68 69 def build( 70 self, 71 attributes: dict, 72 products: tuple = (), 73 int_caster=discretise_multiplicities, 74 ): 75 assert self.particulator.environment is not None 76 77 if "volume" in attributes and "water mass" not in attributes: 78 assert self.particulator.formulae.particle_shape_and_density.__name__ in ( 79 LiquidSpheres.__name__, 80 MixedPhaseSpheres.__name__, 81 ), "implied volume-to-mass conversion is only supported for spherical particles" 82 attributes["water mass"] = ( 83 self.particulator.formulae.particle_shape_and_density.volume_to_mass( 84 attributes.pop("volume") 85 ) 86 ) 87 self.request_attribute("volume") 88 89 if ( 90 "water mass" in attributes 91 and "signed water mass" not in attributes 92 and not self.particulator.formulae.particle_shape_and_density.supports_mixed_phase() 93 ): 94 attributes["signed water mass"] = attributes.pop("water mass") 95 self.request_attribute("water mass") 96 97 self.req_attr = {} 98 for attr_name in self.req_attr_names: 99 self._resolve_attribute(attr_name) 100 self.req_attr_names = None 101 102 for key, dynamic in self.particulator.dynamics.items(): 103 self.particulator.dynamics[key] = dynamic.instantiate(builder=self) 104 105 single_buffer_for_all_products = np.empty(self.particulator.mesh.grid) 106 for product in products: 107 self._register_product(product, single_buffer_for_all_products) 108 109 for attribute in attributes: 110 self.request_attribute(attribute) 111 if "Condensation" in self.particulator.dynamics: 112 self.particulator.condensation_solver = ( 113 self.particulator.backend.make_condensation_solver( 114 self.particulator.dt, 115 self.particulator.mesh.n_cell, 116 **self.condensation_params, 117 ) 118 ) 119 attributes["multiplicity"] = int_caster(attributes["multiplicity"]) 120 if self.particulator.mesh.dimension == 0: 121 attributes["cell id"] = np.zeros_like( 122 attributes["multiplicity"], dtype=np.int64 123 ) 124 self.particulator.attributes = ParticleAttributesFactory.attributes( 125 self.particulator, self.req_attr, attributes 126 ) 127 self.particulator.recalculate_cell_id() 128 129 for key in self.particulator.dynamics: 130 self.particulator.timers[key] = WallTimer() 131 132 if (attributes["multiplicity"] == 0).any(): 133 self.particulator.attributes.healthy = False 134 self.particulator.attributes.sanitize() 135 136 return self.particulator
Builder(n_sd, backend, environment=None)
21 def __init__(self, n_sd, backend, environment=None): 22 assert not inspect.isclass(backend) 23 self.formulae = backend.formulae 24 self.particulator = Particulator(n_sd, backend) 25 self.req_attr_names = ["multiplicity", "water mass", "cell id"] 26 self.req_attr = None 27 self.aerosol_radius_threshold = 0 28 self.condensation_params = None 29 self.particulator.environment = environment.instantiate(builder=self)
def
get_attribute(self, attribute_name):
56 def get_attribute(self, attribute_name): 57 """intended for obtaining attribute instances during build() logic, 58 from within register() methods""" 59 self._resolve_attribute(attribute_name) 60 return self.req_attr[attribute_name]
intended for obtaining attribute instances during build() logic, from within register() methods
def
request_attribute(self, attribute_name):
62 def request_attribute(self, attribute_name): 63 """can be called either before or during build()""" 64 if self.req_attr_names is not None: 65 self.req_attr_names.append(attribute_name) 66 else: 67 self._resolve_attribute(attribute_name)
can be called either before or during build()
def
build( self, attributes: dict, products: tuple = (), int_caster=<function discretise_multiplicities>):
69 def build( 70 self, 71 attributes: dict, 72 products: tuple = (), 73 int_caster=discretise_multiplicities, 74 ): 75 assert self.particulator.environment is not None 76 77 if "volume" in attributes and "water mass" not in attributes: 78 assert self.particulator.formulae.particle_shape_and_density.__name__ in ( 79 LiquidSpheres.__name__, 80 MixedPhaseSpheres.__name__, 81 ), "implied volume-to-mass conversion is only supported for spherical particles" 82 attributes["water mass"] = ( 83 self.particulator.formulae.particle_shape_and_density.volume_to_mass( 84 attributes.pop("volume") 85 ) 86 ) 87 self.request_attribute("volume") 88 89 if ( 90 "water mass" in attributes 91 and "signed water mass" not in attributes 92 and not self.particulator.formulae.particle_shape_and_density.supports_mixed_phase() 93 ): 94 attributes["signed water mass"] = attributes.pop("water mass") 95 self.request_attribute("water mass") 96 97 self.req_attr = {} 98 for attr_name in self.req_attr_names: 99 self._resolve_attribute(attr_name) 100 self.req_attr_names = None 101 102 for key, dynamic in self.particulator.dynamics.items(): 103 self.particulator.dynamics[key] = dynamic.instantiate(builder=self) 104 105 single_buffer_for_all_products = np.empty(self.particulator.mesh.grid) 106 for product in products: 107 self._register_product(product, single_buffer_for_all_products) 108 109 for attribute in attributes: 110 self.request_attribute(attribute) 111 if "Condensation" in self.particulator.dynamics: 112 self.particulator.condensation_solver = ( 113 self.particulator.backend.make_condensation_solver( 114 self.particulator.dt, 115 self.particulator.mesh.n_cell, 116 **self.condensation_params, 117 ) 118 ) 119 attributes["multiplicity"] = int_caster(attributes["multiplicity"]) 120 if self.particulator.mesh.dimension == 0: 121 attributes["cell id"] = np.zeros_like( 122 attributes["multiplicity"], dtype=np.int64 123 ) 124 self.particulator.attributes = ParticleAttributesFactory.attributes( 125 self.particulator, self.req_attr, attributes 126 ) 127 self.particulator.recalculate_cell_id() 128 129 for key in self.particulator.dynamics: 130 self.particulator.timers[key] = WallTimer() 131 132 if (attributes["multiplicity"] == 0).any(): 133 self.particulator.attributes.healthy = False 134 self.particulator.attributes.sanitize() 135 136 return self.particulator