epyt-flow 0.10.0__py3-none-any.whl → 0.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1992,8 +1992,24 @@ class SensorConfig(JsonSerializable):
1992
1992
  bulk_species_link_concentrations: np.ndarray,
1993
1993
  surface_species_concentrations: np.ndarray) -> np.ndarray:
1994
1994
  """
1995
- Applies the sensor configuration to a set of raw simulation results --
1996
- i.e. computes the sensor readings as an array.
1995
+ Applies the sensor configuration to a set of raw simulation results -- i.e. computes
1996
+ the sensor readings as an array.
1997
+
1998
+ Columns (i.e. sensor readings) are ordered as follows:
1999
+
2000
+ 1. Pressures
2001
+ 2. Flows
2002
+ 3. Demands
2003
+ 4. Nodes quality
2004
+ 5. Links quality
2005
+ 6. Valve state
2006
+ 7. Pumps state
2007
+ 8. Pumps efficiency
2008
+ 9. Pumps energy consumption
2009
+ 10. Tanks volume
2010
+ 11. Surface species concentrations
2011
+ 12. Bulk species nodes concentrations
2012
+ 13. Bulk species links concentrations
1997
2013
 
1998
2014
  Parameters
1999
2015
  ----------
epyt_flow/topology.py CHANGED
@@ -653,6 +653,22 @@ class NetworkTopology(nx.Graph, JsonSerializable):
653
653
 
654
654
  return bsr_array((np.ones(len(row)), (row, col)), shape=(n_nodes, n_nodes))
655
655
 
656
+ def get_adj_list(self) -> dict[str, list[str]]:
657
+ """
658
+ Returns the connectivity of the nodes (node IDs) as an adjacency list.
659
+
660
+ Returns
661
+ -------
662
+ `dict[str, list[str]]`
663
+ Adjacency list as a dictionary.
664
+ """
665
+ adj_list = {}
666
+
667
+ for node_id in self.get_all_nodes():
668
+ adj_list[node_id] = self.get_neighbors(node_id)
669
+
670
+ return adj_list
671
+
656
672
  def get_neighbors(self, node_id: str) -> list[str]:
657
673
  """
658
674
  Gets all neighboring nodes of a given node.
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Module provides a class for implementing model uncertainty.
3
3
  """
4
+ from typing import Optional
4
5
  from copy import deepcopy
5
6
  import warnings
6
7
  import epyt
@@ -114,67 +115,31 @@ class ModelUncertainty(JsonSerializable):
114
115
  None, in the case of no uncertainty.
115
116
 
116
117
  The default is None.
118
+ seed : `int`, optional
119
+ Seed for the random number generator.
120
+
121
+ Thed default is None.
117
122
  """
118
- def __init__(self, pipe_length_uncertainty: Uncertainty = None,
119
- pipe_roughness_uncertainty: Uncertainty = None,
120
- pipe_diameter_uncertainty: Uncertainty = None,
121
- base_demand_uncertainty: Uncertainty = None,
122
- demand_pattern_uncertainty: Uncertainty = None,
123
- elevation_uncertainty: Uncertainty = None,
124
- constants_uncertainty: Uncertainty = None,
125
- parameters_uncertainty: Uncertainty = None,
126
- global_pipe_length_uncertainty: Uncertainty = None,
127
- global_pipe_roughness_uncertainty: Uncertainty = None,
128
- global_pipe_diameter_uncertainty: Uncertainty = None,
129
- global_base_demand_uncertainty: Uncertainty = None,
130
- global_demand_pattern_uncertainty: Uncertainty = None,
131
- global_elevation_uncertainty: Uncertainty = None,
132
- global_constants_uncertainty: Uncertainty = None,
133
- global_parameters_uncertainty: Uncertainty = None,
134
- local_pipe_length_uncertainty: dict[str, Uncertainty] = None,
135
- local_pipe_roughness_uncertainty: dict[str, Uncertainty] = None,
136
- local_pipe_diameter_uncertainty: dict[str, Uncertainty] = None,
137
- local_base_demand_uncertainty: dict[str, Uncertainty] = None,
138
- local_demand_pattern_uncertainty: dict[str, Uncertainty] = None,
139
- local_elevation_uncertainty: dict[str, Uncertainty] = None,
140
- local_constants_uncertainty: dict[str, Uncertainty] = None,
141
- local_parameters_uncertainty: dict[str, int, Uncertainty] = None,
142
- local_patterns_uncertainty: dict[str, Uncertainty] = None,
143
- local_msx_patterns_uncertainty: dict[str, Uncertainty] = None,
123
+ def __init__(self, global_pipe_length_uncertainty: Optional[Uncertainty] = None,
124
+ global_pipe_roughness_uncertainty: Optional[Uncertainty] = None,
125
+ global_pipe_diameter_uncertainty: Optional[Uncertainty] = None,
126
+ global_base_demand_uncertainty: Optional[Uncertainty] = None,
127
+ global_demand_pattern_uncertainty: Optional[Uncertainty] = None,
128
+ global_elevation_uncertainty: Optional[Uncertainty] = None,
129
+ global_constants_uncertainty: Optional[Uncertainty] = None,
130
+ global_parameters_uncertainty: Optional[Uncertainty] = None,
131
+ local_pipe_length_uncertainty: Optional[dict[str, Uncertainty]] = None,
132
+ local_pipe_roughness_uncertainty: Optional[dict[str, Uncertainty]] = None,
133
+ local_pipe_diameter_uncertainty: Optional[dict[str, Uncertainty]] = None,
134
+ local_base_demand_uncertainty: Optional[dict[str, Uncertainty]] = None,
135
+ local_demand_pattern_uncertainty: Optional[dict[str, Uncertainty]] = None,
136
+ local_elevation_uncertainty: Optional[dict[str, Uncertainty]] = None,
137
+ local_constants_uncertainty: Optional[dict[str, Uncertainty]] = None,
138
+ local_parameters_uncertainty: Optional[dict[str, int, Uncertainty]] = None,
139
+ local_patterns_uncertainty: Optional[dict[str, Uncertainty]] = None,
140
+ local_msx_patterns_uncertainty: Optional[dict[str, Uncertainty]] = None,
141
+ seed: Optional[int] = None,
144
142
  **kwds):
145
- if pipe_length_uncertainty is not None:
146
- global_pipe_diameter_uncertainty = pipe_length_uncertainty
147
- warnings.warn("'pipe_length_uncertainty' is deprecated and " +
148
- "will be removed in future releases")
149
- if pipe_roughness_uncertainty is not None:
150
- global_pipe_roughness_uncertainty = pipe_roughness_uncertainty
151
- warnings.warn("'pipe_roughness_uncertainty' is deprecated and " +
152
- "will be removed in future releases")
153
- if pipe_diameter_uncertainty is not None:
154
- global_pipe_diameter_uncertainty = pipe_diameter_uncertainty
155
- warnings.warn("'pipe_diameter_uncertainty' is deprecated and " +
156
- "will be removed in future releases")
157
- if base_demand_uncertainty is not None:
158
- global_base_demand_uncertainty = base_demand_uncertainty
159
- warnings.warn("'base_demand_uncertainty' is deprecated and " +
160
- "will be removed in future releases")
161
- if demand_pattern_uncertainty is not None:
162
- global_demand_pattern_uncertainty = demand_pattern_uncertainty
163
- warnings.warn("'demand_pattern_uncertainty' is deprecated and " +
164
- "will be removed in future releases")
165
- if elevation_uncertainty is not None:
166
- global_elevation_uncertainty = elevation_uncertainty
167
- warnings.warn("'elevation_uncertainty' is deprecated and " +
168
- "will be removed in future releases")
169
- if constants_uncertainty is not None:
170
- global_constants_uncertainty = constants_uncertainty
171
- warnings.warn("'constants_uncertainty' is deprecated and " +
172
- "will be removed in future releases")
173
- if parameters_uncertainty is not None:
174
- global_parameters_uncertainty = parameters_uncertainty
175
- warnings.warn("'parameters_uncertainty' is deprecated and " +
176
- "will be removed in future releases")
177
-
178
143
  if global_pipe_length_uncertainty is not None:
179
144
  if not isinstance(global_pipe_length_uncertainty, Uncertainty):
180
145
  raise TypeError("'global_pipe_length_uncertainty' must be an instance of " +
@@ -337,9 +302,22 @@ class ModelUncertainty(JsonSerializable):
337
302
  self.__local_parameters = local_parameters_uncertainty
338
303
  self.__local_patterns = local_patterns_uncertainty
339
304
  self.__local_msx_patterns = local_msx_patterns_uncertainty
305
+ self.__seed = seed
340
306
 
341
307
  super().__init__(**kwds)
342
308
 
309
+ @property
310
+ def seed(self) -> int:
311
+ """
312
+ Returns the seed used for the random number generator.
313
+
314
+ Returns
315
+ -------
316
+ `int`
317
+ Seed for the random number generator.
318
+ """
319
+ return self.__seed
320
+
343
321
  @property
344
322
  def global_pipe_length(self) -> Uncertainty:
345
323
  """
@@ -574,7 +552,8 @@ class ModelUncertainty(JsonSerializable):
574
552
  "local_constants_uncertainty": self.__local_constants,
575
553
  "local_parameters_uncertainty": self.__local_parameters,
576
554
  "local_patterns_uncertainty": self.__local_patterns,
577
- "local_msx_patterns_uncertainty": self.__local_msx_patterns}
555
+ "local_msx_patterns_uncertainty": self.__local_msx_patterns,
556
+ "seed": self.__seed}
578
557
 
579
558
  return super().get_attributes() | attribs
580
559
 
@@ -600,7 +579,8 @@ class ModelUncertainty(JsonSerializable):
600
579
  and self.__local_parameters == other.local_parameters \
601
580
  and self.__local_constants == other.local_constants \
602
581
  and self.__local_patterns == other.local_patterns \
603
- and self.__local_msx_patterns == other.local_msx_patterns
582
+ and self.__local_msx_patterns == other.local_msx_patterns \
583
+ and self.__seed == other.seed
604
584
 
605
585
  def __str__(self) -> str:
606
586
  return f"global_pipe_length: {self.__global_pipe_length} " +\
@@ -620,7 +600,7 @@ class ModelUncertainty(JsonSerializable):
620
600
  f"local_constants: {self.__local_constants} " + \
621
601
  f"local_parameters: {self.__local_parameters} " + \
622
602
  f"local_patterns: {self.__local_patterns} " + \
623
- f"local_msx_patterns: {self.__local_msx_patterns}"
603
+ f"local_msx_patterns: {self.__local_msx_patterns} + seed: {self.__seed}"
624
604
 
625
605
  def apply(self, epanet_api: epyt.epanet) -> None:
626
606
  """
@@ -631,12 +611,18 @@ class ModelUncertainty(JsonSerializable):
631
611
  epanet_api : `epyt.epanet <https://epanet-python-toolkit-epyt.readthedocs.io/en/stable/api.html#epyt.epanet.epanet>`_
632
612
  Interface to EPANET and EPANET-MSX.
633
613
  """
614
+ np_rand_gen = np.random.default_rng(seed=self.__seed)
615
+
634
616
  if self.__global_pipe_length is not None:
617
+ self.__global_pipe_length.set_random_generator(np_rand_gen)
618
+
635
619
  link_length = epanet_api.getLinkLength()
636
620
  link_length = self.__global_pipe_length.apply_batch(link_length)
637
621
  epanet_api.setLinkLength(link_length)
638
622
 
639
623
  if self.__local_pipe_length is not None:
624
+ self.__local_pipe_length.set_random_generator(np_rand_gen)
625
+
640
626
  for pipe_id, uncertainty in self.__local_pipe_length.items():
641
627
  link_idx = epanet_api.getLinkIndex(pipe_id)
642
628
  link_length = epanet_api.getLinkLength(link_idx)
@@ -644,11 +630,15 @@ class ModelUncertainty(JsonSerializable):
644
630
  epanet_api.setLinkLength(link_idx, link_length)
645
631
 
646
632
  if self.__global_pipe_diameter is not None:
633
+ self.__global_pipe_diameter.set_random_generator(np_rand_gen)
634
+
647
635
  link_diameters = epanet_api.getLinkDiameter()
648
636
  link_diameters = self.__global_pipe_diameter.apply_batch(link_diameters)
649
637
  epanet_api.setLinkDiameter(link_diameters)
650
638
 
651
639
  if self.__local_pipe_diameter is not None:
640
+ self.__local_pipe_diameter.set_random_generator(np_rand_gen)
641
+
652
642
  for pipe_id, uncertainty in self.__local_pipe_diameter.items():
653
643
  link_idx = epanet_api.getLinkIndex(pipe_id)
654
644
  link_diameter = epanet_api.getLinkDiameter(link_idx)
@@ -656,11 +646,15 @@ class ModelUncertainty(JsonSerializable):
656
646
  epanet_api.setLinkDiameter(link_idx, link_diameter)
657
647
 
658
648
  if self.__global_pipe_roughness is not None:
649
+ self.__global_pipe_roughness.set_random_generator(np_rand_gen)
650
+
659
651
  coeffs = epanet_api.getLinkRoughnessCoeff()
660
652
  coeffs = self.__global_pipe_roughness.apply_batch(coeffs)
661
653
  epanet_api.setLinkRoughnessCoeff(coeffs)
662
654
 
663
655
  if self.__local_pipe_roughness is not None:
656
+ self.__local_pipe_roughness.set_random_generator(np_rand_gen)
657
+
664
658
  for pipe_id, uncertainty in self.__local_pipe_roughness.items():
665
659
  link_idx = epanet_api.getLinkIndex(pipe_id)
666
660
  link_roughness_coeff = epanet_api.getLinkRoughnessCoeff(link_idx)
@@ -668,6 +662,8 @@ class ModelUncertainty(JsonSerializable):
668
662
  epanet_api.setLinkRoughnessCoeff(link_idx, link_roughness_coeff)
669
663
 
670
664
  if self.__global_base_demand is not None:
665
+ self.__global_base_demand.set_random_generator(np_rand_gen)
666
+
671
667
  all_nodes_idx = epanet_api.getNodeIndex()
672
668
  for node_idx in all_nodes_idx:
673
669
  n_demand_categories = epanet_api.getNodeDemandCategoriesNumber(node_idx)
@@ -677,6 +673,8 @@ class ModelUncertainty(JsonSerializable):
677
673
  epanet_api.setNodeBaseDemands(node_idx, demand_category + 1, base_demand)
678
674
 
679
675
  if self.__local_base_demand is not None:
676
+ self.__local_base_demand.set_random_generator(np_rand_gen)
677
+
680
678
  for node_id, uncertainty in self.__local_base_demand.items():
681
679
  node_idx = epanet_api.getNodeIndex(node_id)
682
680
  n_demand_categories = epanet_api.getNodeDemandCategoriesNumber(node_idx)
@@ -686,6 +684,8 @@ class ModelUncertainty(JsonSerializable):
686
684
  epanet_api.setNodeBaseDemands(node_idx, demand_category + 1, base_demand)
687
685
 
688
686
  if self.__global_demand_pattern is not None:
687
+ self.__global_demand_pattern.set_random_generator(np_rand_gen)
688
+
689
689
  demand_patterns_idx = epanet_api.getNodeDemandPatternIndex()
690
690
  demand_patterns_id = np.unique([demand_patterns_idx[k]
691
691
  for k in demand_patterns_idx.keys()])
@@ -699,6 +699,8 @@ class ModelUncertainty(JsonSerializable):
699
699
  epanet_api.setPatternValue(pattern_id, t+1, v_)
700
700
 
701
701
  if self.__local_demand_pattern is not None:
702
+ self.__local_demand_pattern.set_random_generator(np_rand_gen)
703
+
702
704
  patterns_id = epanet_api.getPatternNameID()
703
705
  paterns_idx = epanet_api.getPatternIndex()
704
706
 
@@ -711,11 +713,15 @@ class ModelUncertainty(JsonSerializable):
711
713
  epanet_api.setPatternValue(pattern_idx, t+1, v_)
712
714
 
713
715
  if self.__global_elevation is not None:
716
+ self.__global_elevation.set_random_generator(np_rand_gen)
717
+
714
718
  elevations = epanet_api.getNodeElevations()
715
719
  elevations = self.__global_elevation.apply_batch(elevations)
716
720
  epanet_api.setNodeElevations(elevations)
717
721
 
718
722
  if self.__local_elevation is not None:
723
+ self.__local_elevation.set_random_generator(np_rand_gen)
724
+
719
725
  for node_id, uncertainty in self.__local_elevation.items():
720
726
  node_idx = epanet_api.getNodeIndex(node_id)
721
727
  elevation = epanet_api.getNodeElevations(node_idx)
@@ -723,6 +729,8 @@ class ModelUncertainty(JsonSerializable):
723
729
  epanet_api.setNodeElevations(node_idx, elevation)
724
730
 
725
731
  if self.__local_patterns is not None:
732
+ self.__local_patterns.set_random_generator(np_rand_gen)
733
+
726
734
  for pattern_id, uncertainty in self.__local_patterns.items():
727
735
  pattern_idx = epanet_api.getPatternIndex(pattern_id)
728
736
  pattern_length = epanet_api.getPatternLengths(pattern_idx)
@@ -733,11 +741,15 @@ class ModelUncertainty(JsonSerializable):
733
741
 
734
742
  if epanet_api.MSXFile is not None:
735
743
  if self.__global_constants is not None:
744
+ self.__global_constants.set_random_generator(np_rand_gen)
745
+
736
746
  constants = np.array(epanet_api.getMSXConstantsValue())
737
747
  constants = self.__global_constants.apply_batch(constants)
738
748
  epanet_api.setMSXConstantsValue(constants)
739
749
 
740
750
  if self.__local_constants:
751
+ self.__local_constants.set_random_generator(np_rand_gen)
752
+
741
753
  for constant_id, uncertainty in self.__local_constants.items():
742
754
  idx = epanet_api.MSXgetindex(ToolkitConstants.MSX_CONSTANT, constant_id)
743
755
  constant = epanet_api.msx.MSXgetconstant(idx)
@@ -745,6 +757,8 @@ class ModelUncertainty(JsonSerializable):
745
757
  epanet_api.msx.MSXsetconstant(idx, constant)
746
758
 
747
759
  if self.__global_parameters is not None:
760
+ self.__global_parameters.set_random_generator(np_rand_gen)
761
+
748
762
  parameters_pipes = epanet_api.getMSXParametersPipesValue()
749
763
  for i, pipe_idx in enumerate(epanet_api.getLinkPipeIndex()):
750
764
  if len(parameters_pipes[i]) == 0:
@@ -764,6 +778,8 @@ class ModelUncertainty(JsonSerializable):
764
778
  epanet_api.setMSXParametersTanksValue(tank_idx, parameters_tanks_val)
765
779
 
766
780
  if self.__local_parameters is not None:
781
+ self.__local_parameters.set_random_generator(np_rand_gen)
782
+
767
783
  for (param_id, item_type, item_id), uncertainty in self.__local_parameters.items():
768
784
  idx, = epanet_api.getMSXParametersIndex([param_id])
769
785
 
@@ -780,6 +796,8 @@ class ModelUncertainty(JsonSerializable):
780
796
  epanet_api.msx.MSXsetparameter(item_type, item_idx, idx, parameter)
781
797
 
782
798
  if self.__local_msx_patterns is not None:
799
+ self.__local_msx_patterns.set_random_generator(np_rand_gen)
800
+
783
801
  for pattern_id, uncertainty in self.__local_msx_patterns.items():
784
802
  pattern_idx, = epanet_api.getMSXPatternsIndex([pattern_id])
785
803
  pattern = epanet_api.getMSXConstantsValue([pattern_idx])
@@ -1,10 +1,11 @@
1
1
  """
2
2
  Module provides a class for implementing sensor noise (e.g. uncertainty in sensor readings).
3
3
  """
4
+ from typing import Optional, Callable
4
5
  from copy import deepcopy
5
6
  import warnings
6
- from typing import Callable
7
7
  import numpy
8
+ from numpy.random import default_rng
8
9
 
9
10
  from .uncertainties import Uncertainty
10
11
  from ..serialization import serializable, JsonSerializable, SENSOR_NOISE_ID
@@ -25,11 +26,16 @@ class SensorNoise(JsonSerializable):
25
26
  Local (i.e. sensor specific) uncertainties.
26
27
  If None, no local sensor uncertainties are applied.
27
28
 
29
+ The default is None.
30
+ seed : `int`, optional
31
+ Seed for the random number generator.
32
+
28
33
  The default is None.
29
34
  """
30
- def __init__(self, uncertainty: Uncertainty = None,
31
- global_uncertainty: Uncertainty = None,
32
- local_uncertainties: dict[int, str, Uncertainty] = None,
35
+ def __init__(self, uncertainty: Optional[Uncertainty] = None,
36
+ global_uncertainty: Optional[Uncertainty] = None,
37
+ local_uncertainties: Optional[dict[int, str, Uncertainty]] = None,
38
+ seed: Optional[int] = None,
33
39
  **kwds):
34
40
  if uncertainty is not None:
35
41
  global_uncertainty = uncertainty
@@ -53,6 +59,7 @@ class SensorNoise(JsonSerializable):
53
59
 
54
60
  self.__global_uncertainty = global_uncertainty
55
61
  self.__local_uncertainties = local_uncertainties
62
+ self.__np_rand_gen = default_rng(seed)
56
63
 
57
64
  super().__init__(**kwds)
58
65
 
@@ -118,6 +125,8 @@ class SensorNoise(JsonSerializable):
118
125
  if self.__local_uncertainties is None:
119
126
  return sensor_readings
120
127
  else:
128
+ self.__local_uncertainties.set_random_generator(self.__np_rand_gen)
129
+
121
130
  for (sensor_type, sensor_id), uncertainty in map_sensor_to_idx.items():
122
131
  idx = map_sensor_to_idx(sensor_type, sensor_id)
123
132
  sensor_readings[:, idx] = uncertainty.apply_batch(sensor_readings[:, idx])
@@ -145,4 +154,6 @@ class SensorNoise(JsonSerializable):
145
154
  if self.__global_uncertainty is None:
146
155
  return sensor_readings
147
156
  else:
157
+ self.__global_uncertainty.set_random_generator(self.__np_rand_gen)
158
+
148
159
  return self.__global_uncertainty.apply_batch(sensor_readings)
@@ -2,7 +2,9 @@
2
2
  Module provides classes for implementing different types of uncertainties.
3
3
  """
4
4
  from abc import ABC, abstractmethod
5
+ from copy import deepcopy
5
6
  import numpy as np
7
+ from numpy.random import Generator, default_rng
6
8
 
7
9
  from .utils import generate_deep_random_gaussian_noise, create_deep_random_pattern
8
10
  from ..serialization import serializable, JsonSerializable, ABSOLUTE_GAUSSIAN_UNCERTAINTY_ID, \
@@ -34,6 +36,8 @@ class Uncertainty(ABC):
34
36
  self.__min_value = min_value
35
37
  self.__max_value = max_value
36
38
 
39
+ self._random_generator = default_rng()
40
+
37
41
  @property
38
42
  def min_value(self) -> float:
39
43
  """
@@ -58,6 +62,32 @@ class Uncertainty(ABC):
58
62
  """
59
63
  return self.__max_value
60
64
 
65
+ @property
66
+ def random_generator(self) -> Generator:
67
+ """
68
+ Returns the random number generator that is used for generating the uncertainties.
69
+
70
+ Returns
71
+ -------
72
+ `numpy.random.Generator <https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator>`_
73
+ The random number generator.
74
+ """
75
+ return deepcopy(self._random_generator)
76
+
77
+ def set_random_generator(self, np_rand_generator: Generator) -> None:
78
+ """
79
+ Sets the random number generator that is going to be used for generating the uncertainties.
80
+
81
+ Parameters
82
+ ----------
83
+ np_rand_generator : `numpy.random.Generator <https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator>`_, optional
84
+ The random number generator.
85
+
86
+ The default is the default BitGenerator (PCG64) as constructed by
87
+ `numpy.random.default_rng() <https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.default_rng>`_.
88
+ """
89
+ self._random_generator = np_rand_generator
90
+
61
91
  def get_attributes(self) -> dict:
62
92
  """
63
93
  Gets all attributes to be serialized -- these attributes are passed to the
@@ -75,7 +105,8 @@ class Uncertainty(ABC):
75
105
  raise TypeError("Can not compare 'Uncertainty' instance " +
76
106
  f"with '{type(other)}' instance")
77
107
 
78
- return self.__min_value == other.min_value and self.__max_value == other.max_value
108
+ return self.__min_value == other.min_value and self.__max_value == other.max_value and \
109
+ self._random_generator == other.random_generator
79
110
 
80
111
  def __str__(self) -> str:
81
112
  return f"min_value: {self.__min_value} max_value: {self.__max_value}"
@@ -159,8 +190,8 @@ class GaussianUncertainty(Uncertainty):
159
190
  def __init__(self, mean: float = None, scale: float = None, **kwds):
160
191
  super().__init__(**kwds)
161
192
 
162
- self.__mean = np.random.rand() if mean is None else mean
163
- self.__scale = np.random.rand() if scale is None else scale
193
+ self._mean = mean
194
+ self._scale = scale
164
195
 
165
196
  @property
166
197
  def mean(self) -> float:
@@ -172,7 +203,7 @@ class GaussianUncertainty(Uncertainty):
172
203
  `float`
173
204
  Mean of the Gaussian noise.
174
205
  """
175
- return self.__mean
206
+ return self._mean
176
207
 
177
208
  @property
178
209
  def scale(self) -> float:
@@ -184,20 +215,20 @@ class GaussianUncertainty(Uncertainty):
184
215
  `float`
185
216
  Scale (i.e. standard deviation) of the Gaussian noise.
186
217
  """
187
- return self.__scale
218
+ return self._scale
188
219
 
189
220
  def get_attributes(self) -> dict:
190
- return super().get_attributes() | {"mean": self.__mean, "scale": self.__scale}
221
+ return super().get_attributes() | {"mean": self._mean, "scale": self._scale}
191
222
 
192
223
  def __eq__(self, other) -> bool:
193
224
  if not isinstance(other, GaussianUncertainty):
194
225
  raise TypeError("Can not compare 'GaussianUncertainty' instance " +
195
226
  f"with '{type(other)}' instance")
196
227
 
197
- return super().__eq__(other) and self.__mean == other.mean and self.__scale == other.scale
228
+ return super().__eq__(other) and self._mean == other.mean and self._scale == other.scale
198
229
 
199
230
  def __str__(self) -> str:
200
- return super().__str__() + f" mean: {self.__mean} scale: {self.__scale}"
231
+ return super().__str__() + f" mean: {self._mean} scale: {self._scale}"
201
232
 
202
233
 
203
234
  @serializable(ABSOLUTE_GAUSSIAN_UNCERTAINTY_ID, ".epytflow_uncertainty_absolute_gaussian")
@@ -206,7 +237,10 @@ class AbsoluteGaussianUncertainty(GaussianUncertainty, JsonSerializable):
206
237
  Class implementing absolute Gaussian uncertainty -- i.e. Gaussian noise is added to the data.
207
238
  """
208
239
  def apply(self, data: float) -> float:
209
- data += np.random.normal(loc=self.mean, scale=self.scale)
240
+ self._mean = self._random_generator.rand() if self._mean is None else self._mean
241
+ self._scale = self._random_generator.rand() if self._scale is None else self._scale
242
+
243
+ data += self._random_generator.normal(loc=self._mean, scale=self._scale)
210
244
 
211
245
  return self.clip(data)
212
246
 
@@ -230,7 +264,9 @@ class RelativeGaussianUncertainty(GaussianUncertainty, JsonSerializable):
230
264
  super().__init__(mean=0., scale=scale, **kwds)
231
265
 
232
266
  def apply(self, data: float) -> float:
233
- data += np.random.normal(loc=0, scale=self.scale)
267
+ self._scale = self._random_generator.rand() if self._scale is None else self._scale
268
+
269
+ data += self._random_generator.normal(loc=0, scale=self._scale)
234
270
 
235
271
  return self.clip(data)
236
272
 
@@ -300,7 +336,7 @@ class AbsoluteUniformUncertainty(UniformUncertainty, JsonSerializable):
300
336
  Class implementing absolute uniform uncertainty -- i.e. uniform noise is added to the data.
301
337
  """
302
338
  def apply(self, data: float) -> float:
303
- data += np.random.uniform(low=self.low, high=self.high)
339
+ data += self._random_generator.uniform(low=self.low, high=self.high)
304
340
 
305
341
  return self.clip(data)
306
342
 
@@ -311,7 +347,7 @@ class RelativeUniformUncertainty(UniformUncertainty, JsonSerializable):
311
347
  Class implementing relative uniform uncertainty -- i.e. data is multiplied by uniform noise.
312
348
  """
313
349
  def apply(self, data: float) -> float:
314
- data *= np.random.uniform(low=self.low, high=self.high)
350
+ data *= self._random_generator.uniform(low=self.low, high=self.high)
315
351
 
316
352
  return self.clip(data)
317
353
 
@@ -345,7 +381,7 @@ class PercentageDeviationUncertainty(UniformUncertainty, JsonSerializable):
345
381
  return super().get_attributes() | {"deviation_percentage": self.high - 1.}
346
382
 
347
383
  def apply(self, data: float) -> float:
348
- data *= np.random.uniform(low=self.low, high=self.high)
384
+ data *= self._random_generator.uniform(low=self.low, high=self.high)
349
385
 
350
386
  return self.clip(data)
351
387
 
@@ -361,13 +397,18 @@ class DeepUniformUncertainty(Uncertainty):
361
397
 
362
398
  def __create_uncertainties(self, n_samples: int = 500):
363
399
  self._uncertainties_idx = 0
364
- rand_low = create_deep_random_pattern(n_samples)
365
- rand_high = create_deep_random_pattern(n_samples)
400
+ rand_low = create_deep_random_pattern(n_samples, np_rand_gen=self._random_generator)
401
+ rand_high = create_deep_random_pattern(n_samples, np_rand_gen=self._random_generator)
366
402
  rand_low = np.minimum(rand_low, rand_high)
367
403
  rand_high = np.maximum(rand_low, rand_high)
368
- self._uncertainties = [np.random.uniform(low, high)
404
+ self._uncertainties = [self._random_generator.uniform(low, high)
369
405
  for low, high in zip(rand_low, rand_high)]
370
406
 
407
+ def set_random_generator(self, np_rand_generator) -> None:
408
+ super().set_random_generator(np_rand_generator)
409
+
410
+ self.__create_uncertainties()
411
+
371
412
  @abstractmethod
372
413
  def apply(self, data: float) -> float:
373
414
  self._uncertainties_idx += 1
@@ -422,7 +463,13 @@ class DeepGaussianUncertainty(Uncertainty, JsonSerializable):
422
463
 
423
464
  def __create_uncertainties(self, n_samples: int = 500) -> None:
424
465
  self._uncertainties_idx = 0
425
- self._uncertainties = generate_deep_random_gaussian_noise(n_samples, self.__mean)
466
+ self._uncertainties = generate_deep_random_gaussian_noise(n_samples, self.__mean,
467
+ np_rand_gen=self._random_generator)
468
+
469
+ def set_random_generator(self, np_rand_generator) -> None:
470
+ super().set_random_generator(np_rand_generator)
471
+
472
+ self.__create_uncertainties()
426
473
 
427
474
  @abstractmethod
428
475
  def apply(self, data: float) -> float:
@@ -505,6 +552,11 @@ class DeepUncertainty(Uncertainty):
505
552
  """
506
553
  return self.__max_noise_value
507
554
 
555
+ def set_random_generator(self, np_rand_generator) -> None:
556
+ super().set_random_generator(np_rand_generator)
557
+
558
+ self.__create_uncertainties()
559
+
508
560
  def get_attributes(self) -> dict:
509
561
  return super().get_attributes() | {"min_noise_value": self.__min_noise_value,
510
562
  "max_noise_value": self.__max_noise_value}
@@ -528,7 +580,8 @@ class DeepUncertainty(Uncertainty):
528
580
 
529
581
  self._uncertainties_idx = 0
530
582
  self._uncertainties = create_deep_random_pattern(n_samples, self.__min_noise_value,
531
- self.__max_noise_value, init_value)
583
+ self.__max_noise_value, init_value,
584
+ np_rand_gen=self._random_generator)
532
585
 
533
586
  @abstractmethod
534
587
  def apply(self, data: float) -> float: