Skip to content

Commit

Permalink
Fixes to the amplitude noise implementation (#768)
Browse files Browse the repository at this point in the history
* Include the beam's propagation direction in Channel

* Apply amplitude fluctuations from run to run instead of pulse to pulse

* Correct emulation of finite-waist effects on amplitude

* Fix handling or laser_waist to/from SimConfig

* UTs for the noise

* Include propagation_dir in the JSON schema

* Fix error in conversion between SimConfig and NoiseModel

* Add the pulser version to serialized devices

* Missing UT for Channel

* Adopting review suggestions
  • Loading branch information
HGSilveri authored Dec 2, 2024
1 parent e27d45a commit 5a58264
Show file tree
Hide file tree
Showing 11 changed files with 367 additions and 30 deletions.
25 changes: 24 additions & 1 deletion pulser-core/pulser/channels/base_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

ChannelType = TypeVar("ChannelType", bound="Channel")

OPTIONAL_ABSTR_CH_FIELDS = ("min_avg_amp",)
OPTIONAL_ABSTR_CH_FIELDS = ("min_avg_amp", "propagation_dir")

# States ranked in decreasing order of their associated eigenenergy
States = Literal["u", "d", "r", "g", "h", "x"]
Expand Down Expand Up @@ -78,6 +78,8 @@ class Channel(ABC):
min_avg_amp: The minimum average amplitude of a pulse (when not zero).
mod_bandwidth: The modulation bandwidth at -3dB (50% reduction), in
MHz.
propagation_dir: The propagation direction of the beam associated with
the channel, given as a vector in 3D space.
Example:
To create a channel targeting the 'ground-rydberg' transition globally,
Expand All @@ -96,6 +98,7 @@ class Channel(ABC):
min_avg_amp: float = 0
mod_bandwidth: Optional[float] = None # MHz
eom_config: Optional[BaseEOM] = field(init=False, default=None)
propagation_dir: tuple[float, float, float] | None = None

@property
def name(self) -> str:
Expand Down Expand Up @@ -196,7 +199,12 @@ def __post_init__(self) -> None:
getattr(self, p) is None
), f"'{p}' must be left as None in a Global channel."
else:
assert self.addressing == "Local"
parameters += local_only
if self.propagation_dir is not None:
raise NotImplementedError(
"'propagation_dir' must be left as None in Local channels."
)

for param in parameters:
value = getattr(self, param)
Expand Down Expand Up @@ -244,6 +252,18 @@ def __post_init__(self) -> None:
"modulation bandwidth."
)

if self.propagation_dir is not None:
dir_vector = np.array(self.propagation_dir, dtype=float)
if dir_vector.size != 3 or np.sum(dir_vector) == 0.0:
raise ValueError(
"'propagation_dir' must be given as a non-zero 3D vector;"
f" got {self.propagation_dir} instead."
)
# Make sure it's stored as a tuple
object.__setattr__(
self, "propagation_dir", tuple(self.propagation_dir)
)

@property
def rise_time(self) -> int:
"""The rise time (in ns).
Expand Down Expand Up @@ -340,6 +360,7 @@ def Global(
cls: Type[ChannelType],
max_abs_detuning: Optional[float],
max_amp: Optional[float],
# TODO: Impose a default propagation_dir in pulser-core 1.3
**kwargs: Any,
) -> ChannelType:
"""Initializes the channel with global addressing.
Expand All @@ -361,6 +382,8 @@ def Global(
bandwidth at -3dB (50% reduction), in MHz.
min_avg_amp: The minimum average amplitude of a pulse (when not
zero).
propagation_dir: The propagation direction of the beam associated
with the channel, given as a vector in 3D space.
"""
# Can't initialize a channel whose addressing is determined internally
for cls_field in fields(cls):
Expand Down
9 changes: 8 additions & 1 deletion pulser-core/pulser/devices/_device_datacls.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import numpy as np
from scipy.spatial.distance import squareform

import pulser
import pulser.json.abstract_repr as pulser_abstract_repr
import pulser.math as pm
from pulser.channels.base_channel import Channel, States, get_states_from_bases
Expand Down Expand Up @@ -565,7 +566,13 @@ def _to_abstract_repr(self) -> dict[str, Any]:
for ch_name, ch_obj in self.channels.items():
ch_list.append(ch_obj._to_abstract_repr(ch_name))
# Add version and channels to params
params.update({"version": "1", "channels": ch_list})
params.update(
{
"version": "1",
"pulser_version": pulser.__version__,
"channels": ch_list,
}
)
dmm_list = []
for dmm_name, dmm_obj in self.dmm_channels.items():
dmm_list.append(dmm_obj._to_abstract_repr(dmm_name))
Expand Down
Loading

0 comments on commit 5a58264

Please sign in to comment.