Closed qzhang234 closed 2 years ago
I noticed that when I put this function in ~/blueske_data/2021/2021-2/
and do %run -m
it would work. However when I move it in the startup scripts of Bluesky, the functions will load but the dictionary qnw_params
will not stay in the memory, hence the following te_qnw
command won't run. Any idea why?
Thanks!
I implemented a bypass in which I had select_sample
saves the sample parameters it picked into another json file to bypass the previous issue:
However, the same problem remains, namely I can run the function just fine in ~/bluesky_data
but not when I put this script in the startup scripts.
Upon inspection I noticed the problem is caused by the line in which I tried to use the string qnw_env1
to get the object qnw_env1
so that I can assign it to something else (the one with global()["_[qnw_env]"]
). Any idea why it won't work if I put it in the start up scripts?
Or should I just re-instantiate the class with the string?
Need to add qnw_params
into the __all__
list.
With %run ...
, you are loading the code into your global namespace. When you load it from the instrument package, te_qnw()
fails when it cannot find qnw_params
in the global namespace. That's what the __all__
list provides, the names of the objects to be imported by default.
Yuck! qnw_env=eval(_["qnw_env"])
Very obscure code.
Use a name rather than _
as a Python object. Unless you plan to ignore whatever is assigned to _
.
@prjemian Thanks! I'll make the changes per your suggestion.
One thing that baffled me is: If I try to access qne_env1
in my sample selection code (see pulldown tab attached), it will fall flat on my face. Something as simple as bps.mv(qnw_env1, 25)
will crash and return an error saying qnw_env1
is not defined.
At the same time, samplestage.qnw_x
was imported in the exact same way as qnw_env1
and I can run bps.mv(samplestage.qnw_x, 150)
with no problem. This has confused me the entire last night. Any idea why?
You can push the QZ_Test
branch to GitHub which will make it much easier for me to inspect the code.
In your example code, you have defined the qnw_env1
object in the file, thus it fails at:
yield from bps.mv(qnw_env1, 25)
The code succeeds with %run ...
because the symbol is defined in the global namespace of the interactive session.
You need to import
that symbol.
Something like this?
from instrument.devices.qnw_device import qnw_env1, qnw_env2, qnw_env3
Yes. If this file is in the devices
directory, then shorten it to:
from .qnw_device import qnw_env1, qnw_env2, qnw_env3
@prjemian I added qnw_params
in __all__
, however the values of qnw_params
did not update when I run RE(select_sample('sample1')
(I pushed my changes and the part of script of interest is here). Any suggestions? I guess I could always go back to writing a separate .json file but I feel like saving the dictionary in the memory is more elegant.
Another question I have is: assuming that I can read the values from qnw_params
, I would like to use the string qnw_env1
to select object that has the same name. It was done using global( )[ ] and the line of script is here. I'm not sure if this is the right way to do this. Any suggestions?
assuming that I can read the values from qnw_params, I would like to use the string qnw_env1 to select object that has the same name. It was done using global( )[ ] and the line of script is here. I'm not sure if this is the right way to do this. Any suggestions?
This is too tricky for mere mortals to understand as they try to find the source of a problem. It pays to be much more obvious.
Duly noted on the string -> object part. I'll rewrite my script.
However what about the creation of qnw_params
? Should I switch back to writing .json file?
Please advise.
See this comment above: https://github.com/aps-8id-dys/ipython-8idiuser/issues/273#issuecomment-909316934
This is the problem you report:
Since qnw_params
is being defined in select_sample()
, a new qnw_params
object is created local to the scope of this function. The function returns this new object but that action does not update the global object created on line 21. If you want to modify the object created on line 21, then the function needs this line:
global qnw_params
The global
is not necessary if you only reference the object since Python's object search starts in the function's scope, then goes to the global namespace if it is not found locally. It's different when writing a value. A new object is created locally unless you inform that the global object should be used.
That code needs other attention, too.
For example, the yield from
after the return
: https://github.com/aps-8id-dys/ipython-8idiuser/blob/458722eda77704457cc9bc5027bd4237f983ed67/profile_bluesky/startup/instrument/plans/qnw_sample_select.py#L29-L30
And this should be simplified. What is supposed to happen? https://github.com/aps-8id-dys/ipython-8idiuser/blob/458722eda77704457cc9bc5027bd4237f983ed67/profile_bluesky/startup/instrument/plans/qnw_sample_select.py#L36
Could line 36 could be changed?
qnw_env = qnw_params["qnw_env"]
If it not that simple, how can we make it that simple? Should not need such calls to get an object from globals()[]
. This type of code will cause failures with import
as you have reported.
Could line 36 could be changed?
qnw_env = qnw_params["qnw_env"]
The goal is to select which qnw_env
to control based on the string and I believe bps.mv
requires an object as input
I pushed another version to QZ_Test
. This version contains a select_sample
and te_qnw
that loads upon startup (instead of %run -m
) and work as expected.
Although I guess I could just leave it like this, I'm very curious to find out if this code can be improved since some of the actions performed here (e.g. converting string to object, passing variables from one function to another) will surely be used at other places.
Could you take a look at the script (see link here) and let me know if you have any suggestions?
Closing this issue for now as it has become outdated. Will reopen if necessary.
@prjemian I made a python script to reproduce the temperature varying and sample changing capacity in SPEC:
bp_qnw_selection.py
```python __all__ = [ 'select_sample', 'te_qnw', ] import json from bluesky import plans as bp from bluesky import plan_stubs as bps from instrument.devices import samplestage, qnw_device from instrument.session_logs import logger logger.info(__file__) qnw_params = {} def select_sample(index=None): with open('QNW_sample_definitions.json', 'r') as f: _ = json.load(f) qnw_params['sample_name']=_[index]["qnw_position"] qnw_params['samp_id_char']=_[index]["qnw_position"] qnw_params['samx_center']=_[index]["qnw_position"] qnw_params['samx_scan_halfwidth']=_[index]["samx_scan_halfwidth"] qnw_params['samx_num_points']=_[index]["samx_num_points"] qnw_params['samz_center']=_[index]["samz_center"] qnw_params['samz_scan_halfwidth']=_[index]["samz_scan_halfwidth"] qnw_params['samz_num_points']=_[index]["samz_num_points"] qnw_params['qnw_position']=_[index]["qnw_position"] qnw_params["qnw_env"] = _[index]["qnw_env"] yield from bps.mv(samplestage.qnw_x, qnw_params['qnw_position']) return qnw_params def te_qnw(set_temp=None, ramp_rate=5, temp_wait=False, tolerance=0.1): qnw_env = globals()[qnw_params["qnw_env"]] # Select object using object name (string) yield from bps.mv(qnw_env.ramprate, ramp_rate) if temp_wait is True: yield from bps.mv(qnw_env.tolerance, tolerance) yield from bps.mv(qnw_env, set_temp) if temp_wait is False: yield from bps.abs_set(qnw_env, set_temp) ```