simcats 1.1.0__py3-none-any.whl → 2.0.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.
Files changed (42) hide show
  1. simcats/__init__.py +4 -3
  2. simcats/_default_configs.py +129 -13
  3. simcats/_simulation.py +451 -69
  4. simcats/config_samplers/_GaAs_v1_random_variations_v3_config_sampler.py +1059 -0
  5. simcats/config_samplers/__init__.py +9 -0
  6. simcats/distortions/_distortion_interfaces.py +1 -1
  7. simcats/distortions/_dot_jumps.py +8 -6
  8. simcats/distortions/_random_telegraph_noise.py +4 -4
  9. simcats/distortions/_transition_blurring.py +5 -5
  10. simcats/distortions/_white_noise.py +2 -2
  11. simcats/ideal_csd/geometric/_generate_lead_transition_mask.py +3 -3
  12. simcats/ideal_csd/geometric/_get_electron_occupation.py +5 -5
  13. simcats/ideal_csd/geometric/_ideal_csd_geometric.py +5 -5
  14. simcats/ideal_csd/geometric/_ideal_csd_geometric_class.py +9 -9
  15. simcats/ideal_csd/geometric/_tct_bezier.py +5 -5
  16. simcats/sensor/__init__.py +10 -6
  17. simcats/sensor/{_generic_sensor.py → _sensor_generic.py} +1 -1
  18. simcats/sensor/_sensor_interface.py +164 -11
  19. simcats/sensor/_sensor_rise_glf.py +229 -0
  20. simcats/sensor/_sensor_scan_sensor_generic.py +929 -0
  21. simcats/sensor/barrier_function/__init__.py +9 -0
  22. simcats/sensor/barrier_function/_barrier_function_glf.py +280 -0
  23. simcats/sensor/barrier_function/_barrier_function_interface.py +43 -0
  24. simcats/sensor/barrier_function/_barrier_function_multi_glf.py +157 -0
  25. simcats/sensor/deformation/__init__.py +9 -0
  26. simcats/sensor/deformation/_sensor_peak_deformation_circle.py +109 -0
  27. simcats/sensor/deformation/_sensor_peak_deformation_interface.py +65 -0
  28. simcats/sensor/deformation/_sensor_peak_deformation_linear.py +77 -0
  29. simcats/support_functions/__init__.py +11 -3
  30. simcats/support_functions/_generalized_logistic_function.py +146 -0
  31. simcats/support_functions/_linear_algebra.py +171 -0
  32. simcats/support_functions/_parameter_sampling.py +108 -19
  33. simcats/support_functions/_pixel_volt_transformation.py +24 -0
  34. simcats/support_functions/_reset_offset_mu_sens.py +43 -0
  35. {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info}/METADATA +93 -29
  36. simcats-2.0.0.dist-info/RECORD +53 -0
  37. {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info}/WHEEL +1 -1
  38. simcats-1.1.0.dist-info/RECORD +0 -37
  39. /simcats/sensor/{_gaussian_sensor_peak.py → _sensor_peak_gaussian.py} +0 -0
  40. /simcats/sensor/{_lorentzian_sensor_peak.py → _sensor_peak_lorentzian.py} +0 -0
  41. {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info/licenses}/LICENSE +0 -0
  42. {simcats-1.1.0.dist-info → simcats-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,9 @@
1
+ """
2
+ Samplers for generating configurations for the Simulation class.
3
+
4
+ @author: f.hader, b.papajewski
5
+ """
6
+
7
+ from simcats.config_samplers._GaAs_v1_random_variations_v3_config_sampler import sample_random_variations_v3_config
8
+
9
+ __all__ = ["sample_random_variations_v3_config"]
@@ -64,7 +64,7 @@ class OccupationDistortionInterface(DistortionInterface):
64
64
  gate.
65
65
  volt_limits_g2 (np.ndarray): Contains the beginning and ending of the swept range for the second (plunger)
66
66
  gate.
67
- generate_csd (Union[Callable, None]): Function which generates data points outside the swept gate range.
67
+ generate_csd (Optional[Callable]): Function which generates data points outside the swept gate range.
68
68
  This is especially required for distortions, which shift the CSD structure. The generated data points
69
69
  also have to contain the distortions, which have already been added to the occupation and
70
70
  lead_transitions before. Default is None.
@@ -4,7 +4,7 @@
4
4
  """
5
5
 
6
6
  import warnings
7
- from typing import Callable, Tuple, Union
7
+ from typing import Callable, Tuple, Union, Optional
8
8
 
9
9
  import numpy as np
10
10
 
@@ -106,7 +106,7 @@ class OccupationDotJumps(OccupationDistortionInterface):
106
106
  self.__rng = rng
107
107
 
108
108
  @property
109
- def activated(self) -> Union[bool, None]:
109
+ def activated(self) -> Optional[bool]:
110
110
  """This is true if the noise was activated during the last call of noise function."""
111
111
  return self.__activated
112
112
 
@@ -139,14 +139,16 @@ class OccupationDotJumps(OccupationDistortionInterface):
139
139
  gate.
140
140
  volt_limits_g2 (np.ndarray): Contains the beginning and ending of the swept range for the second (plunger)
141
141
  gate.
142
- generate_csd (Union[Callable, None]): Function which generates data points outside the swept gate range.
142
+ generate_csd (Optional[Callable]): Function which generates data points outside the swept gate range.
143
143
  This is especially required for distortions, which shift the CSD structure. The generated data points
144
144
  also have to contain the distortions, which have already been added to the occupation and
145
145
  lead_transitions before. Defaults to None.
146
146
  freeze (bool): Indicates if the last used noise should be reused. This is important if there are noise
147
147
  types which need to generate data from outside the current CSD (for example if a part of the structure
148
148
  is shifted). This newly generated data also has to contain the noise which already has been applied to
149
- the CSD before.
149
+ the CSD before. A use case for that is the application of dot jumps in vertical direction after the
150
+ application in horizontal direction. Due to the jumps in vertical direction new data might have to be
151
+ generated with generate_csd. In this data, the horizontal jumps also have to be applied.
150
152
 
151
153
  Returns:
152
154
  Tuple[np.ndarray, np.ndarray]: Occupation numbers and lead transition mask (in our case: total charge
@@ -686,7 +688,7 @@ def dot_jumps_pixelwise(
686
688
  original: np.ndarray,
687
689
  scale: float,
688
690
  lam: float,
689
- noise: Union[np.ndarray, None] = None,
691
+ noise: Optional[np.ndarray] = None,
690
692
  rng: np.random.Generator = np.random.default_rng(),
691
693
  ) -> Tuple[np.ndarray, np.ndarray]:
692
694
  """Adds dot jumps to the original image (pixelwise).
@@ -707,7 +709,7 @@ def dot_jumps_pixelwise(
707
709
  this case, scale specifies the length in pixels, so that a jump can start in the middle of a line and end in
708
710
  the middle of the next line. Given in pixels.
709
711
  lam (float): Lambda for the poisson distribution which specifies the height of the jumps. Given in pixels.
710
- noise (Union[np.ndarray, None]): Noise which was generated with this method for a prior image and should be reapplied for
712
+ noise (Optional[np.ndarray]): Noise which was generated with this method for a prior image and should be reapplied for
711
713
  this image. Default is None.
712
714
  rng (np.random.Generator): The random number generator used for the simulation of random numbers. Default is
713
715
  np.random.default_rng().
@@ -3,7 +3,7 @@
3
3
  @author: s.fleitmann
4
4
  """
5
5
 
6
- from typing import Union
6
+ from typing import Union, Optional
7
7
 
8
8
  import numpy as np
9
9
 
@@ -102,7 +102,7 @@ class RandomTelegraphNoise(DistortionInterface):
102
102
  self.__rng = rng
103
103
 
104
104
  @property
105
- def activated(self) -> Union[bool, None]:
105
+ def activated(self) -> Optional[bool]:
106
106
  """This is true if the noise was activated during the last call of noise function."""
107
107
  return self.__activated
108
108
 
@@ -149,8 +149,8 @@ class RandomTelegraphNoise(DistortionInterface):
149
149
  )
150
150
  else:
151
151
  resolution = (original.shape[0], original.shape[0])
152
- # sweep direction is always the x-axis direction
153
- scale *= resolution[0] / (np.max(volt_limits_g1) - np.min(volt_limits_g1))
152
+ # sweep between starting and ending point
153
+ scale *= resolution[0] / np.maximum(np.max(volt_limits_g1) - np.min(volt_limits_g1), np.max(volt_limits_g2) - np.min(volt_limits_g2))
154
154
 
155
155
  try:
156
156
  std = self.std.sample_parameter()
@@ -3,7 +3,7 @@
3
3
  @author: s.fleitmann
4
4
  """
5
5
 
6
- from typing import Callable, Tuple, Union
6
+ from typing import Callable, Tuple, Union, Optional
7
7
 
8
8
  import numpy as np
9
9
  from scipy.ndimage import gaussian_filter1d
@@ -39,7 +39,7 @@ class OccupationTransitionBlurringFermiDirac(OccupationDistortionInterface):
39
39
  self.__sigma = sigma
40
40
 
41
41
  @property
42
- def latest_sigma(self) -> Union[float, None]:
42
+ def latest_sigma(self) -> Optional[float]:
43
43
  """The sigma that was used for the latest simulation.
44
44
 
45
45
  This is necessary because, depending on the setting, a sampler can be used instead of a fixed sigma.
@@ -75,7 +75,7 @@ class OccupationTransitionBlurringFermiDirac(OccupationDistortionInterface):
75
75
  gate.
76
76
  volt_limits_g2 (np.ndarray): Contains the beginning and ending of the swept range for the second (plunger)
77
77
  gate.
78
- generate_csd (Union[Callable, None]): Function which generates data points outside the swept gate range.
78
+ generate_csd (Optional[Callable]): Function which generates data points outside the swept gate range.
79
79
  This is especially required for distortions, which shift the CSD structure. The generated data points
80
80
  also have to contain the distortions, which have already been added to the occupation and
81
81
  lead_transitions before.
@@ -155,7 +155,7 @@ class OccupationTransitionBlurringGaussian(OccupationDistortionInterface):
155
155
  self.__sigma = sigma
156
156
 
157
157
  @property
158
- def latest_sigma(self) -> Union[float, None]:
158
+ def latest_sigma(self) -> Optional[float]:
159
159
  """The sigma that was used for the latest simulation.
160
160
 
161
161
  This is necessary because, depending on the setting, a sampler can be used instead of a fixed sigma.
@@ -191,7 +191,7 @@ class OccupationTransitionBlurringGaussian(OccupationDistortionInterface):
191
191
  gate.
192
192
  volt_limits_g2 (np.ndarray): Contains the beginning and ending of the swept range for the second (plunger)
193
193
  gate.
194
- generate_csd (Union[Callable, None]): Function which generates data points outside the swept gate range.
194
+ generate_csd (Optional[Callable]): Function which generates data points outside the swept gate range.
195
195
  This is especially required for distortions, which shift the CSD structure. The generated data points
196
196
  also have to contain the distortions, which have already been added to the occupation and
197
197
  lead_transitions before.
@@ -3,7 +3,7 @@
3
3
  @author: s.fleitmann
4
4
  """
5
5
 
6
- from typing import Union
6
+ from typing import Union, Optional
7
7
 
8
8
  import numpy as np
9
9
 
@@ -51,7 +51,7 @@ class SensorResponseWhiteNoise(SensorResponseDistortionInterface):
51
51
  self.__rng = rng
52
52
 
53
53
  @property
54
- def latest_sigma(self) -> Union[float, None]:
54
+ def latest_sigma(self) -> Optional[float]:
55
55
  """The sigma that was used for the latest simulation.
56
56
 
57
57
  This is necessary because, depending on the setting, a sampler can be used instead of a fixed sigma.
@@ -4,7 +4,7 @@ measurements.
4
4
  @author: f.hader
5
5
  """
6
6
 
7
- from typing import Callable, Dict, Union
7
+ from typing import Callable, Dict, Optional
8
8
 
9
9
  import numpy as np
10
10
 
@@ -48,7 +48,7 @@ def generate_lead_transition_mask_2d(
48
48
  volt_limits_g2: np.ndarray,
49
49
  tct_functions: Dict[int, Callable],
50
50
  rotation: float = -np.pi / 4,
51
- lut_entries: Union[int, None] = None,
51
+ lut_entries: Optional[int] = None,
52
52
  ) -> np.ndarray:
53
53
  """Generates the ground truth label mask for the lead transitions of 2D scans.
54
54
 
@@ -71,7 +71,7 @@ def generate_lead_transition_mask_2d(
71
71
  items should be partially initialized versions of the function "tct_bezier".
72
72
  rotation (float): The rotation to be applied to the TCT(s) (which is/are usually represented rotated by 45
73
73
  degrees). Default is -np.pi/4.
74
- lut_entries (Union[int, None]): Number of samples for the lookup-table. If this is not None, a lookup-table will be used to
74
+ lut_entries (Optional[int]): Number of samples for the lookup-table. If this is not None, a lookup-table will be used to
75
75
  evaluate the points on the bezier curve. Default is None.
76
76
 
77
77
  Returns:
@@ -8,7 +8,7 @@ numbers are calculated without the need for a lead transition mask.
8
8
  """
9
9
 
10
10
  from functools import partial
11
- from typing import Callable, Dict, Tuple, Union
11
+ from typing import Callable, Dict, Tuple, Optional
12
12
 
13
13
  # used to find all regions
14
14
  import diplib as dip
@@ -86,9 +86,9 @@ def get_electron_occupation(
86
86
  bezier_coords: Dict[int, np.ndarray],
87
87
  tct_functions: Dict[int, Callable],
88
88
  rotation: float = -np.pi / 4,
89
- lut_entries: Union[int, None] = None,
89
+ lut_entries: Optional[int] = None,
90
90
  cdf_type: str = "sigmoid",
91
- cdf_gamma_factor: Union[float, None] = None,
91
+ cdf_gamma_factor: Optional[float] = None,
92
92
  ) -> np.ndarray:
93
93
  """Calculates the electron occupations for a given CSD represented by a numpy array.
94
94
 
@@ -113,11 +113,11 @@ def get_electron_occupation(
113
113
  system) and the items should be partially initialized versions of the function "tct_bezier".
114
114
  rotation (float): The rotation that has been applied to the TCT (which is usually represented with the
115
115
  tct_params rotated by 45 degrees). Default: is -np.pi/4.
116
- lut_entries (Union[int, None]): Number of samples for the lookup-table for the bezier curves. If this is not
116
+ lut_entries (Optional[int]): Number of samples for the lookup-table for the bezier curves. If this is not
117
117
  None, a lookup-table will be used to evaluate the points on the bezier curve. Default is None.
118
118
  cdf_type (str): Name of the type of cumulative distribution function (CDF) to be used for interdot transitions.
119
119
  Can be either "cauchy" or "sigmoid. Default is "sigmoid".
120
- cdf_gamma_factor (Union[float, None]): The factor used for the calculation of the gamma values of the CDF.
120
+ cdf_gamma_factor (Optional[float]): The factor used for the calculation of the gamma values of the CDF.
121
121
  If set to None, the default values for the selected cdf_type are used (2.2 for sigmoid, 6.15 for cauchy). \n
122
122
  Gamma is calculated as follows: \n
123
123
  gamma = width_bezier_curve / cdf_gamma_factor. \n
@@ -4,7 +4,7 @@ transitions (TCTs), voltage ranges and a desired resolution. It also implements
4
4
  @author: f.hader
5
5
  """
6
6
 
7
- from typing import List, Tuple, Union
7
+ from typing import List, Tuple, Union, Optional
8
8
 
9
9
  import numpy as np
10
10
 
@@ -25,9 +25,9 @@ def ideal_csd_geometric(
25
25
  volt_limits_g2: np.ndarray,
26
26
  resolution: Union[int, np.ndarray] = np.array([100, 100]),
27
27
  rotation: float = -np.pi / 4,
28
- lut_entries: Union[int, None] = None,
28
+ lut_entries: Optional[int] = None,
29
29
  cdf_type: str = "sigmoid",
30
- cdf_gamma_factor: Union[float, None] = None,
30
+ cdf_gamma_factor: Optional[float] = None,
31
31
  ) -> Tuple[np.ndarray, np.ndarray]:
32
32
  """Generate an ideal Charge Stability Diagram (CSD) based on the supplied parameters.
33
33
 
@@ -60,12 +60,12 @@ def ideal_csd_geometric(
60
60
  [res_g1, res_g2]
61
61
  rotation (float): Float value defining the rotation to be applied to the TCT (which is usually represented
62
62
  with the tct_params rotated by 45 degrees). Default is -np.pi/4.
63
- lut_entries (Union[int, None]): Number of samples for the lookup-table for bezier curves. If this is not None, a
63
+ lut_entries (Optional[int]): Number of samples for the lookup-table for bezier curves. If this is not None, a
64
64
  lookup-table will be used to evaluate the points on the bezier curves, else they are solved explicitly.
65
65
  Using a lookup-table speeds up the calculation at the possible cost of accuracy. Default is None.
66
66
  cdf_type (str): Name of the type of cumulative distribution function (CDF) to be used. Can be either
67
67
  "cauchy" or "sigmoid". Default is "sigmoid".
68
- cdf_gamma_factor (Union[float, None]): The factor used for the calculation of the gamma values of the CDF.
68
+ cdf_gamma_factor (Optional[float]): The factor used for the calculation of the gamma values of the CDF.
69
69
  If set to None (=default) the default values for the selected cdf_type are used. \n
70
70
  Gamma is calculated as follows: \n
71
71
  gamma = width_bezier_curve / cdf_gamma_factor \n
@@ -4,7 +4,7 @@ transitions (TCTs), voltage ranges and a desired resolution. It also implements
4
4
  @author: f.hader
5
5
  """
6
6
 
7
- from typing import List, Tuple, Union
7
+ from typing import List, Tuple, Union, Optional
8
8
 
9
9
  import numpy as np
10
10
 
@@ -21,9 +21,9 @@ class IdealCSDGeometric(IdealCSDInterface):
21
21
  self,
22
22
  tct_params: List[np.ndarray],
23
23
  rotation: float = -np.pi / 4,
24
- lut_entries: Union[int, None] = None,
24
+ lut_entries: Optional[int] = None,
25
25
  cdf_type: str = "sigmoid",
26
- cdf_gamma_factor: Union[float, None] = None,
26
+ cdf_gamma_factor: Optional[float] = None,
27
27
  ) -> None:
28
28
  """Initializes an object of the class for the geometric simulation approach which is based on total charge
29
29
  transitions (TCTs).
@@ -42,12 +42,12 @@ class IdealCSDGeometric(IdealCSDInterface):
42
42
  [7] = end position y (bezier curve rightmost point) (in x-/voltage-space, not number of points)
43
43
  rotation (float): Float value defining the rotation to be applied to the TCT (which is usually represented
44
44
  with the tct_params rotated by 45 degrees). Default is -np.pi/4.
45
- lut_entries (Union[int, None]): Number of samples for the lookup-table for bezier curves. If this is not None, a
45
+ lut_entries (Optional[int]): Number of samples for the lookup-table for bezier curves. If this is not None, a
46
46
  lookup-table will be used to evaluate the points on the bezier curves, else they are solved explicitly.
47
47
  Using a lookup-table speeds up the calculation at the possible cost of accuracy. Default is None.
48
48
  cdf_type (str): Name of the type of cumulative distribution function (CDF) to be used. Can be either
49
49
  "cauchy" or "sigmoid". Default is "sigmoid".
50
- cdf_gamma_factor (Union[float, None]): The factor used for the calculation of the gamma values of the CDF. If set to None
50
+ cdf_gamma_factor (Optional[float]): The factor used for the calculation of the gamma values of the CDF. If set to None
51
51
  (=default) the default values for the selected cdf_type are used (2.2 for sigmoid, 6.15 for cauchy).
52
52
  Default is None. \n
53
53
  Gamma is calculated as follows: \n
@@ -82,14 +82,14 @@ class IdealCSDGeometric(IdealCSDInterface):
82
82
  self.__rotation = rotation
83
83
 
84
84
  @property
85
- def lut_entries(self) -> Union[int, None]:
85
+ def lut_entries(self) -> Optional[int]:
86
86
  """Number of samples for the lookup-table for bezier curves. If this is not None, a lookup-table will be used to
87
87
  evaluate the points on the bezier curves, else they are solved explicitly.
88
88
  """
89
89
  return self.__lut_entries
90
90
 
91
91
  @lut_entries.setter
92
- def lut_entries(self, lut_entries: Union[int, None]):
92
+ def lut_entries(self, lut_entries: Optional[int]):
93
93
  self.__lut_entries = lut_entries
94
94
 
95
95
  @property
@@ -102,14 +102,14 @@ class IdealCSDGeometric(IdealCSDInterface):
102
102
  self.__cdf_type = cdf_type
103
103
 
104
104
  @property
105
- def cdf_gamma_factor(self) -> Union[float, None]:
105
+ def cdf_gamma_factor(self) -> Optional[float]:
106
106
  """The factor used for the calculation of the gamma values of the CDF. If set to None (=default) the default values
107
107
  for the selected cdf_type are used (2.2 for sigmoid, 6.15 for cauchy).
108
108
  """
109
109
  return self.__cdf_gamma_factor
110
110
 
111
111
  @cdf_gamma_factor.setter
112
- def cdf_gamma_factor(self, cdf_gamma_factor: Union[float, None]):
112
+ def cdf_gamma_factor(self, cdf_gamma_factor: Optional[float]):
113
113
  self.__cdf_gamma_factor = cdf_gamma_factor
114
114
 
115
115
  def get_csd_data(
@@ -9,7 +9,7 @@ import math
9
9
 
10
10
  # used to check if a single x-value was passed to x_eval
11
11
  import numbers
12
- from typing import Union
12
+ from typing import Union, Optional
13
13
 
14
14
  import bezier
15
15
  import numpy as np
@@ -19,8 +19,8 @@ import sympy
19
19
  def tct_bezier(
20
20
  tct_params: np.ndarray,
21
21
  x_eval: Union[np.ndarray, numbers.Number],
22
- lut_entries: Union[int, None] = None,
23
- max_peaks: Union[int, None] = None,
22
+ lut_entries: Optional[int] = None,
23
+ max_peaks: Optional[int] = None,
24
24
  ) -> Union[np.ndarray, numbers.Number]:
25
25
  """Evaluates a total charge transition (TCT) with bezier curves and linear parts.
26
26
  A TCT separates the region with n electrons and the region with n+1 electrons in the system. The TCTs (series of
@@ -38,9 +38,9 @@ def tct_bezier(
38
38
  [6] = end position x (bezier curve rightmost point) (in x-/voltage-space, not number of points) \n
39
39
  [7] = end position y (bezier curve rightmost point) (in x-/voltage-space, not number of points)
40
40
  x_eval (Union[np.ndarray, numbers.Number]): X-values for which the function is evaluated or a single x-value.
41
- lut_entries (Union[int, None]): Number of samples for the lookup-table. If this is not None, a lookup-table will
41
+ lut_entries (Optional[int]): Number of samples for the lookup-table. If this is not None, a lookup-table will
42
42
  be used to evaluate the points on the bezier curve, else it is solved explicitly. Default is None.
43
- max_peaks (Union[int, None]): Limit for the number of peaks of the TCT. If multiple TCTs are supplied, max_peaks
43
+ max_peaks (Optional[int]): Limit for the number of peaks of the TCT. If multiple TCTs are supplied, max_peaks
44
44
  is increased by 1 for every further wavefront. If None, all TCTs have an unlimited number of peaks and no
45
45
  outer linear part. Default is None.
46
46
 
@@ -2,10 +2,14 @@
2
2
  SimCATS subpackage containing all functionalities related to the sensor simulation.
3
3
  """
4
4
 
5
- from simcats.sensor._sensor_interface import SensorPeakInterface, SensorInterface
6
- from simcats.sensor._gaussian_sensor_peak import SensorPeakGaussian, sensor_response_gauss
7
- from simcats.sensor._lorentzian_sensor_peak import SensorPeakLorentzian, sensor_response_lorentz
8
- from simcats.sensor._generic_sensor import SensorGeneric
5
+ from simcats.sensor._sensor_interface import SensorPeakInterface, SensorRiseInterface, SensorInterface, \
6
+ SensorScanSensorInterface
7
+ from simcats.sensor._sensor_peak_gaussian import SensorPeakGaussian, sensor_response_gauss
8
+ from simcats.sensor._sensor_peak_lorentzian import SensorPeakLorentzian, sensor_response_lorentz
9
+ from simcats.sensor._sensor_rise_glf import SensorRiseGLF
10
+ from simcats.sensor._sensor_generic import SensorGeneric
11
+ from simcats.sensor._sensor_scan_sensor_generic import SensorScanSensorGeneric
9
12
 
10
- __all__ = ["SensorPeakInterface", "SensorInterface", "SensorPeakGaussian", "SensorPeakLorentzian", "SensorGeneric",
11
- "sensor_response_gauss", "sensor_response_lorentz"]
13
+ __all__ = ["SensorPeakInterface", "SensorRiseInterface", "SensorInterface", "SensorScanSensorInterface",
14
+ "SensorPeakGaussian", "SensorPeakLorentzian", "SensorRiseGLF", "SensorGeneric",
15
+ "SensorScanSensorGeneric", "sensor_response_gauss", "sensor_response_lorentz"]
@@ -155,7 +155,7 @@ class SensorGeneric(SensorInterface):
155
155
  def __repr__(self):
156
156
  return (
157
157
  self.__class__.__name__
158
- + f"(sensor_peak_function={self.__sensor_peak_function}, alpha_dot={self.__alpha_dot}, alpha_gate={self.__alpha_gate}, offset_mu_sens={self.__offset_mu_sens})"
158
+ + f"(sensor_peak_function={self.__sensor_peak_function}, alpha_dot={repr(self.__alpha_dot)}, alpha_gate={repr(self.__alpha_gate)}, offset_mu_sens={self.__offset_mu_sens})"
159
159
  )
160
160
 
161
161
  def sensor_response(self, mu_sens: np.ndarray) -> np.ndarray:
@@ -1,11 +1,11 @@
1
1
  """This module contains functions for simulating the sensor response for a charge stability diagram (CSD) including the
2
2
  cross coupling between the sensor and double dot (plunger) gates.
3
3
 
4
- @author: f.hader
4
+ @author: f.hader, b.papajewski
5
5
  """
6
6
 
7
7
  from abc import ABC, abstractmethod
8
- from typing import List, Union
8
+ from typing import List, Union, Optional
9
9
 
10
10
  import numpy as np
11
11
 
@@ -18,6 +18,17 @@ class SensorPeakInterface(ABC):
18
18
  Implementations of the SensorInterface can consist of multiple peaks.
19
19
  """
20
20
 
21
+ @property
22
+ @abstractmethod
23
+ def mu0(self) -> Optional[float]:
24
+ """Mu0 of the sensor peak.
25
+ This property represents the potential value at which the sensor peak reaches its maximum.
26
+
27
+ The method is needed for the generation of labels of scans. An example for that is the generation of labels for
28
+ sensor scans.
29
+ """
30
+ raise NotImplementedError()
31
+
21
32
  @abstractmethod
22
33
  def sensor_function(self, mu_sens: np.ndarray) -> np.ndarray:
23
34
  """This method has to be implemented in every object which should be used as sensor peak function during the simulation of CSDs.
@@ -39,16 +50,48 @@ class SensorPeakInterface(ABC):
39
50
  return self.__class__.__name__ + str(self.__dict__)
40
51
 
41
52
 
53
+ class SensorRiseInterface(ABC):
54
+ """Interface for all sensor rise functions that model a final rise of the sensor response.
55
+
56
+ This type of rise is needed to simulate the rise at the end of a sensor function, that can be observed in sensor
57
+ scans.
58
+ """
59
+
60
+ @property
61
+ @abstractmethod
62
+ def fully_conductive(self) -> float:
63
+ """Potential value of the point at which the sensor rise reaches its maximum."""
64
+ raise NotImplementedError
65
+
66
+ @abstractmethod
67
+ def sensor_function(self, mu_sens: np.ndarray, offset: float) -> np.ndarray:
68
+ """This method has to be implemented in every object which should be used as sensor rise function during the simulation of CSDs.
69
+
70
+ This function should return the sensor (rise) values which result from the given electrochemical potential.
71
+
72
+ Args:
73
+ mu_sens (np.ndarray): The sensor potential, stored in a numpy array with the axis mapping to the scan axis.
74
+ offset (float): Potential value to which the fully conductive point is shifted.
75
+
76
+ Returns:
77
+ np.ndarray: The sensor response (for the corresponding rise), calculated from the given potential. It is
78
+ stored in a numpy array with the axis mapping to the CSD axis.
79
+ """
80
+ raise NotImplementedError()
81
+
82
+ def __repr__(self) -> str:
83
+ return self.__class__.__name__ + str(self.__dict__)
84
+
85
+
42
86
  class SensorInterface(ABC):
43
87
  """Interface for all sensor functions, which are used in the simulation of CSDs."""
44
88
 
45
89
  @abstractmethod
46
- def __init__(
47
- self,
48
- sensor_peak_function: Union[SensorPeakInterface, List[SensorPeakInterface]],
49
- alpha_dot: np.ndarray,
50
- alpha_gate: np.ndarray,
51
- offset_mu_sens: float,
90
+ def __init__(self,
91
+ sensor_peak_function: Union[SensorPeakInterface, List[SensorPeakInterface]],
92
+ alpha_dot: np.ndarray,
93
+ alpha_gate: np.ndarray,
94
+ offset_mu_sens: float,
52
95
  ) -> None:
53
96
  """Initializes an object of the class for the simulation of the sensor response for a CSD.
54
97
 
@@ -69,7 +112,7 @@ class SensorInterface(ABC):
69
112
 
70
113
  The electrochemical potential at the sensor should be given as one- or two-dimensional numpy array to this
71
114
  function. The parameters for this sensor function should be attributes of this class. This function should
72
- return the sensor values which result from the given electrochemical potential.
115
+ return the sensor response which result from the given electrochemical potential.
73
116
 
74
117
  Args:
75
118
  mu_sens (np.ndarray): The sensor potential, stored in a 2-dimensional numpy array with the axis mapping to
@@ -82,8 +125,10 @@ class SensorInterface(ABC):
82
125
  raise NotImplementedError
83
126
 
84
127
  @abstractmethod
85
- def sensor_potential(
86
- self, occupations: np.ndarray, volt_limits_g1: np.ndarray, volt_limits_g2: np.ndarray
128
+ def sensor_potential(self,
129
+ occupations: np.ndarray,
130
+ volt_limits_g1: np.ndarray,
131
+ volt_limits_g2: np.ndarray
87
132
  ) -> np.ndarray:
88
133
  """Simulates the electrochemical potential at the sensing dot.
89
134
 
@@ -106,3 +151,111 @@ class SensorInterface(ABC):
106
151
 
107
152
  def __repr__(self) -> str:
108
153
  return self.__class__.__name__ + str(self.__dict__)
154
+
155
+
156
+ class SensorScanSensorInterface(SensorInterface):
157
+ def __init__(self,
158
+ sensor_peak_function: Union[SensorPeakInterface, List[SensorPeakInterface], None],
159
+ alpha_dot: np.ndarray,
160
+ alpha_gate: np.ndarray,
161
+ alpha_sensor_gate: np.ndarray,
162
+ offset_mu_sens: np.ndarray,
163
+ ) -> None:
164
+ """This method initializes an object of the class SensorScanSensorInterface.
165
+
166
+ Args:
167
+ sensor_peak_function (Union[SensorPeakInterface, List[SensorPeakInterface], None]): An implementation of the
168
+ SensorPeakInterface. It is also possible to supply a list of such peaks, if a sensor with multiple peaks
169
+ should be simulated.
170
+ alpha_dot (np.ndarray): Lever-arm of the dots for the sensor potential(s). The values should be negative.
171
+ alpha_gate (np.ndarray): Lever-arm of the gates for the sensor potential(s). The values should be positive.
172
+ alpha_sensor_gate (np.ndarray): Lever-arm of the sensor gates for the sensor potential(s). The values should
173
+ be positive.
174
+ offset_mu_sens (np.ndarray): Electrochemical potential of the sensor dot for zero electrons in the dots and
175
+ no applied voltage at the gates.
176
+ """
177
+ raise NotImplementedError
178
+
179
+ @abstractmethod
180
+ def sensor_potential(self,
181
+ occupations: np.ndarray,
182
+ volt_limits_g1: Union[np.ndarray, float, None],
183
+ volt_limits_g2: Union[np.ndarray, float, None],
184
+ volt_limits_sensor_g1: Union[np.ndarray, float, None],
185
+ volt_limits_sensor_g2: Union[np.ndarray, float, None]
186
+ ) -> np.ndarray:
187
+ """Simulates the electrochemical potential at the sensor dot and both barriers.
188
+
189
+ This is done in dependency on the electron occupation in the double dot, the voltages applied at the double
190
+ dot (plunger) gates, and voltages applied at the gates of sensor.
191
+ Either the double dot gates or the sensor gates can be swept.
192
+
193
+ Args:
194
+ occupations (np.ndarray): Occupation in left and right dot per applied voltage combination. The occupation
195
+ numbers are stored in a 3-dimensional numpy array. The first two dimensions map to the axis of the CSD,
196
+ while the third dimension indicates the dot of the corresponding occupation value.
197
+ volt_limits_g1 (Union[np.ndarray, float, None]): Voltages applied to the first (plunger) gate of the double
198
+ dot. When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy
199
+ array with the minimum and maximum of the sweep.
200
+ volt_limits_g2 (Union[np.ndarray, float, None]): Voltages applied to the second (plunger) gate of the double
201
+ dot. When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy
202
+ array with the minimum and maximum of the sweep.
203
+ volt_limits_sensor_g1 (Union[np.ndarray, float, None]): Voltages applied to the first sensor gate.
204
+ When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy array
205
+ with the minimum and maximum of the sweep.
206
+ volt_limits_sensor_g2 (Union[np.ndarray, float, None]): voltages applied to the second sensor gate.
207
+ When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy array
208
+ with the minimum and maximum of the sweep.
209
+
210
+ Returns:
211
+ np.ndarray: The electrochemical potential of the sensor dot, and both barrier. It is returned as a
212
+ three-dimensional array with the shape (3, occupations.shape[0], occupations.shape[1]). The first dimension
213
+ corresponds to the three potentials involved. It is structured as follows:
214
+ [sensor dot potential, barrier 1 potential, barrier 2 potential]
215
+ The remaining two dimensions correspond to the swept voltages.
216
+ """
217
+ raise NotImplementedError
218
+
219
+ def get_sensor_scan_labels(self,
220
+ volt_limits_g1: Union[np.ndarray, float, None],
221
+ volt_limits_g2: Union[np.ndarray, float, None],
222
+ volt_limits_sensor_g1: Union[np.ndarray, float, None],
223
+ volt_limits_sensor_g2: Union[np.ndarray, float, None],
224
+ potential: np.ndarray) -> np.ndarray:
225
+ """This method returns the labels of the sensor scans.
226
+
227
+ There are two labels for sensor scans: the conductive area mask and the Coulomb peak mask. Both masks are numpy
228
+ arrays that consist of integers.
229
+ The conductive area mask marks the non-conductive area, sensor oscillation regime, and fully conductive area.
230
+ The non-conductive area is marked with 0. This is the area in which no electron can tunnel or flow through the
231
+ sensor dot. The sensor oscillation regime is the area in which the barriers are open enough for oscillations to
232
+ occur, as electrons tunnel periodically. This area is marked with 1. In the third area, the conductive area,
233
+ both barriers are fully open and transport occurs as a continuous current rather than through a well-defined
234
+ sensor dot. The fully conductive area is marked with 2.
235
+ The Coulomb peak mask marks the peaks of the Coulomb peak as integers. The wave fronts are marked with values
236
+ higher or equal to one. All maxima belonging to the same Coulomb peak are marked with the same integer.
237
+ Depending on the potential value, the various Coulomb peaks are marked with ascending values.
238
+
239
+ Args:
240
+ volt_limits_g1 (Union[np.ndarray, float, None]): Voltages applied to the first double dot (plunger) gate.
241
+ When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy array
242
+ with the minimum and maximum of the sweep. None can also be passed if no voltage is applied.
243
+ volt_limits_g2 (Union[np.ndarray, float, None]): Voltages applied to the second double dot(plunger) gate.
244
+ When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy array
245
+ with the minimum and maximum of the sweep. None can also be passed if no voltage is applied.
246
+ volt_limits_sensor_g1 (Union[np.ndarray, float, None]): Voltages applied to the first sensor gate.
247
+ When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy array
248
+ with the minimum and maximum of the sweep. None can also be passed if no voltage is applied.
249
+ volt_limits_sensor_g2 (Union[np.ndarray, float, None]): Voltages applied to the second sensor gate.
250
+ When a fixed voltage is applied this is a float and when this gate should be swept it is a numpy array
251
+ with the minimum and maximum of the sweep. None can also be passed if no voltage is applied.
252
+ potential (np.ndarray): Numpy array that contains the potential of the area for which labels should be
253
+ generated. This potential must correspond to the voltages specified for volt_limits_g1,
254
+ volt_limits_g2, volt_limits_sensor_g1 and volt_limits_sensor_g2.
255
+
256
+ Returns:
257
+ (np.ndarray, np.ndarray): Tuple with the two numpy arrays of the two labels of sensor scan.
258
+ The returned tuple looks like: (conductive area mask, coulomb peak mask). Both arrays have the same shape
259
+ as the provided potential.
260
+ """
261
+ raise NotImplementedError