コード例 #1
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"]  # This should only flip the z-coordinate
    spherical3["phi"] = 180 + spherical0[
        "phi"]  # This should flip the xy-coordinate
    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]))
コード例 #2
0
ファイル: test_field_vector.py プロジェクト: nisaige/Qcodes
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())
コード例 #3
0
ファイル: test_ami430.py プロジェクト: quantumsg/Qcodes
def test_cylindrical_setpoints(current_driver, set_target):
    """
    Check that the individual x, y, z instruments are getting the set points as intended. We can do this because the
    instruments are printing log messages to an IO stream. We intercept these messages and extract the log lines which
    mention that the instrument is ramping to certain values. These values should match the values of the input. In
    this test we are verifying this for cylindrical coordinates.
    """
    current_driver.cylindrical(set_target)

    reported_ramp_targets = get_instruments_ramp_messages(current_driver)
    get_target = {k: v["value"] for k, v in reported_ramp_targets.items()}

    set_vector = FieldVector(**dict(zip(["rho", "phi", "z"], set_target)))
    get_vector = FieldVector(**get_target)
    assert set_vector.is_equal(get_vector)
コード例 #4
0
ファイル: test_field_vector.py プロジェクト: nisaige/Qcodes
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]))
コード例 #5
0
ファイル: test_field_vector.py プロジェクト: nisaige/Qcodes
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"))
コード例 #6
0
 def _get_target_field(self) -> FieldVector:
     return FieldVector(
         **{
             coord: self._get_component(coord)
             for coord in 'xyz'
         }
     )
コード例 #7
0
ファイル: test_field_vector.py プロジェクト: nisaige/Qcodes
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]
    }
コード例 #8
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)
コード例 #9
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)
コード例 #10
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)
コード例 #11
0
    def __init__(self,
                 name: str,
                 address: str,
                 visalib=None,
                 field_limits: Optional[Callable[[float, float, float],
                                                 bool]] = None,
                 **kwargs) -> 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'

        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 = MercurySlavePS(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())

        self.connect_message()
コード例 #12
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)
コード例 #13
0
ファイル: test_ami430.py プロジェクト: quantumsg/Qcodes
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 FieldVector(*set_target).is_equal(
        FieldVector(x=cartesian_x, y=cartesian_y, z=cartesian_z))
    assert np.allclose(cartesian, [cartesian_x, cartesian_y, 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])
コード例 #14
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
コード例 #15
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)
コード例 #16
0
ファイル: AMI430.py プロジェクト: quantumsg/Qcodes
    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))
        return_value = [
            d[name] for name in names
        ]  # 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
        if len(names) == 1:
            return_value = return_value[0]

        return return_value
コード例 #17
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 slaves
        cartesian_targ = self._target_vector.get_components('x', 'y', 'z')
        for targ, slave in zip(cartesian_targ, self.submodules.values()):
            slave.field_target(targ)
コード例 #18
0
ファイル: test_MercuryiPS.py プロジェクト: zhinst/Qcodes
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)
コード例 #19
0
    def set_field(self,
                  target_field: FieldVector,
                  n_steps: int = 10,
                  absolute: bool = True,
                  ramp_rate: float = 1e-3,
                  observer_fn: Optional[Callable[[FieldVector], None]] = None,
                  verbose: bool = False,
                  threshold: float = 1e-6) -> None:
        """
        Sets the field controlled by this problem's instrument to a
        given target field by taking small steps, measuring, and then
        updating the target accordingly.

        Args:
            target_field: The value of the field that should be set,
                or the difference between the current and target field
                if `absolute=True`.
            n_steps: The number of steps that should be taken in order
                to reach the given target.
            absolute: Indicates whether `target_field` is the target field,
                or a difference from the current field to the target.
            ramp_rate: A rate at which the field can be safely swept between
                points.
            observer_fn: A callable which gets called after each small step.
            threshold: If the norm of the difference between the current and
                target field is smaller than this value, no further steps
                will be taken.
        """
        if IPYTHON and ipw is not None:
            status = ipw.Label()

            def update(field: FieldVector):
                status.value = field.repr_spherical()

            def finish():
                status.value = "Move complete."

            display(status)
        else:

            def update(field: FieldVector):
                print(
                    f'Magnet reached (r, phi, theta) = ({field.r}, {field.phi}, {field.theta})',
                    end='\r')

            def finish():
                print("Move complete.")

        target = FieldVector()
        if absolute:
            target.copy(target_field)
        else:
            initial = self.instrument.field_measured()
            target = target_field + initial

        with temporary_setting(
                self.instrument.field_ramp_rate,
                FieldVector(x=ramp_rate, y=ramp_rate, z=ramp_rate)):

            for step_amount in np.linspace(0, 1, n_steps + 1)[1:]:
                current = self.instrument.field_measured()
                intermediate_target = step_amount * (target -
                                                     current) + current

                if (intermediate_target - current).norm() <= threshold:
                    print("Step threshold met, stopping move early.")
                    break

                if verbose:
                    print(
                        f"Setting field target to {intermediate_target.repr_spherical()}"
                    )
                self.instrument.field_target(intermediate_target)
                self.instrument.ramp()

                time.sleep(0.1)
                current = self.instrument.field_measured()
                if observer_fn is not None:
                    observer_fn(current)
                update(current)
                time.sleep(0.1)

        finish()
コード例 #20
0
    def __init__(self, name, instrument_x, instrument_y, instrument_z,
                 field_limit: Union[numbers.Real,
                                    Iterable[CartesianFieldLimitFunction]],
                 **kwargs):
        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):
            # Convertion 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())
コード例 #21
0
    def optimize_and_ramp_magnitude(
            self,
            initial_r: float,
            final_r: float,
            n_r_steps: int,
            initial_phi: float,
            phi_window: float,
            n_phis: int,
            initial_theta: float,
            theta_window: float,
            n_thetas: int,
            reoptimization_threshold: float = 0.5,
            n_steps: int = 5,
            ramp_rate: float = 1e-3,
            return_extra: bool = False,
            verbose: bool = False) -> OptionalExtra[FieldVector]:
        """
        Ramps the magnitude of a magnetic field from a given start point,
        optimizing the objective by exhaustive search at each increment in
        field magnitude.

        Returns:
            The optimal field found by an exhaustive seach.
            If `return_extra=True`, this method returns a tuple of the
            optimal field and a dictionary containing diagnostic data.

        Args:
            initial_r: Initial magnitude of the magnetic field.
            final_r: Target magnitude of the magnetic field.
            n_r_steps: The number of steps to take in field magnitude.
            initial_phi: Initial value of phi to use in the exhaustive
                search at `initial_r`.
            phi_window: The size of the window around each value of phi
                to be searched.
            n_phis: The number of discrete values of phi to be searched
                at each field magnitude.
            initial_theta: Initial value of theta to use in the exhaustive
                search at `initial_r`.
            theta_window: The size of the window around each value of theta
                to be searched.
            n_thetas: The number of discrete values of theta to be searched
                at each field magnitude.
            reoptimization_threshold: If an increment in field magnitude
                changes the objective by more than this threshold, as
                scaled by the uncertainty, then an exhaustive search
                will be performed after incrementing. This is useful to
                avoid situations in which an objective value has changed
                by less than a "line width."
            return_extra: If `True`, this method will return additional
                data as a dictionary.

        Returns:
            The optimal field found by an exhaustive seach.
            If `return_extra=True`, this method returns a tuple of the
            optimal field and a dictionary containing diagnostic data.
        """

        extra = {}

        print("Moving to initial field vector...")
        self.set_field(FieldVector(r=initial_r,
                                   phi=initial_phi,
                                   theta=initial_theta),
                       absolute=True)

        rs = np.linspace(initial_r, final_r, n_r_steps)

        # Find the FWHM, so that we can compare line widths.
        prev_objective = None
        prev_uncertainty = None

        objective_history = []
        optima_history = []

        for r in rs:
            print(f"Optimizing at |B| = {r}...")
            current = self.instrument.field_measured()
            self.set_field(FieldVector(r=r,
                                       theta=current.theta,
                                       phi=current.phi),
                           absolute=True,
                           n_steps=n_steps,
                           ramp_rate=ramp_rate,
                           verbose=verbose)

            current_objective = self.objective()
            current_uncertainty = self.objective_uncertainty()

            objective_history.append(current_objective)

            # Check if we can skip this iteration.
            # We force optimization at the final iteration.
            if self.objective_uncertainty is not None and r != rs[
                    -1] and prev_objective is not None:
                scaled_distance = np.abs(
                    current_objective - prev_objective) / np.mean(
                        [prev_uncertainty, current_uncertainty])
                if scaled_distance < reoptimization_threshold:
                    prev_objective = current_objective
                    prev_uncertainty = current_uncertainty
                    print(
                        f"Within {reoptimization_threshold} line widths, not re-optimizing yet."
                    )
                    continue
                else:
                    print(
                        f"Current and previous objectives differ by {scaled_distance} line widths, thus re-optimizing."
                    )

            current_best = self.optimize_at_fixed_magnitude(
                r,
                (current.phi - phi_window / 2, current.phi + phi_window / 2),
                n_phis, (current.theta - theta_window / 2,
                         current.theta + theta_window / 2),
                n_thetas,
                ramp_rate=ramp_rate,
                n_steps=n_steps,
                verbose=verbose)
            optima_history.append(current_best)

            # Find the FWHM at the point optimized by align_at, and save
            # to "prev" so that it's ready for the next iteration.
            if self.objective_uncertainty is not None:
                prev_objective = current_objective
                prev_uncertainty = current_uncertainty

        if return_extra:
            extra['history'] = {
                'rs': rs,
                'objectives': objective_history,
                'optima': optima_history
            }
            return current_best, extra
        else:
            return current_best
コード例 #22
0
ファイル: AMI430.py プロジェクト: mwilmer/Qcodes
    def __init__(self, name, instrument_x, instrument_y, instrument_z,
                 field_limit, **kwargs):
        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

        if repr(field_limit).isnumeric() or isinstance(field_limit,
                                                       collections.Iterable):
            self._field_limit = field_limit
        else:
            raise ValueError("field limit should either be"
                             " a number or an iterable")

        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=self._set_cartesian,
                           unit='T',
                           vals=Anything())

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

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

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

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

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

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

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

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

        self.add_parameter('rho',
                           get_cmd=partial(self._get_setpoints, 'rho'),
                           set_cmd=self._set_rho,
                           unit='T',
                           vals=Numbers())
コード例 #23
0
 def _get_field(self) -> FieldVector:
     return FieldVector(x=self.x_measured(),
                        y=self.y_measured(),
                        z=self.z_measured())
コード例 #24
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(),
     )
コード例 #25
0
    def __init__(self,
                 name: str,
                 address: str,
                 visalib=None,
                 field_limits: Optional[Callable[[float, float, float],
                                                 bool]] = None,
                 **kwargs) -> 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 = MercurySlavePS(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()
コード例 #26
0
ファイル: test_MercuryiPS.py プロジェクト: zhinst/Qcodes
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
コード例 #27
0
ファイル: test_MercuryiPS.py プロジェクト: zhinst/Qcodes
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
コード例 #28
0
    def optimize_at_fixed_magnitude(
            self,
            r: float,
            phi_range: Interval[float],
            n_phi: int,
            theta_range: Interval[float],
            n_theta: int,
            return_extra: bool = False,
            n_steps: int = 5,
            plot: bool = False,
            verbose: bool = False,
            ramp_rate: float = 1.5e-3) -> OptionalExtra[FieldVector]:
        """
        Given the magnitude of a magnetic field, maximizes the objective
        over the spherical coordinates phi and theta by an exhaustive
        search.

        Args:
            r: The magnitude of the magnetic field to be optimized over
                angles.
            phi_range: The interval over which phi will be searched.
            n_phi: The number of distinct values of phi to be evaluated.
            theta_range: The interval over which theta will be searched.
            n_theta: The number of distinct values of theta to be evaluated.
            return_extra: If `True`, this method will return additional
                data as a dictionary.
            plot: If `True`, produces a plot of the path that this
                method took to find the optimal objective value.

        Returns:
            The optimal field found by an exhaustive seach.
            If `return_extra=True`, this method returns a tuple of the
            optimal field and a dictionary containing diagnostic data.
        """

        locations = []
        objectives_meas = []

        still_to_visit = [
            FieldVector(r=r, phi=phi, theta=theta)
            for phi in np.linspace(phi_range[0], phi_range[1], n_phi)
            for theta in np.linspace(theta_range[0], theta_range[1], n_theta)
        ]

        def observe(current_field: FieldVector):
            new_loc = FieldVector()
            new_loc.copy(current_field)
            locations.append(new_loc)
            objectives_meas.append(self.objective())

        while still_to_visit:
            # Find the nearest point.
            current = self.instrument.field_measured()
            nearest = min(still_to_visit, key=current.distance)
            still_to_visit.remove(nearest)
            print(
                f"Evaluating at phi = {nearest.phi}, theta = {nearest.theta}")
            self.set_field(nearest,
                           absolute=True,
                           n_steps=n_steps,
                           ramp_rate=ramp_rate,
                           observer_fn=observe,
                           verbose=verbose)
            observe(self.instrument.field_measured())

        extra = {'objectives': objectives_meas, 'field_vectors': locations}
        idx_flat_best = np.argmax(objectives_meas)
        optimum = FieldVector()
        optimum.copy(locations[idx_flat_best])

        # Renormalize to desired B.
        optimum['r'] = r

        # Move the field before returning.
        print(
            f"Found optimum for |B| = {r} at ({optimum.phi}, {optimum.theta})."
        )
        self.set_field(optimum, absolute=True)

        if plot:
            plt_xs = [vec.phi for vec in extra['field_vectors']]
            plt_ys = [vec.theta for vec in extra['field_vectors']]
            plt.figure()
            plt.plot(
                plt_xs,
                plt_ys,
            )
            plt.scatter(plt_xs, plt_ys, c=extra['objectives'])
            plt.colorbar()

        if return_extra:
            return optimum, extra
        else:
            return optimum
コード例 #29
0
 def observe(current_field: FieldVector):
     new_loc = FieldVector()
     new_loc.copy(current_field)
     locations.append(new_loc)
     objectives_meas.append(self.objective())