MultiPyVu 3.3.0__tar.gz → 3.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. {multipyvu-3.3.0/src/MultiPyVu.egg-info → multipyvu-3.6.1}/PKG-INFO +69 -51
  2. {multipyvu-3.3.0 → multipyvu-3.6.1}/README.md +61 -26
  3. {multipyvu-3.3.0 → multipyvu-3.6.1}/pyproject.toml +1 -2
  4. {multipyvu-3.3.0 → multipyvu-3.6.1}/setup.py +5 -5
  5. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/BRT.py +25 -16
  6. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/CommandChamber.py +14 -10
  7. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/CommandField.py +76 -62
  8. multipyvu-3.6.1/src/MultiPyVu/CommandFieldSetPoints.py +288 -0
  9. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/CommandMultiVu.py +1 -1
  10. multipyvu-3.6.1/src/MultiPyVu/CommandRotator.py +566 -0
  11. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/CommandSdo.py +17 -13
  12. multipyvu-3.6.1/src/MultiPyVu/CommandTempSetPoints.py +248 -0
  13. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/CommandTemperature.py +31 -26
  14. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/CommandWaitFor.py +75 -9
  15. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/Command_factory.py +90 -3
  16. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/ICommand.py +33 -31
  17. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/MultiVuClient.py +116 -10
  18. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/MultiVuClient_base.py +201 -88
  19. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/MultiVuDataFile/MultiVuDataFile.py +5 -6
  20. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/MultiVuServer.py +14 -14
  21. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/SocketMessage.py +175 -159
  22. multipyvu-3.6.1/src/MultiPyVu/SocketMessageClient.py +510 -0
  23. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/SocketMessageServer.py +388 -208
  24. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/__version.py +1 -1
  25. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/exceptions.py +1 -1
  26. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/instrument.py +3 -3
  27. multipyvu-3.6.1/src/MultiPyVu/logging_config.py +76 -0
  28. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/project_vars.py +9 -2
  29. {multipyvu-3.3.0 → multipyvu-3.6.1/src/MultiPyVu.egg-info}/PKG-INFO +69 -51
  30. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu.egg-info/SOURCES.txt +3 -0
  31. multipyvu-3.3.0/src/MultiPyVu/SocketMessageClient.py +0 -290
  32. multipyvu-3.3.0/src/MultiPyVu/logging_config.py +0 -72
  33. {multipyvu-3.3.0 → multipyvu-3.6.1}/LICENSE +0 -0
  34. {multipyvu-3.3.0 → multipyvu-3.6.1}/setup.cfg +0 -0
  35. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/IEventManager.py +0 -0
  36. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/IServer.py +0 -0
  37. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/MultiVuDataFile/__init__.py +0 -0
  38. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/MultiVuDataFile/__version.py +0 -0
  39. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/MultiVuDataFile/is_pathname_valid.py +0 -0
  40. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/ParseInputs.py +0 -0
  41. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/__init__.py +0 -0
  42. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/__main__.py +0 -0
  43. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/check_windows_esc.py +0 -0
  44. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/font/Play-Bold.ttf +0 -0
  45. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/font/Play-Regular.ttf +0 -0
  46. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/font/__init__.py +0 -0
  47. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/generate_sdo_objects.py +0 -0
  48. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/gui/Controller.py +0 -0
  49. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/gui/IController.py +0 -0
  50. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/gui/IView.py +0 -0
  51. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/gui/ViewFactory.py +0 -0
  52. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/gui/ViewTk.py +0 -0
  53. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/gui/__init__.py +0 -0
  54. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/images/Q.png +0 -0
  55. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/images/QD_logo.jpg +0 -0
  56. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/images/__init__.py +0 -0
  57. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/logging_config.yaml +0 -0
  58. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/scripts/__init__.py +0 -0
  59. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/scripts/helper_scripts.py +0 -0
  60. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/scripts/whats_my_ip_address.cmd +0 -0
  61. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu/sdo_object.py +0 -0
  62. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu.egg-info/dependency_links.txt +0 -0
  63. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu.egg-info/requires.txt +0 -0
  64. {multipyvu-3.3.0 → multipyvu-3.6.1}/src/MultiPyVu.egg-info/top_level.txt +0 -0
@@ -1,47 +1,30 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: MultiPyVu
3
- Version: 3.3.0
3
+ Version: 3.6.1
4
4
  Summary: Control MultiVu using Python
5
5
  Author-email: Damon D Jackson <djackson@qdusa.com>
6
6
  Maintainer-email: "Quantum Design, Inc." <apps@qdusa.com>
7
- License: MIT License (MIT)
8
-
9
- Copyright (c) 2023 Quantum Design, Inc
10
-
11
- Permission is hereby granted, free of charge, to any person obtaining a copy
12
- of this software and associated documentation files (the "Software"), to deal
13
- in the Software without restriction, including without limitation the rights
14
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
- copies of the Software, and to permit persons to whom the Software is
16
- furnished to do so, subject to the following conditions:
17
-
18
- The above copyright notice and this permission notice shall be included in all
19
- copies or substantial portions of the Software.
20
-
21
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
- SOFTWARE.
7
+ License-Expression: MIT
28
8
  Project-URL: Quantum Design, https://qdusa.com
29
9
  Project-URL: Pharos, https://www.qdusa.com/register/account/login
30
10
  Keywords: Quantum Design,QD,MultiVu,PPMS,DynaCool,MPMS3,VersaLab,OptiCool
31
11
  Classifier: Programming Language :: Python :: 3
32
- Classifier: License :: OSI Approved :: MIT License
33
12
  Classifier: Operating System :: OS Independent
34
13
  Classifier: Intended Audience :: Science/Research
35
14
  Classifier: Topic :: Scientific/Engineering :: Physics
36
15
  Classifier: Topic :: Scientific/Engineering :: Chemistry
37
16
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
38
- Requires-Python: >=3.8
17
+ Requires-Python: >=3.7
39
18
  Description-Content-Type: text/markdown
40
19
  License-File: LICENSE
41
20
  Requires-Dist: pandas
42
21
  Requires-Dist: pywin32>=300; platform_system == "Windows"
43
22
  Requires-Dist: pillow
44
23
  Requires-Dist: pyyaml
24
+ Dynamic: license-file
25
+ Dynamic: requires-dist
26
+ Dynamic: requires-python
27
+ Dynamic: summary
45
28
 
46
29
  ![qd_logo](https://qdusa.com/images/QD_logo.png)
47
30
  # MultiPyVu
@@ -60,6 +43,7 @@ Requires-Dist: pyyaml
60
43
  * [is_steady()](#is_steady)
61
44
  * [get_aux_temperature()](#aux_therm)
62
45
  * [resistivity option](#brt)
46
+ * [horizontal rotator option](#rotator)
63
47
  * [Saving & Opening a MultiVu Data File](#save)
64
48
  * [Querying the Server Status](#server_status)
65
49
  * [Testing the Server Using Scaffolding](#scaffolding)
@@ -77,13 +61,13 @@ The components of MultiPyVu enable access to the set and read the temperature, f
77
61
 
78
62
  ### Module Requirements<a class="anchor" id="requirements"></a>
79
63
  MultiPyVu uses the following modules:
80
- - python version 3.8 or higher
64
+ - python version 3.7 or higher
81
65
  - pywin32 - version 300 or higher.
82
66
  - pandas - data read back from a *.dat* file is a Pandas Dataframe
83
67
  - pillow - supports server gui
84
68
  - pyyaml - supports logging
85
69
 
86
- For the Python 3 distribution Quantum Design recommends [Anaconda](https://www.anaconda.com/products/individual) as it includes most modules needed for this server and other packages useful for scientific computing. This code was built and tested using Python 3.8. If you are not sure which version of Python you are using, from a command prompt type:
70
+ For the Python 3 distribution Quantum Design recommends [Anaconda](https://www.anaconda.com/products/individual) as it includes most modules needed for this server and other packages useful for scientific computing. To find which version of Python is used, from a command prompt type:
87
71
  ```
88
72
  python --version
89
73
  ```
@@ -104,8 +88,10 @@ Remote Connection\example_MVDataFile_VISA.py | Simple example showing how to rou
104
88
  Data Processing\example_save_open_dat.py | Script showing how to save and read a MultiVu *.dat* file into a Pandas DataFrame, then plot with matplotlib.
105
89
  Measuring\example_stabilize.py | Measures the temperature while stabilizing at each temperature.
106
90
  Measuring\example_sweep.py | Measures the temperature while sweeping the temperature.
107
- Options\example_aux_therm.py | Gets the temperature of the auxilary thermometer from the OptiCool.
91
+ Measuring\example_get_setpoints.py | Shows how to get the temperature and magnetic field setpoints.
92
+ Options\example_aux_therm.py | Gets the temperature of the auxiliary thermometer from the OptiCool.
108
93
  Options\example_resistivity_option.py | Demonstrates how to set up the BRT module bridges for resistivity measurements and how to save the data.
94
+ Options\example_horizontal_rotator.py | Demonstrates how to move the horizontal rotator to a new position.
109
95
  UsefulBatchFiles\whats_my_ip_address.cmd | This batch file script prints out the IP address for the computer, providing an easy way to get the server IP address needed for remote operation. Alternatively, the gui can be used to get the IP address by calling ```python -m MultiPyVu```.
110
96
  UsefulBatchFiles\show_process_with_port.cmd | Shows that active processes are running and what port is being used. By default, this looks for processes running on port 5000. To query a different port number, append it to the command line arguments. ```$ show_processes_with_port.cmd 4567```
111
97
  UsefulBatchFiles\RunServer.cmd | This runs the server GUI.
@@ -138,22 +124,23 @@ $ python -m MultiPyVu -get_ip
138
124
  On the client PC, update the 'host' variable of the 'example_Remote-Client.py' script *with the same server PC IPV4 address* and run it. The script will report the present temperature and field value/status a few times to show the connection is functioning.
139
125
 
140
126
  **Next Steps:**
141
- It may sometimes be desirable to combine the sample environment parameters (temperature, field) with readings from a user's own instrumentation into a single *.dat* file which can be plotted in MultiVu. This functionality, accomplished using the MultiPyVu.DataFile module, is demonstrated using PyVISA to communicate with a VISA-compatible instrument in the 'example_MvDataFile_VISA.py' example. Note that for this routine to execute properly, the correct instrument bus/address and query string need to be updated in the script.
127
+ It may sometimes be desirable to combine the sample environment parameters (temperature, field) with readings from a user's own instrumentation into a single *.dat* file which can be plotted in MultiVu. This functionality, accomplished using the MultiPyVu.DataFile module, is demonstrated using PyVISA to communicate with a VISA-compatible instrument in the 'Remote Connection/example_MvDataFile_VISA.py' example. Note that for this routine to execute properly, the correct instrument bus/address and query string need to be updated in the script.
142
128
 
143
129
  For further information on the detailed operation of the components of the module, see the following sections.
144
130
 
145
131
  ### Using MultiPyVu.Server() and MultiPyVu.Client()<a class="anchor" id="using"></a>
146
- To start the server on localhost, open MultiVu, and then, using the example script _run_server.py_, go to a command prompt and type:
132
+ To start the server on localhost, open MultiVu, and type:
147
133
  ```cmd
148
- $ python run_server.py
134
+ $ python -m MultiPyVu
149
135
  ```
150
- The server can also be started using a gui:
136
+ One can also use the example script _run_server.py_, go to a command prompt and type:
151
137
  ```cmd
152
- $ python -m MultiPyVu
138
+ $ python run_server.py
153
139
  ```
140
+
154
141
  As mentioned above, if the client and the server are running on the same computer as MultiVu, then one can use example_local.py as a guide to set up the whole script in one file.
155
142
 
156
- There are a list of useful flags to specify settings. These can be found by typing -h, which brings up help information:
143
+ There are a list of flags to specify settings. These can be found by typing -h, which brings up help information:
157
144
  ```cmd
158
145
  $ python -m MultiPyVu -h
159
146
  ```
@@ -170,8 +157,8 @@ Both the Server and the Client are context managers, which means to write a scri
170
157
  import MultiPyVu as mpv
171
158
 
172
159
  with mpv.Client('127.0.0.1') as client:
173
- <put scripting commands here>
174
- <do post-processing once the client has been closed>
160
+ # put scripting commands here
161
+ # do post-processing once the client has been closed
175
162
  ```
176
163
 
177
164
  If the host or port are not default values (localhost and 5000, respectively), then these parameters must be specified when instantiating MultiPyVu.Client().
@@ -180,16 +167,11 @@ Alternatively, one can start a connection to the server using:
180
167
  ```python
181
168
  client = mpv.Client(host='127.0.0.1')
182
169
  client.open()
183
- <put scripting commands here>
170
+ # put scripting commands here
184
171
  client.close_client()
185
- <do post-processing once the client has been closed>
186
- ```
187
- Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block.
188
-
189
- If needed, one can turn off socket timeouts so that the client will wait indefinitely for a response from the server. To do this, set the time in seconds using the 'socket_timeout' keyword when instantiating the client, or set the time to *None* to turn off the timeout. By default, the timeout is set to one second.
190
- ```python
191
- client = mpv.Client(socket_timeout=None)
172
+ # do post-processing once the client has been closed
192
173
  ```
174
+ Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block. In addition, a client object can only connect to the server once. For a second connection, one must instantiate a new client instance.
193
175
 
194
176
  The client can also close the server directly using:
195
177
  ```python
@@ -197,14 +179,14 @@ client.close_server()
197
179
  ```
198
180
  instead of client.close_client(). Note that once this is called, the server will need to be reopened. Also, this can not be accessed from within a with-block.
199
181
 
200
- If the client and server are being run on the same computer, then one could also write one script to control them both.
182
+ If the client and server are being run on the same computer, then a single script can control them both.
201
183
  ```python
202
184
  import MultiPyVu as mpv
203
185
 
204
186
  with mpv.Server() as server:
205
187
  with mpv.Client() as client:
206
- <put scripting commands here>
207
- <do post-processing now that the client and server have been closed>
188
+ # put scripting commands here
189
+ # do post-processing now that the client and server have been closed
208
190
  ```
209
191
 
210
192
  This is convenient as it does not require running two different scripts.
@@ -237,6 +219,10 @@ The <enum_options> mode is set using the client.temperature.approach_mode enum,
237
219
  ```python
238
220
  temperature, status = client.get_temperature()
239
221
  ```
222
+ One can also retrieve the setpoint, rate, and approach mode:
223
+ ```python
224
+ temperature, rate, approach = client.get_temperature_setpoints()
225
+ ```
240
226
 
241
227
  **Field**<a class="anchor" id="field"></a>
242
228
  ```python
@@ -258,6 +244,10 @@ The field and status are read back using:
258
244
  ```python
259
245
  field, status = client.get_field()
260
246
  ```
247
+ One can also retrieve the setpoint, rate, and approach mode:
248
+ ```python
249
+ field, rate, approach, driven = client.get_field_setpoints()
250
+ ```
261
251
 
262
252
  **Chamber**<a class="anchor" id="chamber"></a>
263
253
  ```python
@@ -271,9 +261,9 @@ chamber = client.get_chamber()
271
261
  Note that this command is not used by the OptiCool.
272
262
 
273
263
  **Wait For**<a class="anchor" id="waitfor"></a>
274
- When a setting on a cryostat is configured, it will take time to reach the new set point. If desired, one can wait for the setting to become stable using the .wait_for(delay, timeout, bitmask) command. A delay will set the time in seconds after the setting is stable, which can be useful to make sure a sample has time to thermalize; timeout is the seconds until the command will give up; bitmask tells the system which settings need to be stable. This can be set using the client.subsystem enum, and multiple parameters are combined using bit-wise or. In the example below, the wait_for command will wait at least 90 seconds for the temperature, field, and chamber to stabilize, and will then immediately go on to the next command.
264
+ When a setting on a cryostat is configured, it will take time to reach the new set point. If desired, one can wait for the setting to become stable using the .wait_for(delay, timeout, bitmask) command. A delay will set the time in seconds after the setting is stable, which can be useful to make sure a sample has time to thermalize; timeout is the seconds until the command will give up; bitmask tells the system which settings need to be stable. This can be set using the waitfor handle, and multiple parameters are combined using bit-wise or. In the example below, the wait_for command will wait at least 90 seconds for the temperature, field, and chamber to stabilize, and will then immediately go on to the next command.
275
265
  ```python
276
- client.wait_for(0, 90, client.temperature.waitfor | client.field.waitfor|
266
+ client.wait_for(0, 90, client.temperature.waitfor | client.field.waitfor |
277
267
  client.chamber.waitfor)
278
268
  ```
279
269
 
@@ -316,6 +306,18 @@ client.resistivity.get_resistance(bridge_number)
316
306
  client.resistivity.get_current(bridge_number)
317
307
  ```
318
308
 
309
+ **Horizontal Rotator Option**<a class="anchor" id="rotator"></a>
310
+
311
+ For DynaCool, VersaLab, and PPMS customers with the horizontal rotator option, MultiPyVu can be used to adjust the rotator position. The option must be configured before using MultiPyVu. Note that the rate_deg_per_sec is ignored for the PPMS.
312
+
313
+ Once configured, the following commands are simple to use:
314
+ ```python
315
+ position = 374.5
316
+ rate_deg_per_sec = 100.0
317
+ client.set_position(position, rate_deg_per_sec)
318
+ pos, status = client.get_position()
319
+ ```
320
+
319
321
  ### Saving & Opening a MultiVu Data File<a class="anchor" id="save"></a>
320
322
  The MultiPyVu.Client class can be used in conjunction with 3rd party tools in order to expand the capabilities of measurements from a Quantum Design cryostat. One can set up a VISA connection to a voltmeter, for example, and then collect information while controlling the cryostat temperature, field, and chamber status. This data can be collected into a MultiVu data file using MultiPyVu.DataFile. One can also use this to read a data file into a Pandas DataFrame.
321
323
 
@@ -419,8 +421,8 @@ import MultiPyVu as mpv
419
421
 
420
422
  with mpv.Server(flags=['-s', 'DYNACOOL']) as server:
421
423
  with mpv.Client() as client:
422
- <put scripting commands here>
423
- <do post-processing now that the client and server have been closed>
424
+ # put scripting commands here
425
+ # do post-processing now that the client and server have been closed
424
426
  ```
425
427
 
426
428
  ### Troubleshooting<a class="anchor" id="troubleshooting"></a>
@@ -435,6 +437,22 @@ client = mpv.Client(port=6000)
435
437
  - A log file named QdMultiVu.log shows the traffic between the server and client which can also be useful during troubleshooting.
436
438
 
437
439
  ## Changelog<a class="anchor" id="changelog"></a>
440
+ **3.6.1**
441
+ - August 2025
442
+ - Add commands to get the temperature and field setpoints.
443
+ - Remove dependencies on the distutils module.
444
+ - Minimum python version 3.7
445
+
446
+ **3.5.4**
447
+ - June 2025
448
+ - Add the horizontal rotator option for DynaCool, VersaLab, and PPMS.
449
+
450
+ **3.4.0**
451
+ - May 2025
452
+ - Minimum python version now 3.9.
453
+ - Implemented socket handshaking to improve the reliability of the socket
454
+ communications.
455
+
438
456
  **3.3.0**
439
457
  - April 2025
440
458
  - Bugfix which didn't allow this to be run on Mac or Linux platforms.
@@ -15,6 +15,7 @@
15
15
  * [is_steady()](#is_steady)
16
16
  * [get_aux_temperature()](#aux_therm)
17
17
  * [resistivity option](#brt)
18
+ * [horizontal rotator option](#rotator)
18
19
  * [Saving & Opening a MultiVu Data File](#save)
19
20
  * [Querying the Server Status](#server_status)
20
21
  * [Testing the Server Using Scaffolding](#scaffolding)
@@ -32,13 +33,13 @@ The components of MultiPyVu enable access to the set and read the temperature, f
32
33
 
33
34
  ### Module Requirements<a class="anchor" id="requirements"></a>
34
35
  MultiPyVu uses the following modules:
35
- - python version 3.8 or higher
36
+ - python version 3.7 or higher
36
37
  - pywin32 - version 300 or higher.
37
38
  - pandas - data read back from a *.dat* file is a Pandas Dataframe
38
39
  - pillow - supports server gui
39
40
  - pyyaml - supports logging
40
41
 
41
- For the Python 3 distribution Quantum Design recommends [Anaconda](https://www.anaconda.com/products/individual) as it includes most modules needed for this server and other packages useful for scientific computing. This code was built and tested using Python 3.8. If you are not sure which version of Python you are using, from a command prompt type:
42
+ For the Python 3 distribution Quantum Design recommends [Anaconda](https://www.anaconda.com/products/individual) as it includes most modules needed for this server and other packages useful for scientific computing. To find which version of Python is used, from a command prompt type:
42
43
  ```
43
44
  python --version
44
45
  ```
@@ -59,8 +60,10 @@ Remote Connection\example_MVDataFile_VISA.py | Simple example showing how to rou
59
60
  Data Processing\example_save_open_dat.py | Script showing how to save and read a MultiVu *.dat* file into a Pandas DataFrame, then plot with matplotlib.
60
61
  Measuring\example_stabilize.py | Measures the temperature while stabilizing at each temperature.
61
62
  Measuring\example_sweep.py | Measures the temperature while sweeping the temperature.
62
- Options\example_aux_therm.py | Gets the temperature of the auxilary thermometer from the OptiCool.
63
+ Measuring\example_get_setpoints.py | Shows how to get the temperature and magnetic field setpoints.
64
+ Options\example_aux_therm.py | Gets the temperature of the auxiliary thermometer from the OptiCool.
63
65
  Options\example_resistivity_option.py | Demonstrates how to set up the BRT module bridges for resistivity measurements and how to save the data.
66
+ Options\example_horizontal_rotator.py | Demonstrates how to move the horizontal rotator to a new position.
64
67
  UsefulBatchFiles\whats_my_ip_address.cmd | This batch file script prints out the IP address for the computer, providing an easy way to get the server IP address needed for remote operation. Alternatively, the gui can be used to get the IP address by calling ```python -m MultiPyVu```.
65
68
  UsefulBatchFiles\show_process_with_port.cmd | Shows that active processes are running and what port is being used. By default, this looks for processes running on port 5000. To query a different port number, append it to the command line arguments. ```$ show_processes_with_port.cmd 4567```
66
69
  UsefulBatchFiles\RunServer.cmd | This runs the server GUI.
@@ -93,22 +96,23 @@ $ python -m MultiPyVu -get_ip
93
96
  On the client PC, update the 'host' variable of the 'example_Remote-Client.py' script *with the same server PC IPV4 address* and run it. The script will report the present temperature and field value/status a few times to show the connection is functioning.
94
97
 
95
98
  **Next Steps:**
96
- It may sometimes be desirable to combine the sample environment parameters (temperature, field) with readings from a user's own instrumentation into a single *.dat* file which can be plotted in MultiVu. This functionality, accomplished using the MultiPyVu.DataFile module, is demonstrated using PyVISA to communicate with a VISA-compatible instrument in the 'example_MvDataFile_VISA.py' example. Note that for this routine to execute properly, the correct instrument bus/address and query string need to be updated in the script.
99
+ It may sometimes be desirable to combine the sample environment parameters (temperature, field) with readings from a user's own instrumentation into a single *.dat* file which can be plotted in MultiVu. This functionality, accomplished using the MultiPyVu.DataFile module, is demonstrated using PyVISA to communicate with a VISA-compatible instrument in the 'Remote Connection/example_MvDataFile_VISA.py' example. Note that for this routine to execute properly, the correct instrument bus/address and query string need to be updated in the script.
97
100
 
98
101
  For further information on the detailed operation of the components of the module, see the following sections.
99
102
 
100
103
  ### Using MultiPyVu.Server() and MultiPyVu.Client()<a class="anchor" id="using"></a>
101
- To start the server on localhost, open MultiVu, and then, using the example script _run_server.py_, go to a command prompt and type:
104
+ To start the server on localhost, open MultiVu, and type:
102
105
  ```cmd
103
- $ python run_server.py
106
+ $ python -m MultiPyVu
104
107
  ```
105
- The server can also be started using a gui:
108
+ One can also use the example script _run_server.py_, go to a command prompt and type:
106
109
  ```cmd
107
- $ python -m MultiPyVu
110
+ $ python run_server.py
108
111
  ```
112
+
109
113
  As mentioned above, if the client and the server are running on the same computer as MultiVu, then one can use example_local.py as a guide to set up the whole script in one file.
110
114
 
111
- There are a list of useful flags to specify settings. These can be found by typing -h, which brings up help information:
115
+ There are a list of flags to specify settings. These can be found by typing -h, which brings up help information:
112
116
  ```cmd
113
117
  $ python -m MultiPyVu -h
114
118
  ```
@@ -125,8 +129,8 @@ Both the Server and the Client are context managers, which means to write a scri
125
129
  import MultiPyVu as mpv
126
130
 
127
131
  with mpv.Client('127.0.0.1') as client:
128
- <put scripting commands here>
129
- <do post-processing once the client has been closed>
132
+ # put scripting commands here
133
+ # do post-processing once the client has been closed
130
134
  ```
131
135
 
132
136
  If the host or port are not default values (localhost and 5000, respectively), then these parameters must be specified when instantiating MultiPyVu.Client().
@@ -135,16 +139,11 @@ Alternatively, one can start a connection to the server using:
135
139
  ```python
136
140
  client = mpv.Client(host='127.0.0.1')
137
141
  client.open()
138
- <put scripting commands here>
142
+ # put scripting commands here
139
143
  client.close_client()
140
- <do post-processing once the client has been closed>
141
- ```
142
- Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block.
143
-
144
- If needed, one can turn off socket timeouts so that the client will wait indefinitely for a response from the server. To do this, set the time in seconds using the 'socket_timeout' keyword when instantiating the client, or set the time to *None* to turn off the timeout. By default, the timeout is set to one second.
145
- ```python
146
- client = mpv.Client(socket_timeout=None)
144
+ # do post-processing once the client has been closed
147
145
  ```
146
+ Using the above method could end up with the server hung up because errors need to be correctly accounted for. It is safer to use the Client as a context manager using a with-block. In addition, a client object can only connect to the server once. For a second connection, one must instantiate a new client instance.
148
147
 
149
148
  The client can also close the server directly using:
150
149
  ```python
@@ -152,14 +151,14 @@ client.close_server()
152
151
  ```
153
152
  instead of client.close_client(). Note that once this is called, the server will need to be reopened. Also, this can not be accessed from within a with-block.
154
153
 
155
- If the client and server are being run on the same computer, then one could also write one script to control them both.
154
+ If the client and server are being run on the same computer, then a single script can control them both.
156
155
  ```python
157
156
  import MultiPyVu as mpv
158
157
 
159
158
  with mpv.Server() as server:
160
159
  with mpv.Client() as client:
161
- <put scripting commands here>
162
- <do post-processing now that the client and server have been closed>
160
+ # put scripting commands here
161
+ # do post-processing now that the client and server have been closed
163
162
  ```
164
163
 
165
164
  This is convenient as it does not require running two different scripts.
@@ -192,6 +191,10 @@ The <enum_options> mode is set using the client.temperature.approach_mode enum,
192
191
  ```python
193
192
  temperature, status = client.get_temperature()
194
193
  ```
194
+ One can also retrieve the setpoint, rate, and approach mode:
195
+ ```python
196
+ temperature, rate, approach = client.get_temperature_setpoints()
197
+ ```
195
198
 
196
199
  **Field**<a class="anchor" id="field"></a>
197
200
  ```python
@@ -213,6 +216,10 @@ The field and status are read back using:
213
216
  ```python
214
217
  field, status = client.get_field()
215
218
  ```
219
+ One can also retrieve the setpoint, rate, and approach mode:
220
+ ```python
221
+ field, rate, approach, driven = client.get_field_setpoints()
222
+ ```
216
223
 
217
224
  **Chamber**<a class="anchor" id="chamber"></a>
218
225
  ```python
@@ -226,9 +233,9 @@ chamber = client.get_chamber()
226
233
  Note that this command is not used by the OptiCool.
227
234
 
228
235
  **Wait For**<a class="anchor" id="waitfor"></a>
229
- When a setting on a cryostat is configured, it will take time to reach the new set point. If desired, one can wait for the setting to become stable using the .wait_for(delay, timeout, bitmask) command. A delay will set the time in seconds after the setting is stable, which can be useful to make sure a sample has time to thermalize; timeout is the seconds until the command will give up; bitmask tells the system which settings need to be stable. This can be set using the client.subsystem enum, and multiple parameters are combined using bit-wise or. In the example below, the wait_for command will wait at least 90 seconds for the temperature, field, and chamber to stabilize, and will then immediately go on to the next command.
236
+ When a setting on a cryostat is configured, it will take time to reach the new set point. If desired, one can wait for the setting to become stable using the .wait_for(delay, timeout, bitmask) command. A delay will set the time in seconds after the setting is stable, which can be useful to make sure a sample has time to thermalize; timeout is the seconds until the command will give up; bitmask tells the system which settings need to be stable. This can be set using the waitfor handle, and multiple parameters are combined using bit-wise or. In the example below, the wait_for command will wait at least 90 seconds for the temperature, field, and chamber to stabilize, and will then immediately go on to the next command.
230
237
  ```python
231
- client.wait_for(0, 90, client.temperature.waitfor | client.field.waitfor|
238
+ client.wait_for(0, 90, client.temperature.waitfor | client.field.waitfor |
232
239
  client.chamber.waitfor)
233
240
  ```
234
241
 
@@ -271,6 +278,18 @@ client.resistivity.get_resistance(bridge_number)
271
278
  client.resistivity.get_current(bridge_number)
272
279
  ```
273
280
 
281
+ **Horizontal Rotator Option**<a class="anchor" id="rotator"></a>
282
+
283
+ For DynaCool, VersaLab, and PPMS customers with the horizontal rotator option, MultiPyVu can be used to adjust the rotator position. The option must be configured before using MultiPyVu. Note that the rate_deg_per_sec is ignored for the PPMS.
284
+
285
+ Once configured, the following commands are simple to use:
286
+ ```python
287
+ position = 374.5
288
+ rate_deg_per_sec = 100.0
289
+ client.set_position(position, rate_deg_per_sec)
290
+ pos, status = client.get_position()
291
+ ```
292
+
274
293
  ### Saving & Opening a MultiVu Data File<a class="anchor" id="save"></a>
275
294
  The MultiPyVu.Client class can be used in conjunction with 3rd party tools in order to expand the capabilities of measurements from a Quantum Design cryostat. One can set up a VISA connection to a voltmeter, for example, and then collect information while controlling the cryostat temperature, field, and chamber status. This data can be collected into a MultiVu data file using MultiPyVu.DataFile. One can also use this to read a data file into a Pandas DataFrame.
276
295
 
@@ -374,8 +393,8 @@ import MultiPyVu as mpv
374
393
 
375
394
  with mpv.Server(flags=['-s', 'DYNACOOL']) as server:
376
395
  with mpv.Client() as client:
377
- <put scripting commands here>
378
- <do post-processing now that the client and server have been closed>
396
+ # put scripting commands here
397
+ # do post-processing now that the client and server have been closed
379
398
  ```
380
399
 
381
400
  ### Troubleshooting<a class="anchor" id="troubleshooting"></a>
@@ -390,6 +409,22 @@ client = mpv.Client(port=6000)
390
409
  - A log file named QdMultiVu.log shows the traffic between the server and client which can also be useful during troubleshooting.
391
410
 
392
411
  ## Changelog<a class="anchor" id="changelog"></a>
412
+ **3.6.1**
413
+ - August 2025
414
+ - Add commands to get the temperature and field setpoints.
415
+ - Remove dependencies on the distutils module.
416
+ - Minimum python version 3.7
417
+
418
+ **3.5.4**
419
+ - June 2025
420
+ - Add the horizontal rotator option for DynaCool, VersaLab, and PPMS.
421
+
422
+ **3.4.0**
423
+ - May 2025
424
+ - Minimum python version now 3.9.
425
+ - Implemented socket handshaking to improve the reliability of the socket
426
+ communications.
427
+
393
428
  **3.3.0**
394
429
  - April 2025
395
430
  - Bugfix which didn't allow this to be run on Mac or Linux platforms.
@@ -15,10 +15,9 @@ maintainers = [
15
15
  { name = "Quantum Design, Inc.", email = "apps@qdusa.com" },
16
16
  ]
17
17
  readme = "README.md"
18
- license = {file = "LICENSE"}
18
+ license = "MIT"
19
19
  classifiers = [
20
20
  "Programming Language :: Python :: 3",
21
- "License :: OSI Approved :: MIT License",
22
21
  "Operating System :: OS Independent",
23
22
  "Intended Audience :: Science/Research",
24
23
  "Topic :: Scientific/Engineering :: Physics",
@@ -5,12 +5,12 @@ https://packaging.python.org/guides/distributing-packages-using-setuptools/
5
5
  https://github.com/pypa/sampleproject
6
6
  """
7
7
 
8
- # Always prefer setuptools over distutils
9
- from setuptools import setup, find_packages
10
- import pathlib
11
8
  import codecs
12
9
  import os.path
10
+ import pathlib
13
11
 
12
+ # Always prefer setuptools over distutils
13
+ from setuptools import find_packages, setup
14
14
 
15
15
  here = pathlib.Path(__file__).parent.resolve()
16
16
 
@@ -51,11 +51,11 @@ setup(
51
51
  "logging_config.yaml"
52
52
  ]
53
53
  },
54
- python_requires=">=3.8",
54
+ python_requires=">=3.7",
55
55
  install_requires=[
56
56
  "pandas",
57
57
  "pywin32>=300; platform_system=='Windows'",
58
58
  "pillow",
59
- "pyyaml",
59
+ "pyyaml"
60
60
  ],
61
61
  )
@@ -20,6 +20,23 @@ class Brt():
20
20
  self.client = client
21
21
  self.stabilize_time = 5
22
22
 
23
+ def _make_bridge_number_error(self, bridge_number: int) -> str:
24
+ """
25
+ This creates a simple error message saying that the
26
+ selected bridge number is out of range
27
+
28
+ Arguments:
29
+ bridge_number
30
+
31
+ Returns:
32
+ error message
33
+ """
34
+ msg = 'bridge_number must be 1, 2, or 3 '
35
+ # Note that python version 3.7 does not allow formatting
36
+ # strings using {bridge_number = }
37
+ msg += f'(bridge_number = {bridge_number})'
38
+ return msg
39
+
23
40
  def bridge_setup(self,
24
41
  bridge_number: int,
25
42
  channel_on: bool,
@@ -74,8 +91,7 @@ class Brt():
74
91
 
75
92
  sdo = enable_sdo.get(bridge_number, None)
76
93
  if sdo is None:
77
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
78
- raise ValueError(msg)
94
+ raise ValueError(self._make_bridge_number_error(bridge_number))
79
95
  self.client._set_sdo(sdo, int(enable))
80
96
  # Pause to let the SDO go through. The pause time is
81
97
  # somewhat arbitrary.
@@ -113,8 +129,7 @@ class Brt():
113
129
 
114
130
  sdo = const_current_sdo.get(bridge_number, None)
115
131
  if sdo is None:
116
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
117
- raise ValueError(msg)
132
+ raise ValueError(self._make_bridge_number_error(bridge_number))
118
133
  self.client._set_sdo(sdo, int(const_current))
119
134
  for timeout in range(0, 4):
120
135
  time.sleep(0.6)
@@ -149,8 +164,7 @@ class Brt():
149
164
 
150
165
  sdo = resistance.get(bridge_number, None)
151
166
  if sdo is None:
152
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
153
- raise ValueError(msg)
167
+ raise ValueError(self._make_bridge_number_error(bridge_number))
154
168
  res, status = self.client._get_sdo(sdo)
155
169
  return float(res), status
156
170
 
@@ -181,8 +195,7 @@ class Brt():
181
195
 
182
196
  sdo = current.get(bridge_number, None)
183
197
  if sdo is None:
184
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
185
- raise ValueError(msg)
198
+ raise ValueError(self._make_bridge_number_error(bridge_number))
186
199
  res, status = self.client._get_sdo(sdo)
187
200
  return float(res), status
188
201
 
@@ -222,8 +235,7 @@ class Brt():
222
235
 
223
236
  sdo = current_sdo.get(bridge_number, None)
224
237
  if sdo is None:
225
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
226
- raise ValueError(msg)
238
+ raise ValueError(self._make_bridge_number_error(bridge_number))
227
239
  self.client._set_sdo(sdo, current_uA)
228
240
  # Put in constant current mode
229
241
  self._constant_current(bridge_number, True)
@@ -265,8 +277,7 @@ class Brt():
265
277
 
266
278
  sdo = current_sdo.get(bridge_number, None)
267
279
  if sdo is None:
268
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
269
- raise ValueError(msg)
280
+ raise ValueError(self._make_bridge_number_error(bridge_number))
270
281
  self.client._set_sdo(sdo, current_uA)
271
282
 
272
283
  def power_limit(self, bridge_number: int, power_uW: float) -> None:
@@ -306,8 +317,7 @@ class Brt():
306
317
 
307
318
  sdo = current_sdo.get(bridge_number, None)
308
319
  if sdo is None:
309
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
310
- raise ValueError(msg)
320
+ raise ValueError(self._make_bridge_number_error(bridge_number))
311
321
  self.client._set_sdo(sdo, power_uW)
312
322
 
313
323
  def voltage_limit(self, bridge_number: int, voltage_mV: float) -> None:
@@ -347,8 +357,7 @@ class Brt():
347
357
 
348
358
  sdo = current_sdo.get(bridge_number, None)
349
359
  if sdo is None:
350
- msg = f'bridge_number must be 1, 2, or 3 ({bridge_number = })'
351
- raise ValueError(msg)
360
+ raise ValueError(self._make_bridge_number_error(bridge_number))
352
361
  self.client._set_sdo(sdo, voltage_mV)
353
362
 
354
363
  # This works, but is not used for the resistivity option, so currently commented out