From 7712ead3f0478d33da93b29704ae411e9d65bbdf Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Mon, 29 Sep 2025 16:23:00 -0700 Subject: [PATCH 01/13] Add blocking during temperature ramp --- .../QuantumDesign/DynaCoolPPMS/DynaCool.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 657f15af54bd..5770e045facb 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -410,6 +410,12 @@ def _temp_setter( values[self.temp_params.index(param)] = value self.write(f"TEMP {values[0]}, {values[1]}, {values[2]}") + self._block_on_temperature_ramp() + + def _block_on_temperature_ramp(self) -> None: + """Block all instrument interactions until temperature stabilizes.""" + while self.temperature_state() != "stable": + sleep(1) def write(self, cmd: str) -> None: """ From 57095b97b0cd276b1b7a3f767fa7106eeaed7ee8 Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Mon, 29 Sep 2025 16:39:43 -0700 Subject: [PATCH 02/13] Update newsfragment for DynaCool PPMS driver improvement --- docs/changes/newsfragments/7534.improved_driver | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/changes/newsfragments/7534.improved_driver diff --git a/docs/changes/newsfragments/7534.improved_driver b/docs/changes/newsfragments/7534.improved_driver new file mode 100644 index 000000000000..00505ea20703 --- /dev/null +++ b/docs/changes/newsfragments/7534.improved_driver @@ -0,0 +1,3 @@ +Added blocking function to DynaCool PPMS driver that waits for temperature +state to be stable before allowing other functions to be called when +setting the temperature. From 78974917d529552afa4accdff1bd44ce502e9e4e Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Mon, 27 Oct 2025 08:23:46 -0700 Subject: [PATCH 03/13] Add optional bool to _temp_setter to control blocking_t function to prevent breaking current implementations. --- .../QuantumDesign/DynaCoolPPMS/DynaCool.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 5770e045facb..2b2a29a97355 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -83,6 +83,15 @@ def __init__( ) """Parameter temperature_setpoint""" + self.blocking_t: Parameter = self.add_parameter( + "blocking_t", + label="Block instrument while ramping temp", + unit="K", + vals=vals.Numbers(1.6, 400), + set_cmd=partial(self._temp_setter, "temperature_setpoint", True), + ) + """Parameter blocking_t will block instrument interaction while temperature is ramping to setpoint.""" + self.temperature_rate: Parameter = self.add_parameter( "temperature_rate", label="Temperature settle rate", @@ -400,6 +409,7 @@ def _temp_setter( "temperature_setpoint", "temperature_rate", "temperature_settling" ], value: float, + block_while_ramping: bool = False, ) -> None: """ The setter function for the temperature parameters. All three are set @@ -410,12 +420,10 @@ def _temp_setter( values[self.temp_params.index(param)] = value self.write(f"TEMP {values[0]}, {values[1]}, {values[2]}") - self._block_on_temperature_ramp() - def _block_on_temperature_ramp(self) -> None: - """Block all instrument interactions until temperature stabilizes.""" - while self.temperature_state() != "stable": - sleep(1) + if block_while_ramping: + while self.temperature_state() != "stable": + sleep(self._ramp_time_resolution) def write(self, cmd: str) -> None: """ From 0cf2dc0030bc62afaa1f14904b0d83c612b2b4be Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Mon, 27 Oct 2025 13:28:59 -0700 Subject: [PATCH 04/13] Use new attribute for blocking_t sleep --- .../instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 2b2a29a97355..f0ca54b47a99 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -44,6 +44,7 @@ class DynaCool(VisaInstrument): # the ramp time resolution is in (s) and is used in the # _do_blocking_ramp method _ramp_time_resolution = 0.1 + _blocking_t_sleep = 0.5 temp_params = ("temperature_setpoint", "temperature_rate", "temperature_settling") field_params = ("field_target", "field_rate", "field_approach") @@ -423,7 +424,7 @@ def _temp_setter( if block_while_ramping: while self.temperature_state() != "stable": - sleep(self._ramp_time_resolution) + sleep(self._blocking_t_sleep) def write(self, cmd: str) -> None: """ From a06433589d69e4afc8c49b5398f57949d74c7c49 Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Fri, 2 Jan 2026 11:16:11 -0800 Subject: [PATCH 05/13] Fix bug that crashes PPMS server --- .../instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index f0ca54b47a99..0c331e13c6ca 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -89,7 +89,9 @@ def __init__( label="Block instrument while ramping temp", unit="K", vals=vals.Numbers(1.6, 400), - set_cmd=partial(self._temp_setter, "temperature_setpoint", True), + set_cmd=partial( + self._temp_setter, "temperature_setpoint", block_while_ramping=True + ), ) """Parameter blocking_t will block instrument interaction while temperature is ramping to setpoint.""" From 9f9be9f05b67efb3aad3f28a69e22f07458ba71f Mon Sep 17 00:00:00 2001 From: Thomas <56311859+trlemon@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:50:19 -0800 Subject: [PATCH 06/13] Update setpoint and blocking_t caches after calling either's set Co-authored-by: Mikhail Astafev --- .../instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 0c331e13c6ca..4c0885c22e2a 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -427,7 +427,8 @@ def _temp_setter( if block_while_ramping: while self.temperature_state() != "stable": sleep(self._blocking_t_sleep) - + self.setpoint.cache._set_from_raw_value(values[0]) + self.blocking_t.cache._set_from_raw_value(values[0]) def write(self, cmd: str) -> None: """ Since the error code is always returned, we must read it back From 2c671bb106cf87ad75b2940c69be5af900395c91 Mon Sep 17 00:00:00 2001 From: Thomas <56311859+trlemon@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:52:33 -0800 Subject: [PATCH 07/13] Make blocking_t parameter not gettable Co-authored-by: Mikhail Astafev --- .../instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 4c0885c22e2a..9f9aa7ac0adc 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -89,6 +89,7 @@ def __init__( label="Block instrument while ramping temp", unit="K", vals=vals.Numbers(1.6, 400), + get_cmd=False, set_cmd=partial( self._temp_setter, "temperature_setpoint", block_while_ramping=True ), From dd72970ca116fa3d748fa3d659caf2fc4fefcc8f Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Wed, 14 Jan 2026 12:11:58 -0800 Subject: [PATCH 08/13] Format for readability. --- .../instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 9f9aa7ac0adc..e5e6689abafe 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -428,8 +428,10 @@ def _temp_setter( if block_while_ramping: while self.temperature_state() != "stable": sleep(self._blocking_t_sleep) + self.setpoint.cache._set_from_raw_value(values[0]) self.blocking_t.cache._set_from_raw_value(values[0]) + def write(self, cmd: str) -> None: """ Since the error code is always returned, we must read it back From 243e36ed0e3ebdd3ca5c780c93b1e47c13e228bc Mon Sep 17 00:00:00 2001 From: Thomas <56311859+trlemon@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:11:18 -0800 Subject: [PATCH 09/13] Change "temp" to unabbreviated "temperature" for clarity Co-authored-by: Mikhail Astafev --- .../instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index e5e6689abafe..df7ca0b17130 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -86,7 +86,7 @@ def __init__( self.blocking_t: Parameter = self.add_parameter( "blocking_t", - label="Block instrument while ramping temp", + label="Block instrument while ramping temperature", unit="K", vals=vals.Numbers(1.6, 400), get_cmd=False, From 2ddcf1efd15767ace1c45b92e80d989c32a45d9c Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Wed, 14 Jan 2026 12:24:06 -0800 Subject: [PATCH 10/13] Add note on blocking_t to PPMS example notebook --- .../Qcodes example with DynaCool PPMS.ipynb | 788 +----------------- 1 file changed, 17 insertions(+), 771 deletions(-) diff --git a/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb b/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb index 106550749dd7..7d9c2eb639fa 100644 --- a/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb +++ b/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb @@ -157,777 +157,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\n", - "\n", - "mpl.get_websocket_type = function() {\n", - " if (typeof(WebSocket) !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof(MozWebSocket) !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert('Your browser does not have WebSocket support.' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.');\n", - " };\n", - "}\n", - "\n", - "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = (this.ws.binaryType != undefined);\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById(\"mpl-warnings\");\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent = (\n", - " \"This browser does not support binary websocket messages. \" +\n", - " \"Performance may be slow.\");\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = $('
');\n", - " this._root_extra_style(this.root)\n", - " this.root.attr('style', 'display: inline-block');\n", - "\n", - " $(parent_element).append(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", - " fig.send_message(\"send_image_mode\", {});\n", - " if (mpl.ratio != 1) {\n", - " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", - " }\n", - " fig.send_message(\"refresh\", {});\n", - " }\n", - "\n", - " this.imageObj.onload = function() {\n", - " if (fig.image_mode == 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function() {\n", - " fig.ws.close();\n", - " }\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "}\n", - "\n", - "mpl.figure.prototype._init_header = function() {\n", - " var titlebar = $(\n", - " '
');\n", - " var titletext = $(\n", - " '
');\n", - " titlebar.append(titletext)\n", - " this.root.append(titlebar);\n", - " this.header = titletext[0];\n", - "}\n", - "\n", - "\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._init_canvas = function() {\n", - " var fig = this;\n", - "\n", - " var canvas_div = $('
');\n", - "\n", - " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", - "\n", - " function canvas_keyboard_event(event) {\n", - " return fig.key_event(event, event['data']);\n", - " }\n", - "\n", - " canvas_div.keydown('key_press', canvas_keyboard_event);\n", - " canvas_div.keyup('key_release', canvas_keyboard_event);\n", - " this.canvas_div = canvas_div\n", - " this._canvas_extra_style(canvas_div)\n", - " this.root.append(canvas_div);\n", - "\n", - " var canvas = $('');\n", - " canvas.addClass('mpl-canvas');\n", - " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", - "\n", - " this.canvas = canvas[0];\n", - " this.context = canvas[0].getContext(\"2d\");\n", - "\n", - " var backingStore = this.context.backingStorePixelRatio ||\n", - "\tthis.context.webkitBackingStorePixelRatio ||\n", - "\tthis.context.mozBackingStorePixelRatio ||\n", - "\tthis.context.msBackingStorePixelRatio ||\n", - "\tthis.context.oBackingStorePixelRatio ||\n", - "\tthis.context.backingStorePixelRatio || 1;\n", - "\n", - " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband = $('');\n", - " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", - "\n", - " var pass_mouse_events = true;\n", - "\n", - " canvas_div.resizable({\n", - " start: function(event, ui) {\n", - " pass_mouse_events = false;\n", - " },\n", - " resize: function(event, ui) {\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " stop: function(event, ui) {\n", - " pass_mouse_events = true;\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " });\n", - "\n", - " function mouse_event_fn(event) {\n", - " if (pass_mouse_events)\n", - " return fig.mouse_event(event, event['data']);\n", - " }\n", - "\n", - " rubberband.mousedown('button_press', mouse_event_fn);\n", - " rubberband.mouseup('button_release', mouse_event_fn);\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband.mousemove('motion_notify', mouse_event_fn);\n", - "\n", - " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", - " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", - "\n", - " canvas_div.on(\"wheel\", function (event) {\n", - " event = event.originalEvent;\n", - " event['data'] = 'scroll'\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " mouse_event_fn(event);\n", - " });\n", - "\n", - " canvas_div.append(canvas);\n", - " canvas_div.append(rubberband);\n", - "\n", - " this.rubberband = rubberband;\n", - " this.rubberband_canvas = rubberband[0];\n", - " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", - " this.rubberband_context.strokeStyle = \"#000000\";\n", - "\n", - " this._resize_canvas = function(width, height) {\n", - " // Keep the size of the canvas, canvas container, and rubber band\n", - " // canvas in synch.\n", - " canvas_div.css('width', width)\n", - " canvas_div.css('height', height)\n", - "\n", - " canvas.attr('width', width * mpl.ratio);\n", - " canvas.attr('height', height * mpl.ratio);\n", - " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", - "\n", - " rubberband.attr('width', width);\n", - " rubberband.attr('height', height);\n", - " }\n", - "\n", - " // Set the figure to an initial 600x600px, this will subsequently be updated\n", - " // upon first draw.\n", - " this._resize_canvas(600, 600);\n", - "\n", - " // Disable right mouse context menu.\n", - " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", - " return false;\n", - " });\n", - "\n", - " function set_focus () {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "}\n", - "\n", - "mpl.figure.prototype._init_toolbar = function() {\n", - " var fig = this;\n", - "\n", - " var nav_element = $('
')\n", - " nav_element.attr('style', 'width: 100%');\n", - " this.root.append(nav_element);\n", - "\n", - " // Define a callback function for later on.\n", - " function toolbar_event(event) {\n", - " return fig.toolbar_button_onclick(event['data']);\n", - " }\n", - " function toolbar_mouse_event(event) {\n", - " return fig.toolbar_button_onmouseover(event['data']);\n", - " }\n", - "\n", - " for(var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " // put a spacer in here.\n", - " continue;\n", - " }\n", - " var button = $('');\n button.click(method_name, toolbar_event);\n button.mouseover(tooltip, toolbar_mouse_event);\n nav_element.append(button);\n }\n\n // Add the status bar.\n var status_bar = $('');\n nav_element.append(status_bar);\n this.message = status_bar[0];\n\n // Add the close button to the window.\n var buttongrp = $('
');\n var button = $('');\n button.click(function (evt) { fig.handle_close(fig, {}); } );\n button.mouseover('Stop Interaction', toolbar_mouse_event);\n buttongrp.append(button);\n var titlebar = this.root.find($('.ui-dialog-titlebar'));\n titlebar.prepend(buttongrp);\n}\n\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.figure.prototype._canvas_extra_style = function(el){\n // this is important to make the div 'focusable\n el.attr('tabindex', 0)\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n }\n else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n\n}\n\nmpl.figure.prototype._key_event_extra = function(event, name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager)\n manager = IPython.keyboard_manager;\n\n // Check for shift+enter\n if (event.shiftKey && event.which == 13) {\n this.canvas_div.blur();\n event.shiftKey = false;\n // Send a \"J\" for go to next cell\n event.which = 74;\n event.keyCode = 74;\n manager.command_mode();\n manager.handle_keydown(event);\n }\n}\n\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.find_output_cell = function(html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i=0; i= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] == html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n}\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel != null) {\n IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n}\n", "text/plain": [ "" ] @@ -966,6 +196,22 @@ "plt.ylabel(\"Temperature (K)\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternatively, you can use the `blocking_t` parameter to prevent users from taking any action until the setpoint is reached. This may be useful for measurements where you are sweeping temperature and want to ensure the temperature is stable before taking a measurement." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dynacool.blocking_t(dynacool.temperature() + 1.3)" + ] + }, { "cell_type": "markdown", "metadata": {}, From 3c074c2d024d996458b98ff315ced9e7801d10cb Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Wed, 14 Jan 2026 12:36:57 -0800 Subject: [PATCH 11/13] Convert private _blocking_t_sleep attribute to Parameter. --- .../QuantumDesign/DynaCoolPPMS/DynaCool.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index df7ca0b17130..1e3451552608 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -44,7 +44,6 @@ class DynaCool(VisaInstrument): # the ramp time resolution is in (s) and is used in the # _do_blocking_ramp method _ramp_time_resolution = 0.1 - _blocking_t_sleep = 0.5 temp_params = ("temperature_setpoint", "temperature_rate", "temperature_settling") field_params = ("field_target", "field_rate", "field_approach") @@ -96,6 +95,17 @@ def __init__( ) """Parameter blocking_t will block instrument interaction while temperature is ramping to setpoint.""" + self.blocking_t_state_check_interval: Parameter = self.add_parameter( + name="blocking_t_state_check_interval", + instrument=self, + initial_value=0.5, + unit="s", + vals=vals.Numbers(0, 60), + set_cmd=None, + get_cmd=None, + ) + """Parameter blocking_t_state_check_interval sets how often blocking_t checks for temperature stability.""" + self.temperature_rate: Parameter = self.add_parameter( "temperature_rate", label="Temperature settle rate", @@ -427,7 +437,7 @@ def _temp_setter( if block_while_ramping: while self.temperature_state() != "stable": - sleep(self._blocking_t_sleep) + sleep(self.blocking_t_state_check_interval()) self.setpoint.cache._set_from_raw_value(values[0]) self.blocking_t.cache._set_from_raw_value(values[0]) From 21a9b4365cadcc5685790571134e8d1b6c05182b Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Wed, 14 Jan 2026 12:39:38 -0800 Subject: [PATCH 12/13] Update PPMS example notebook with blocking_t state check interval --- .../driver_examples/Qcodes example with DynaCool PPMS.ipynb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb b/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb index 7d9c2eb639fa..f3a9188101dd 100644 --- a/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb +++ b/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb @@ -200,7 +200,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Alternatively, you can use the `blocking_t` parameter to prevent users from taking any action until the setpoint is reached. This may be useful for measurements where you are sweeping temperature and want to ensure the temperature is stable before taking a measurement." + "Alternatively, you can use the `blocking_t` parameter to prevent users from taking any action until the setpoint is reached. This may be useful for measurements where you are sweeping temperature and want to ensure the temperature is stable before taking a measurement.\n", + "\n", + "The interval at which `blocking_t` checks for temperature stability can be modified through the parameter `blocking_t_state_check_interval`." ] }, { @@ -209,6 +211,7 @@ "metadata": {}, "outputs": [], "source": [ + "dynacool.blocking_t_state_check_interval(0.5)\n", "dynacool.blocking_t(dynacool.temperature() + 1.3)" ] }, From c2ca63c2042af89780e4ae643c359494a436ac83 Mon Sep 17 00:00:00 2001 From: Thomas Lemon Date: Tue, 20 Jan 2026 14:19:04 -0800 Subject: [PATCH 13/13] Use bool to control blocking_t functionality in temperature_setpoint --- .../Qcodes example with DynaCool PPMS.ipynb | 7 +++--- .../QuantumDesign/DynaCoolPPMS/DynaCool.py | 22 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb b/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb index f3a9188101dd..00080a6f38df 100644 --- a/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb +++ b/docs/examples/driver_examples/Qcodes example with DynaCool PPMS.ipynb @@ -200,9 +200,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Alternatively, you can use the `blocking_t` parameter to prevent users from taking any action until the setpoint is reached. This may be useful for measurements where you are sweeping temperature and want to ensure the temperature is stable before taking a measurement.\n", + "Alternatively, you can use the `block_while_ramping_temperature` parameter to prevent users from taking any action until the setpoint is reached. This may be useful for measurements where you are sweeping temperature and want to ensure the temperature is stable before taking a measurement.\n", "\n", - "The interval at which `blocking_t` checks for temperature stability can be modified through the parameter `blocking_t_state_check_interval`." + "The interval at which `temperature_setpoint` checks for temperature stability when `block_while_ramping_temperature` is True can be modified through the parameter `blocking_t_state_check_interval`." ] }, { @@ -212,7 +212,8 @@ "outputs": [], "source": [ "dynacool.blocking_t_state_check_interval(0.5)\n", - "dynacool.blocking_t(dynacool.temperature() + 1.3)" + "dynacool.block_while_ramping_temperature(True)\n", + "dynacool.temperature_setpoint(dynacool.temperature() + 1.3)" ] }, { diff --git a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py index 1e3451552608..c02bc3922013 100644 --- a/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py +++ b/src/qcodes/instrument_drivers/QuantumDesign/DynaCoolPPMS/DynaCool.py @@ -83,17 +83,16 @@ def __init__( ) """Parameter temperature_setpoint""" - self.blocking_t: Parameter = self.add_parameter( - "blocking_t", + self.block_while_ramping_temperature: Parameter = self.add_parameter( + "block_while_ramping_temperature", label="Block instrument while ramping temperature", - unit="K", - vals=vals.Numbers(1.6, 400), + initial_value=False, + vals=vals.Bool(), get_cmd=False, - set_cmd=partial( - self._temp_setter, "temperature_setpoint", block_while_ramping=True - ), + set_cmd=False, ) - """Parameter blocking_t will block instrument interaction while temperature is ramping to setpoint.""" + """Parameter block_while_ramping_temperature, when set to True, + will block further interaction while temperature is ramping to setpoint.""" self.blocking_t_state_check_interval: Parameter = self.add_parameter( name="blocking_t_state_check_interval", @@ -104,7 +103,8 @@ def __init__( set_cmd=None, get_cmd=None, ) - """Parameter blocking_t_state_check_interval sets how often blocking_t checks for temperature stability.""" + """Parameter blocking_t_state_check_interval sets how often + temperature_setpoint checks for temperature stability when block_while_ramping_temperature is True.""" self.temperature_rate: Parameter = self.add_parameter( "temperature_rate", @@ -423,7 +423,6 @@ def _temp_setter( "temperature_setpoint", "temperature_rate", "temperature_settling" ], value: float, - block_while_ramping: bool = False, ) -> None: """ The setter function for the temperature parameters. All three are set @@ -435,12 +434,11 @@ def _temp_setter( self.write(f"TEMP {values[0]}, {values[1]}, {values[2]}") - if block_while_ramping: + if self.block_while_ramping_temperature(): while self.temperature_state() != "stable": sleep(self.blocking_t_state_check_interval()) self.setpoint.cache._set_from_raw_value(values[0]) - self.blocking_t.cache._set_from_raw_value(values[0]) def write(self, cmd: str) -> None: """