Example #1
0
def test_triangle_inequality(cylindrical0, spherical0):
    cylindrical0 = FieldVector(**dict(zip(["rho", "phi", "z"], cylindrical0)))
    spherical0 = FieldVector(**dict(zip(["r", "phi", "theta"], spherical0)))

    assert (cylindrical0 + spherical0).norm() \
           <= (cylindrical0.norm() + spherical0.norm())
    assert cylindrical0.distance(spherical0) \
           <= (cylindrical0.norm() + spherical0.norm())
Example #2
0
def test_cylindrical_properties(cylindrical0):
    """
    If the cartesian to cylindrical transform has been correctly implemented
    then we expect certain symmetrical properties
    """
    # Generate a random coordinate in cylindrical representation
    cylindrical0 = dict(zip(["rho", "phi", "z"], cylindrical0))
    cartisian0 = FieldVector(**cylindrical0).get_components("x", "y", "z")

    # If we flip the sign of the rho coordinate, we will flip the xy coordinate
    cylindrical1 = dict(cylindrical0)
    cylindrical1["rho"] *= -1
    cartisian1 = FieldVector(**cylindrical1).get_components("x", "y", "z")

    assert np.allclose(cartisian0, cartisian1 * np.array([-1, -1, 1]))
Example #3
0
def test_homogeneous_roundtrip(cartesian0):
    vec = FieldVector(**dict(zip("xyz", cartesian0)))
    h_vec = 13 * vec.as_homogeneous()

    assert np.allclose(
        vec.get_components(*"xyz"),
        FieldVector.from_homogeneous(h_vec).get_components(*"xyz"))
Example #4
0
 def _get_target_field(self) -> FieldVector:
     return FieldVector(
         **{
             coord: self._get_component(coord)
             for coord in 'xyz'
         }
     )
Example #5
0
def test_cartesian_setpoints(current_driver, set_target):
    """
    Check that the individual x, y, z instruments are getting the set
    points as intended. This test is very similar to the sanity test, but
    adds in the FieldVector as well.
    """
    current_driver.cartesian(set_target)

    x = current_driver.x()
    y = current_driver.y()
    z = current_driver.z()

    get_target = dict(zip(('x', 'y', 'z'), (x, y, z)))

    set_vector = FieldVector(*set_target)
    get_vector = FieldVector(**get_target)
    assert set_vector.is_equal(get_vector)
Example #6
0
def test_json_dump(spherical0):
    vec = FieldVector(**dict(zip(["r", "phi", "theta"], spherical0)))
    dump = json.dumps(vec, cls=NumpyJSONEncoder)

    assert json.loads(dump) == {
        '__class__': FieldVector.__name__,
        '__args__': [vec.x, vec.y, vec.z]
    }
Example #7
0
def test_spherical_setpoints(current_driver, set_target):
    """
    Check that the individual x, y, z instruments are getting the set
    points as intended. This test is very similar to the sanity test, but
    adds in the FieldVector as well.
    """
    current_driver.spherical(set_target)

    r = current_driver.field()
    theta = current_driver.theta()
    phi = current_driver.phi()

    get_target = dict(zip(('r', 'theta', 'phi'), (r, theta, phi)))
    set_target = dict(zip(('r', 'theta', 'phi'), set_target))

    set_vector = FieldVector(**set_target)
    get_vector = FieldVector(**get_target)
    assert set_vector.is_equal(get_vector)
Example #8
0
def test_cylindrical_setpoints(current_driver, set_target):
    """
    Check that the individual x, y, z instruments are getting the set
    points as intended. This test is very similar to the sanity test, but
    adds in the FieldVector as well.
    """
    current_driver.cylindrical(set_target)

    rho = current_driver.rho()
    z = current_driver.z()
    phi = current_driver.phi()

    get_target = dict(zip(('rho', 'phi', 'z'), (rho, phi, z)))
    set_target = dict(zip(('rho', 'phi', 'z'), set_target))

    set_vector = FieldVector(**set_target)
    get_vector = FieldVector(**get_target)
    assert set_vector.is_equal(get_vector)
Example #9
0
def test_all_attributes_are_floats():
    cartesian0 = (400, 200, 300)
    cylindrical0 = (1, 52, 0)
    spherical0 = (1, 78, 145)

    cartesian = FieldVector(**dict(zip("xyz", cartesian0)))
    cylindrical = FieldVector(**dict(zip(["rho", "phi", "z"], cylindrical0)))
    spherical = FieldVector(**dict(zip(["r", "phi", "theta"], spherical0)))

    # Test that all attributes are floats upon creation
    for fv in [cartesian, cylindrical, spherical]:
        for attr in FieldVector.attributes:
            assert isinstance(getattr(fv, attr), float)

    # Test that all attributes are floats even after setting components
    for fv in [cartesian, cylindrical, spherical]:
        for set_comp in FieldVector.attributes:
            fv.set_component(**{set_comp: 1})

            for attr in FieldVector.attributes:
                assert isinstance(getattr(fv, attr), float)
Example #10
0
def test_spherical_properties(spherical0):
    """
    If the cartesian to spherical transform has been correctly implemented
    then we expect certain symmetrical properties
    """
    # Generate a random coordinate in spherical representation
    spherical0 = dict(zip(["r", "theta", "phi"], spherical0))
    cartisian0 = FieldVector(**spherical0).get_components("x", "y", "z")

    # Mirror the theta angle in the xy-plane.
    # This should flip the sign of the z-coordinate
    spherical1 = dict(spherical0)
    spherical1["theta"] = 180 - spherical0["theta"]
    cartisian1 = FieldVector(**spherical1).get_components("x", "y", "z")
    assert np.allclose(cartisian0, cartisian1 * np.array([1, 1, -1]))

    # Add 180 to the phi coordinate.
    # This should flip the sign of the xy coordinate
    spherical2 = dict(spherical0)
    spherical2["phi"] = 180 + spherical0["phi"]
    cartisian2 = FieldVector(**spherical2).get_components("x", "y", "z")
    assert np.allclose(cartisian0, cartisian2 * np.array([-1, -1, 1]))

    # Mirroring the theta angle in the xy-plane
    # and adding 180 to the phi coordinate
    # should flip all cartesian coordinates
    spherical3 = dict(spherical0)
    spherical3["theta"] = 180 - spherical0["theta"]  # should only flip z
    spherical3["phi"] = 180 + spherical0["phi"]  # should flip xy
    cartisian3 = FieldVector(**spherical3).get_components("x", "y", "z")
    assert np.allclose(cartisian0, cartisian3 * np.array([-1, -1, -1]))

    # Finally, flipping the sign of the r coordinate
    # should flip all cartesian coordinates
    spherical4 = dict(spherical0)
    spherical4["r"] = -spherical0["r"]  # This should flip all coordinates
    cartisian4 = FieldVector(**spherical4).get_components("x", "y", "z")
    assert np.allclose(cartisian0, cartisian4 * np.array([-1, -1, -1]))
Example #11
0
    def _get_measured(self, coordinates: List[str]) -> Union[float,
                                                             List[float]]:
        """
        Get the measured value of a coordinate. Measures all three fields
        and computes whatever coordinate we asked for.
        """
        meas_field = FieldVector(x=self.GRPX.field(),
                                 y=self.GRPY.field(),
                                 z=self.GRPZ.field())

        if len(coordinates) == 1:
            return meas_field.get_components(*coordinates)[0]
        else:
            return meas_field.get_components(*coordinates)
Example #12
0
    def _set_setpoints(self, names, values):

        kwargs = dict(zip(names, np.atleast_1d(values)))

        set_point = FieldVector()
        set_point.copy(self._set_point)
        if len(kwargs) == 3:
            set_point.set_vector(**kwargs)
        else:
            set_point.set_component(**kwargs)

        self._adjust_child_instruments(set_point.get_components("x", "y", "z"))

        self._set_point = set_point
Example #13
0
    def _get_measured(self, *names):

        x = self._instrument_x.field()
        y = self._instrument_y.field()
        z = self._instrument_z.field()
        measured_values = FieldVector(x=x, y=y, z=z).get_components(*names)

        # Convert angles from radians to degrees
        d = dict(zip(names, measured_values))

        # Do not do "return list(d.values())", because then there is
        # no guaranty that the order in which the values are returned
        # is the same as the original intention
        return_value = [d[name] for name in names]

        if len(names) == 1:
            return_value = return_value[0]

        return return_value
Example #14
0
    def _update_individual_axes_ramp_rates(
        self, values: Tuple[float, float, float]
    ) -> None:
        if self.vector_ramp_rate() is None or self.vector_ramp_rate() == 0:
            raise ValueError('The value of the `vector_ramp_rate` Parameter is '
                             'currently None or 0. Set it to an appropriate '
                             'value to use the simultaneous ramping feature.')

        new_axes_ramp_rates = self.calculate_axes_ramp_rates_from_vector_ramp_rate(
            start=self._get_measured_field_vector(),
            setpoint=FieldVector(x=values[0], y=values[1], z=values[2]),
            vector_ramp_rate=self.vector_ramp_rate.get(),
        )
        instruments = (self._instrument_x, self._instrument_y, self._instrument_z)
        for instrument, new_axis_ramp_rate in zip(instruments, new_axes_ramp_rates):
            instrument.ramp_rate.set(new_axis_ramp_rate)
            self.log.debug(
                f"Simultaneous ramp: new rate for {instrument.full_name} "
                f"is {new_axis_ramp_rate} {instrument.ramp_rate.unit}"
            )
Example #15
0
def test_ramp_safely(driver, x, y, z, caplog):
    """
    Test that we get the first-down-then-up order right
    """
    # reset the instrument to default
    driver.GRPX.ramp_status('HOLD')
    driver.GRPY.ramp_status('HOLD')
    driver.GRPZ.ramp_status('HOLD')

    # the current field values are always zero for the sim. instr.
    # Use the FieldVector interface here to increase coverage.
    driver.field_target(FieldVector(x=x, y=y, z=z))

    exp_order = \
        np.array(['x', 'y', 'z'])[np.argsort(np.abs(np.array([x, y, z])))]

    with caplog.at_level(logging.DEBUG, logger='qcodes.instrument.visa'):
        caplog.clear()
        driver._ramp_safely()
        ramp_order = get_ramp_order(caplog.records)

    assert ramp_order == list(exp_order)
Example #16
0
    def _set_target(self, coordinate: str, target: float) -> None:
        """
        The function to set a target value for a coordinate, i.e. the set_cmd
        for the XXX_target parameters
        """
        # first validate the new target
        valid_vec = FieldVector()
        valid_vec.copy(self._target_vector)
        valid_vec.set_component(**{coordinate: target})
        components = valid_vec.get_components('x', 'y', 'z')
        if not self._field_limits(*components):
            raise ValueError(f'Cannot set {coordinate} target to {target}, '
                             'that would violate the field_limits. ')

        # update our internal target cache
        self._target_vector.set_component(**{coordinate: target})

        # actually assign the target on the workers
        cartesian_targ = self._target_vector.get_components('x', 'y', 'z')
        for targ, worker in zip(cartesian_targ, self.submodules.values()):
            if not isinstance(worker, MercuryWorkerPS):
                raise RuntimeError(f"Expected a MercuryWorkerPS but got "
                                   f"{type(worker)}")
            worker.field_target(targ)
Example #17
0
def test_measured(current_driver, set_target):
    """
    Simply call the measurement methods and verify that no exceptions
    are raised.
    """
    current_driver.cartesian(set_target)

    cartesian = current_driver.cartesian_measured()

    cartesian_x = current_driver.x_measured()
    cartesian_y = current_driver.y_measured()
    cartesian_z = current_driver.z_measured()

    assert np.allclose(cartesian, [cartesian_x, cartesian_y, cartesian_z])
    assert FieldVector(*set_target).is_equal(FieldVector(x=cartesian_x,
                                                         y=cartesian_y,
                                                         z=cartesian_z))

    spherical = current_driver.spherical_measured()
    spherical_field = current_driver.field_measured()
    spherical_theta = current_driver.theta_measured()
    spherical_phi = current_driver.phi_measured()

    assert FieldVector(*set_target).is_equal(FieldVector(
        r=spherical_field,
        theta=spherical_theta,
        phi=spherical_phi)
    )
    assert np.allclose(spherical,
                       [spherical_field, spherical_theta, spherical_phi])

    cylindrical = current_driver.cylindrical_measured()
    cylindrical_rho = current_driver.rho_measured()

    assert FieldVector(*set_target).is_equal(FieldVector(rho=cylindrical_rho,
                                                         phi=spherical_phi,
                                                         z=cartesian_z))
    assert np.allclose(cylindrical, [cylindrical_rho,
                                     spherical_phi,
                                     cartesian_z])
Example #18
0
 def _get_measured_field_vector(self) -> FieldVector:
     return FieldVector(
         x=self._instrument_x.field(),
         y=self._instrument_y.field(),
         z=self._instrument_z.field(),
     )
Example #19
0
 def _get_field(self) -> FieldVector:
     return FieldVector(
         x=self.x_measured(),
         y=self.y_measured(),
         z=self.z_measured()
     )
Example #20
0
def test_vector_ramp_rate(driver):
    driver.field_ramp_rate(FieldVector(0.1, 0.1, 0.1))
    assert driver.field_ramp_rate().distance(
        FieldVector(0.1, 0.1, 0.1)
    ) <= 1e-8
Example #21
0
 def _get_ramp_rate(self) -> FieldVector:
     return FieldVector(
         x=self.GRPX.field_ramp_rate(),
         y=self.GRPY.field_ramp_rate(),
         z=self.GRPZ.field_ramp_rate(),
     )
Example #22
0
    def __init__(
        self,
        name: str,
        instrument_x: Union[AMI430, str],
        instrument_y: Union[AMI430, str],
        instrument_z: Union[AMI430, str],
        field_limit: Union[numbers.Real,
                           Iterable[CartesianFieldLimitFunction]],
        **kwargs: Any,
    ):
        """
        Driver for controlling three American Magnetics Model 430 magnet power
        supplies simultaneously for setting magnetic field vectors.

        The individual magnet power supplies can be passed in as either
        instances of AMI430 driver or as names of existing AMI430 instances.
        In the latter case, the instances will be found via the passed names.

        Args:
            name: a name for the instrument
            instrument_x: AMI430 instance or a names of existing AMI430
                instance for controlling the X axis of magnetic field
            instrument_y: AMI430 instance or a names of existing AMI430
                instance for controlling the Y axis of magnetic field
            instrument_z: AMI430 instance or a names of existing AMI430
                instance for controlling the Z axis of magnetic field
            field_limit: a number for maximum allows magnetic field or an
                iterable of callable field limit functions that define
                region(s) of allowed values in 3D magnetic field space
        """
        super().__init__(name, **kwargs)

        if not isinstance(name, str):
            raise ValueError("Name should be a string")

        for instrument, arg_name in zip(
            (instrument_x, instrument_y, instrument_z),
            ("instrument_x", "instrument_y", "instrument_z"),
        ):
            if not isinstance(instrument, (AMI430, str)):
                raise ValueError(
                    f"Instruments need to be instances of the class AMI430 "
                    f"or be valid names of already instantiated instances "
                    f"of AMI430 class; {arg_name} argument is "
                    f"neither of those")

        def find_ami430_with_name(ami430_name: str) -> AMI430:
            found_ami430 = AMI430.find_instrument(name=ami430_name,
                                                  instrument_class=AMI430)
            return found_ami430

        self._instrument_x = (instrument_x if isinstance(instrument_x, AMI430)
                              else find_ami430_with_name(instrument_x))
        self._instrument_y = (instrument_y if isinstance(instrument_y, AMI430)
                              else find_ami430_with_name(instrument_y))
        self._instrument_z = (instrument_z if isinstance(instrument_z, AMI430)
                              else find_ami430_with_name(instrument_z))

        self._field_limit: Union[float, Iterable[CartesianFieldLimitFunction]]
        if isinstance(field_limit, collections.abc.Iterable):
            self._field_limit = field_limit
        elif isinstance(field_limit, numbers.Real):
            # Conversion to float makes related driver logic simpler
            self._field_limit = float(field_limit)
        else:
            raise ValueError("field limit should either be a number or "
                             "an iterable of callable field limit functions.")

        self._set_point = FieldVector(
            x=self._instrument_x.field(),
            y=self._instrument_y.field(),
            z=self._instrument_z.field(),
        )

        # Get-only parameters that return a measured value
        self.add_parameter(
            "cartesian_measured",
            get_cmd=partial(self._get_measured, "x", "y", "z"),
            unit="T",
        )

        self.add_parameter("x_measured",
                           get_cmd=partial(self._get_measured, "x"),
                           unit="T")

        self.add_parameter("y_measured",
                           get_cmd=partial(self._get_measured, "y"),
                           unit="T")

        self.add_parameter("z_measured",
                           get_cmd=partial(self._get_measured, "z"),
                           unit="T")

        self.add_parameter(
            "spherical_measured",
            get_cmd=partial(self._get_measured, "r", "theta", "phi"),
            unit="T",
        )

        self.add_parameter("phi_measured",
                           get_cmd=partial(self._get_measured, "phi"),
                           unit="deg")

        self.add_parameter("theta_measured",
                           get_cmd=partial(self._get_measured, "theta"),
                           unit="deg")

        self.add_parameter("field_measured",
                           get_cmd=partial(self._get_measured, "r"),
                           unit="T")

        self.add_parameter(
            "cylindrical_measured",
            get_cmd=partial(self._get_measured, "rho", "phi", "z"),
            unit="T",
        )

        self.add_parameter("rho_measured",
                           get_cmd=partial(self._get_measured, "rho"),
                           unit="T")

        # Get and set parameters for the set points of the coordinates
        self.add_parameter(
            "cartesian",
            get_cmd=partial(self._get_setpoints, ("x", "y", "z")),
            set_cmd=partial(self._set_setpoints, ("x", "y", "z")),
            unit="T",
            vals=Anything(),
        )

        self.add_parameter(
            "x",
            get_cmd=partial(self._get_setpoints, ("x", )),
            set_cmd=partial(self._set_setpoints, ("x", )),
            unit="T",
            vals=Numbers(),
        )

        self.add_parameter(
            "y",
            get_cmd=partial(self._get_setpoints, ("y", )),
            set_cmd=partial(self._set_setpoints, ("y", )),
            unit="T",
            vals=Numbers(),
        )

        self.add_parameter(
            "z",
            get_cmd=partial(self._get_setpoints, ("z", )),
            set_cmd=partial(self._set_setpoints, ("z", )),
            unit="T",
            vals=Numbers(),
        )

        self.add_parameter(
            "spherical",
            get_cmd=partial(self._get_setpoints, ("r", "theta", "phi")),
            set_cmd=partial(self._set_setpoints, ("r", "theta", "phi")),
            unit="tuple?",
            vals=Anything(),
        )

        self.add_parameter(
            "phi",
            get_cmd=partial(self._get_setpoints, ("phi", )),
            set_cmd=partial(self._set_setpoints, ("phi", )),
            unit="deg",
            vals=Numbers(),
        )

        self.add_parameter(
            "theta",
            get_cmd=partial(self._get_setpoints, ("theta", )),
            set_cmd=partial(self._set_setpoints, ("theta", )),
            unit="deg",
            vals=Numbers(),
        )

        self.add_parameter(
            "field",
            get_cmd=partial(self._get_setpoints, ("r", )),
            set_cmd=partial(self._set_setpoints, ("r", )),
            unit="T",
            vals=Numbers(),
        )

        self.add_parameter(
            "cylindrical",
            get_cmd=partial(self._get_setpoints, ("rho", "phi", "z")),
            set_cmd=partial(self._set_setpoints, ("rho", "phi", "z")),
            unit="tuple?",
            vals=Anything(),
        )

        self.add_parameter(
            "rho",
            get_cmd=partial(self._get_setpoints, ("rho", )),
            set_cmd=partial(self._set_setpoints, ("rho", )),
            unit="T",
            vals=Numbers(),
        )

        self.add_parameter("block_during_ramp",
                           set_cmd=None,
                           initial_value=True,
                           unit="",
                           vals=Bool())

        self.ramp_mode = Parameter(
            name="ramp_mode",
            instrument=self,
            get_cmd=None,
            set_cmd=None,
            vals=Enum("default", "simultaneous"),
            initial_value="default",
        )

        self.ramping_state_check_interval = Parameter(
            name="ramping_state_check_interval",
            instrument=self,
            initial_value=0.05,
            unit="s",
            vals=Numbers(0, 10),
            set_cmd=None,
            get_cmd=None,
        )

        self.vector_ramp_rate = Parameter(
            name="vector_ramp_rate",
            instrument=self,
            unit="T/s",
            vals=Numbers(min_value=0.0),
            set_cmd=None,
            get_cmd=None,
            set_parser=self._set_vector_ramp_rate_units,
            docstring="Ramp rate along a line (vector) in 3D space. Only active"
            " if `ramp_mode='simultaneous'`.",
        )
        """Ramp rate along a line (vector) in 3D field space"""
Example #23
0
    def __init__(self, name: str, address: str, visalib: Optional[str] = None,
                 field_limits: Optional[Callable[[float,
                                                  float,
                                                  float], bool]] = None,
                 **kwargs: Any) -> None:
        """
        Args:
            name: The name to give this instrument internally in QCoDeS
            address: The VISA resource of the instrument. Note that a
                socket connection to port 7020 must be made
            visalib: The VISA library to use. Leave blank if not in simulation
                mode.
            field_limits: A function describing the allowed field
                range (T). The function shall take (x, y, z) as an input and
                return a boolean describing whether that field value is
                acceptable.
        """

        if field_limits is not None and not(callable(field_limits)):
            raise ValueError('Got wrong type of field_limits. Must be a '
                             'function from (x, y, z) -> Bool. Received '
                             f'{type(field_limits)} instead.')

        if visalib:
            visabackend = visalib.split('@')[1]
        else:
            visabackend = 'NI'

        # ensure that a socket is used unless we are in simulation mode
        if not address.endswith('SOCKET') and visabackend != 'sim':
            raise ValueError('Incorrect VISA resource name. Must be of type '
                             'TCPIP0::XXX.XXX.XXX.XXX::7020::SOCKET.')

        super().__init__(name, address, terminator='\n', visalib=visalib,
                         **kwargs)

        # to ensure a correct snapshot, we must wrap the get function
        self.IDN.get = self.IDN._wrap_get(self._idn_getter)

        self.firmware = self.IDN()['firmware']

        # TODO: Query instrument to ensure which PSUs are actually present
        for grp in ['GRPX', 'GRPY', 'GRPZ']:
            psu_name = grp
            psu = MercuryWorkerPS(self, psu_name, grp)
            self.add_submodule(psu_name, psu)

        self._field_limits = (field_limits if field_limits else
                              lambda x, y, z: True)

        self._target_vector = FieldVector(x=self.GRPX.field(),
                                          y=self.GRPY.field(),
                                          z=self.GRPZ.field())

        for coord, unit in zip(
                ['x', 'y', 'z', 'r', 'theta',   'phi',     'rho'],
                ['T', 'T', 'T', 'T', 'degrees', 'degrees', 'T']):
            self.add_parameter(name=f'{coord}_target',
                               label=f'{coord.upper()} target field',
                               unit=unit,
                               get_cmd=partial(self._get_component, coord),
                               set_cmd=partial(self._set_target, coord))

            self.add_parameter(name=f'{coord}_measured',
                               label=f'{coord.upper()} measured field',
                               unit=unit,
                               get_cmd=partial(self._get_measured, [coord]))

            self.add_parameter(name=f'{coord}_ramp',
                               label=f'{coord.upper()} ramp field',
                               unit=unit,
                               docstring='A safe ramp for each coordinate',
                               get_cmd=partial(self._get_component, coord),
                               set_cmd=partial(self._set_target_and_ramp,
                                               coord, 'safe'))

            if coord in ['r', 'theta', 'phi', 'rho']:
                self.add_parameter(name=f'{coord}_simulramp',
                                   label=f'{coord.upper()} ramp field',
                                   unit=unit,
                                   docstring='A simultaneous blocking ramp for'
                                             ' a combined coordinate',
                                   get_cmd=partial(self._get_component, coord),
                                   set_cmd=partial(self._set_target_and_ramp,
                                                   coord, 'simul_block'))

        # FieldVector-valued parameters #

        self.add_parameter(name="field_target",
                           label="target field",
                           unit="T",
                           get_cmd=self._get_target_field,
                           set_cmd=self._set_target_field)

        self.add_parameter(name="field_measured",
                           label="measured field",
                           unit="T",
                           get_cmd=self._get_field)

        self.add_parameter(name="field_ramp_rate",
                           label="ramp rate",
                           unit="T/s",
                           get_cmd=self._get_ramp_rate,
                           set_cmd=self._set_ramp_rate)

        self.connect_message()
Example #24
0
def test_vector_setting(driver):
    assert driver.field_target().distance(FieldVector(0, 0, 0)) <= 1e-8
    driver.field_target(FieldVector(r=0.1, theta=0, phi=0))
    assert driver.field_target().distance(
        FieldVector(r=0.1, theta=0, phi=0)
    ) <= 1e-8
Example #25
0
    def __init__(self, name: str, instrument_x: Union[AMI430, str],
                 instrument_y: Union[AMI430, str], instrument_z: Union[AMI430,
                                                                       str],
                 field_limit: Union[numbers.Real,
                                    Iterable[CartesianFieldLimitFunction]],
                 **kwargs: Any):
        super().__init__(name, **kwargs)

        if not isinstance(name, str):
            raise ValueError("Name should be a string")

        for instrument, arg_name in zip(
            (instrument_x, instrument_y, instrument_z),
            ("instrument_x", "instrument_y", "instrument_z"),
        ):
            if not isinstance(instrument, (AMI430, str)):
                raise ValueError(
                    f"Instruments need to be instances of the class AMI430 "
                    f"or be valid names of already instantiated instances "
                    f"of AMI430 class; {arg_name} argument is "
                    f"neither of those")

        def find_ami430_with_name(ami430_name: str) -> AMI430:
            found_ami430 = AMI430.find_instrument(name=ami430_name,
                                                  instrument_class=AMI430)
            return cast(AMI430, found_ami430)

        self._instrument_x = (instrument_x if isinstance(instrument_x, AMI430)
                              else find_ami430_with_name(instrument_x))
        self._instrument_y = (instrument_y if isinstance(instrument_y, AMI430)
                              else find_ami430_with_name(instrument_y))
        self._instrument_z = (instrument_z if isinstance(instrument_z, AMI430)
                              else find_ami430_with_name(instrument_z))

        self._field_limit: Union[float, Iterable[CartesianFieldLimitFunction]]
        if isinstance(field_limit, collections.abc.Iterable):
            self._field_limit = field_limit
        elif isinstance(field_limit, numbers.Real):
            # Conversion to float makes related driver logic simpler
            self._field_limit = float(field_limit)
        else:
            raise ValueError("field limit should either be a number or "
                             "an iterable of callable field limit functions.")

        self._set_point = FieldVector(x=self._instrument_x.field(),
                                      y=self._instrument_y.field(),
                                      z=self._instrument_z.field())

        # Get-only parameters that return a measured value
        self.add_parameter('cartesian_measured',
                           get_cmd=partial(self._get_measured, 'x', 'y', 'z'),
                           unit='T')

        self.add_parameter('x_measured',
                           get_cmd=partial(self._get_measured, 'x'),
                           unit='T')

        self.add_parameter('y_measured',
                           get_cmd=partial(self._get_measured, 'y'),
                           unit='T')

        self.add_parameter('z_measured',
                           get_cmd=partial(self._get_measured, 'z'),
                           unit='T')

        self.add_parameter('spherical_measured',
                           get_cmd=partial(self._get_measured, 'r', 'theta',
                                           'phi'),
                           unit='T')

        self.add_parameter('phi_measured',
                           get_cmd=partial(self._get_measured, 'phi'),
                           unit='deg')

        self.add_parameter('theta_measured',
                           get_cmd=partial(self._get_measured, 'theta'),
                           unit='deg')

        self.add_parameter('field_measured',
                           get_cmd=partial(self._get_measured, 'r'),
                           unit='T')

        self.add_parameter('cylindrical_measured',
                           get_cmd=partial(self._get_measured, 'rho', 'phi',
                                           'z'),
                           unit='T')

        self.add_parameter('rho_measured',
                           get_cmd=partial(self._get_measured, 'rho'),
                           unit='T')

        # Get and set parameters for the set points of the coordinates
        self.add_parameter('cartesian',
                           get_cmd=partial(self._get_setpoints,
                                           ('x', 'y', 'z')),
                           set_cmd=partial(self._set_setpoints,
                                           ('x', 'y', 'z')),
                           unit='T',
                           vals=Anything())

        self.add_parameter('x',
                           get_cmd=partial(self._get_setpoints, ('x', )),
                           set_cmd=partial(self._set_setpoints, ('x', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('y',
                           get_cmd=partial(self._get_setpoints, ('y', )),
                           set_cmd=partial(self._set_setpoints, ('y', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('z',
                           get_cmd=partial(self._get_setpoints, ('z', )),
                           set_cmd=partial(self._set_setpoints, ('z', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('spherical',
                           get_cmd=partial(self._get_setpoints,
                                           ('r', 'theta', 'phi')),
                           set_cmd=partial(self._set_setpoints,
                                           ('r', 'theta', 'phi')),
                           unit='tuple?',
                           vals=Anything())

        self.add_parameter('phi',
                           get_cmd=partial(self._get_setpoints, ('phi', )),
                           set_cmd=partial(self._set_setpoints, ('phi', )),
                           unit='deg',
                           vals=Numbers())

        self.add_parameter('theta',
                           get_cmd=partial(self._get_setpoints, ('theta', )),
                           set_cmd=partial(self._set_setpoints, ('theta', )),
                           unit='deg',
                           vals=Numbers())

        self.add_parameter('field',
                           get_cmd=partial(self._get_setpoints, ('r', )),
                           set_cmd=partial(self._set_setpoints, ('r', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('cylindrical',
                           get_cmd=partial(self._get_setpoints,
                                           ('rho', 'phi', 'z')),
                           set_cmd=partial(self._set_setpoints,
                                           ('rho', 'phi', 'z')),
                           unit='tuple?',
                           vals=Anything())

        self.add_parameter('rho',
                           get_cmd=partial(self._get_setpoints, ('rho', )),
                           set_cmd=partial(self._set_setpoints, ('rho', )),
                           unit='T',
                           vals=Numbers())

        self.add_parameter('block_during_ramp',
                           set_cmd=None,
                           initial_value=True,
                           unit='',
                           vals=Bool())
Example #26
0
    def __init__(self,
                 name: str,
                 instrument_x: AMI430,
                 instrument_y: AMI430,
                 instrument_z: AMI430,
                 field_limit: Union[numbers.Real,
                                    Iterable[CartesianFieldLimitFunction]],
                 **kwargs: Any):
        super().__init__(name, **kwargs)

        if not isinstance(name, str):
            raise ValueError("Name should be a string")

        instruments = [instrument_x, instrument_y, instrument_z]

        if not all([isinstance(instrument, AMI430)
                    for instrument in instruments]):
            raise ValueError("Instruments need to be instances "
                             "of the class AMI430")

        self._instrument_x = instrument_x
        self._instrument_y = instrument_y
        self._instrument_z = instrument_z

        self._field_limit: Union[float, Iterable[CartesianFieldLimitFunction]]
        if isinstance(field_limit, collections.abc.Iterable):
            self._field_limit = field_limit
        elif isinstance(field_limit, numbers.Real):
            # Conversion to float makes related driver logic simpler
            self._field_limit = float(field_limit)
        else:
            raise ValueError("field limit should either be a number or "
                             "an iterable of callable field limit functions.")

        self._set_point = FieldVector(
            x=self._instrument_x.field(),
            y=self._instrument_y.field(),
            z=self._instrument_z.field()
        )

        # Get-only parameters that return a measured value
        self.add_parameter(
            'cartesian_measured',
            get_cmd=partial(self._get_measured, 'x', 'y', 'z'),
            unit='T'
        )

        self.add_parameter(
            'x_measured',
            get_cmd=partial(self._get_measured, 'x'),
            unit='T'
        )

        self.add_parameter(
            'y_measured',
            get_cmd=partial(self._get_measured, 'y'),
            unit='T'
        )

        self.add_parameter(
            'z_measured',
            get_cmd=partial(self._get_measured, 'z'),
            unit='T'
        )

        self.add_parameter(
            'spherical_measured',
            get_cmd=partial(
                self._get_measured,
                'r',
                'theta',
                'phi'
            ),
            unit='T'
        )

        self.add_parameter(
            'phi_measured',
            get_cmd=partial(self._get_measured, 'phi'),
            unit='deg'
        )

        self.add_parameter(
            'theta_measured',
            get_cmd=partial(self._get_measured, 'theta'),
            unit='deg'
        )

        self.add_parameter(
            'field_measured',
            get_cmd=partial(self._get_measured, 'r'),
            unit='T')

        self.add_parameter(
            'cylindrical_measured',
            get_cmd=partial(self._get_measured,
                            'rho',
                            'phi',
                            'z'),
            unit='T')

        self.add_parameter(
            'rho_measured',
            get_cmd=partial(self._get_measured, 'rho'),
            unit='T'
        )

        # Get and set parameters for the set points of the coordinates
        self.add_parameter(
            'cartesian',
            get_cmd=partial(self._get_setpoints, ('x', 'y', 'z')),
            set_cmd=partial(self._set_setpoints, ('x', 'y', 'z')),
            unit='T',
            vals=Anything()
        )

        self.add_parameter(
            'x',
            get_cmd=partial(self._get_setpoints, ('x',)),
            set_cmd=partial(self._set_setpoints, ('x',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'y',
            get_cmd=partial(self._get_setpoints, ('y',)),
            set_cmd=partial(self._set_setpoints, ('y',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'z',
            get_cmd=partial(self._get_setpoints, ('z',)),
            set_cmd=partial(self._set_setpoints, ('z',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'spherical',
            get_cmd=partial(
                self._get_setpoints, ('r', 'theta', 'phi')
            ),
            set_cmd=partial(
                self._set_setpoints, ('r', 'theta', 'phi')
            ),
            unit='tuple?',
            vals=Anything()
        )

        self.add_parameter(
            'phi',
            get_cmd=partial(self._get_setpoints, ('phi',)),
            set_cmd=partial(self._set_setpoints, ('phi',)),
            unit='deg',
            vals=Numbers()
        )

        self.add_parameter(
            'theta',
            get_cmd=partial(self._get_setpoints, ('theta',)),
            set_cmd=partial(self._set_setpoints, ('theta',)),
            unit='deg',
            vals=Numbers()
        )

        self.add_parameter(
            'field',
            get_cmd=partial(self._get_setpoints, ('r',)),
            set_cmd=partial(self._set_setpoints, ('r',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'cylindrical',
            get_cmd=partial(
                self._get_setpoints, ('rho', 'phi', 'z')
            ),
            set_cmd=partial(
                self._set_setpoints, ('rho', 'phi', 'z')
            ),
            unit='tuple?',
            vals=Anything()
        )

        self.add_parameter(
            'rho',
            get_cmd=partial(self._get_setpoints, ('rho',)),
            set_cmd=partial(self._set_setpoints, ('rho',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'block_during_ramp',
            set_cmd=None,
            initial_value=True,
            unit='',
            vals=Bool()
        )
Example #27
0
    def __init__(self,
                 name: str,
                 instrument_x: Union[AMI430, str],
                 instrument_y: Union[AMI430, str],
                 instrument_z: Union[AMI430, str],
                 field_limit: Union[numbers.Real,
                                    Iterable[CartesianFieldLimitFunction]],
                 **kwargs: Any):
        """
        Driver for controlling three American Magnetics Model 430 magnet power
        supplies simultaneously for setting magnetic field vectors.

        The individual magnet power supplies can be passed in as either
        instances of AMI430 driver or as names of existing AMI430 instances.
        In the latter case, the instances will be found via the passed names.

        Args:
            name: a name for the instrument
            instrument_x: AMI430 instance or a names of existing AMI430
                instance for controlling the X axis of magnetic field
            instrument_y: AMI430 instance or a names of existing AMI430
                instance for controlling the Y axis of magnetic field
            instrument_z: AMI430 instance or a names of existing AMI430
                instance for controlling the Z axis of magnetic field
            field_limit: a number for maximum allows magnetic field or an
                iterable of callable field limit functions that define
                region(s) of allowed values in 3D magnetic field space
        """
        super().__init__(name, **kwargs)

        if not isinstance(name, str):
            raise ValueError("Name should be a string")

        for instrument, arg_name in zip(
                (instrument_x, instrument_y, instrument_z),
                ("instrument_x", "instrument_y", "instrument_z"),
        ):
            if not isinstance(instrument, (AMI430, str)):
                raise ValueError(
                    f"Instruments need to be instances of the class AMI430 "
                    f"or be valid names of already instantiated instances "
                    f"of AMI430 class; {arg_name} argument is "
                    f"neither of those"
                )

        def find_ami430_with_name(ami430_name: str) -> AMI430:
            found_ami430 = AMI430.find_instrument(
                name=ami430_name, instrument_class=AMI430
            )
            return cast(AMI430, found_ami430)

        self._instrument_x = (
            instrument_x if isinstance(instrument_x, AMI430)
            else find_ami430_with_name(instrument_x)
        )
        self._instrument_y = (
            instrument_y if isinstance(instrument_y, AMI430)
            else find_ami430_with_name(instrument_y)
        )
        self._instrument_z = (
            instrument_z if isinstance(instrument_z, AMI430)
            else find_ami430_with_name(instrument_z)
        )

        self._field_limit: Union[float, Iterable[CartesianFieldLimitFunction]]
        if isinstance(field_limit, collections.abc.Iterable):
            self._field_limit = field_limit
        elif isinstance(field_limit, numbers.Real):
            # Conversion to float makes related driver logic simpler
            self._field_limit = float(field_limit)
        else:
            raise ValueError("field limit should either be a number or "
                             "an iterable of callable field limit functions.")

        self._set_point = FieldVector(
            x=self._instrument_x.field(),
            y=self._instrument_y.field(),
            z=self._instrument_z.field()
        )

        # Get-only parameters that return a measured value
        self.add_parameter(
            'cartesian_measured',
            get_cmd=partial(self._get_measured, 'x', 'y', 'z'),
            unit='T'
        )

        self.add_parameter(
            'x_measured',
            get_cmd=partial(self._get_measured, 'x'),
            unit='T'
        )

        self.add_parameter(
            'y_measured',
            get_cmd=partial(self._get_measured, 'y'),
            unit='T'
        )

        self.add_parameter(
            'z_measured',
            get_cmd=partial(self._get_measured, 'z'),
            unit='T'
        )

        self.add_parameter(
            'spherical_measured',
            get_cmd=partial(
                self._get_measured,
                'r',
                'theta',
                'phi'
            ),
            unit='T'
        )

        self.add_parameter(
            'phi_measured',
            get_cmd=partial(self._get_measured, 'phi'),
            unit='deg'
        )

        self.add_parameter(
            'theta_measured',
            get_cmd=partial(self._get_measured, 'theta'),
            unit='deg'
        )

        self.add_parameter(
            'field_measured',
            get_cmd=partial(self._get_measured, 'r'),
            unit='T')

        self.add_parameter(
            'cylindrical_measured',
            get_cmd=partial(self._get_measured,
                            'rho',
                            'phi',
                            'z'),
            unit='T')

        self.add_parameter(
            'rho_measured',
            get_cmd=partial(self._get_measured, 'rho'),
            unit='T'
        )

        # Get and set parameters for the set points of the coordinates
        self.add_parameter(
            'cartesian',
            get_cmd=partial(self._get_setpoints, ('x', 'y', 'z')),
            set_cmd=partial(self._set_setpoints, ('x', 'y', 'z')),
            unit='T',
            vals=Anything()
        )

        self.add_parameter(
            'x',
            get_cmd=partial(self._get_setpoints, ('x',)),
            set_cmd=partial(self._set_setpoints, ('x',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'y',
            get_cmd=partial(self._get_setpoints, ('y',)),
            set_cmd=partial(self._set_setpoints, ('y',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'z',
            get_cmd=partial(self._get_setpoints, ('z',)),
            set_cmd=partial(self._set_setpoints, ('z',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'spherical',
            get_cmd=partial(
                self._get_setpoints, ('r', 'theta', 'phi')
            ),
            set_cmd=partial(
                self._set_setpoints, ('r', 'theta', 'phi')
            ),
            unit='tuple?',
            vals=Anything()
        )

        self.add_parameter(
            'phi',
            get_cmd=partial(self._get_setpoints, ('phi',)),
            set_cmd=partial(self._set_setpoints, ('phi',)),
            unit='deg',
            vals=Numbers()
        )

        self.add_parameter(
            'theta',
            get_cmd=partial(self._get_setpoints, ('theta',)),
            set_cmd=partial(self._set_setpoints, ('theta',)),
            unit='deg',
            vals=Numbers()
        )

        self.add_parameter(
            'field',
            get_cmd=partial(self._get_setpoints, ('r',)),
            set_cmd=partial(self._set_setpoints, ('r',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'cylindrical',
            get_cmd=partial(
                self._get_setpoints, ('rho', 'phi', 'z')
            ),
            set_cmd=partial(
                self._set_setpoints, ('rho', 'phi', 'z')
            ),
            unit='tuple?',
            vals=Anything()
        )

        self.add_parameter(
            'rho',
            get_cmd=partial(self._get_setpoints, ('rho',)),
            set_cmd=partial(self._set_setpoints, ('rho',)),
            unit='T',
            vals=Numbers()
        )

        self.add_parameter(
            'block_during_ramp',
            set_cmd=None,
            initial_value=True,
            unit='',
            vals=Bool()
        )