Scope of this guide
This guide will teach you how to read and write simulacrum data using the services you started in How to Start up Simulacum
In the background, you will understand the context in which caget and caput can help us develop simulacrum models at SLAC.
In the instructions, you will learn how to use caput and caget commands. You will also learn the limitations of these commands.
This will prepare you for the next chapter, which discusses putter functions in depth: Simulating PVs 2: putter functions
How to read this guide
Green text means you should be typing it into your terminal/file as the bullet point specifies. E.g., source ENV
Since some commands will be specific to your computer, text in arrow brackets will describe fields where you have to supply your own customization. E.g., <your name here>
Background
By now, you have gotten copies of existing simulacrum code and you have started up simulacrum yourself. However, you've probably noticed that simulacrum services don't output anything on their own. At the time of writing, simulacrum is not widely integrated with any matlab GUIs (graphical user interfaces). There are no buttons or switches we can press to operate the simulation. We need to ask for output manually! Furthermore, we need manual input commands to prompt changes to our device. Caget and caput commands allow us to update PVs in real time with our simulation.
Sometimes, we need to run a single interaction in our service to see if simulacrum is handling input correctly. We'll use the magnet service and quadrupole as an example. Since every quadrupole receives the same instructions from the magnet service, we can pick a single quadrupole to run a little input/output simulation. You can do this for any existing simulacrum service, or use this as a guide to start adding PV behavior to your own! This chapter will focus on caput and caget commands to run a simple simulation. In the next chapter, we will learn how input commands can trigger more complex behavior.
Instructions
I am running the model service in the background with the cu_hxr beampath and no jitter. For help setting up your terminal, refer to How to Start up Simulacum. We are going to edit the B-value of a quadrupole using caput, then check our work using caget.
Open up your magnet service on your preferred text editor to follow along. The very first class, the PVGroup, should be your first destination when you're deciding how to run a simulation. Here, you'll find the list of PVs that it models as well as the format of those PVs. In the magnet service, you'll notice that the PVGroup has many versions of the B-value. This is a sneak preview for the next chapter, where we will discuss more complex simulations that can arise from user input. For now, let's keep it simple with bdes, or B-"desired". It’s common for some PVs to include a “des” or “desired” placeholder in addition to the “act” or “actual” value present in the simulation.There are many reasons why an operator may want to write a placeholder without immediately triggering a change to the model. For our purposes, the "desired" value of B is a good example to talk about what runs when you call caget or caput.
Below, we see where our PV is first defined. We know that bdes has a float value of 0.0. This tells us that bdes outputs a float number, and defaults to 0.0 when no other information is given from the model service. We are trying to be as generic as possible here, so values are 0.0 unless they have a known constant in all situations. The __init__ of this class will assign actual modeled values to these PVs. We also know that the suffix for this PV is ":BDES". This will become important when we write our caput/caget commands. Finally, we notice that bdes lacks a "read_only=True" statement, meaning that this is a read/write PV. Read-only values may be physical constants (e.g., the uniform length of a cavity) or outputs from our accelerator model (e.g., B-"actual", bact) that it wouldn't make sense for the user to assert. Now we know that it is possible to read and write numerical float values for bdes. Crucially, this is not where we should write any functions besides pvproperty.
Fig. 1: Lines 18-24 of magnet_service.py
Further down in the PVGroup class, we can find where PVs initialize their values for specific instances. The __init__ is called with a data set already completed, called initial_value. Don't worry about where that came from for now. Instead, just understand that the __init__ of PVGroup is where each quadrupole acquires the values that the model generated for it, or that the user input manually. This is one destination for our caput command!
Fig. 2: Lines 51-61 of magnet_service.py
Some PVs may also have a putter function! While not required in order to write to a PV, this function allows us to manipulate what happens as a result of changes to a given PV.
Fig. 3: Lines 159-165 of magnet_service.py. (Note: There is some redundant syntax here! "return value" may be written simply as "return;")
The body of the putter function will become more important in the next chapter, but for now you can read the putter function as follows:
Fig. 4: Condensed putter function for bdes from the magnet_service.py
We don't care about whatever was inside the body of the putter function because we only care about changes to bdes, not changes to other PVs as a result of bdes. Hence, this condensed version removed the body entirely. Save a copy of the magnet service with the edited putter function. Call it magnet_service_edited.py
We are ready to run caget and caput! If you have edited your magnet service, you will need to type ps -ef | grep <your fastx username> to make sure you are not running another version of the magnet service in the background. Start up magnet_service_edited.py in the background.
Fig. 5: Starting up my edited magnet service. I had some unexpected error messages! In this case, it looks like some devices have been renamed or added to the database, so simulacrum can't find them. You shouldn't worry about this unless the devices listed are integral to your simulation.
I have looked up cu_hxr quadrupoles on the Oracle database and picked out QA11 to run my simulation. The control system name is QUAD:LI21:131. Refer to my short guide Looking Up Devices to learn how to look up your own example on the Oracle database.
With the magnet service and the model service running in the background, I should be able to type new commands into my terminal.
- caget QUAD:LI21:131:BDES
- I am looking up the current value of bdes for this quadrupole. I have concatenated the control system name "QUAD:LI21:131" with the suffix that was specified in the PVGroup class, ":BDES", to form the name of my PV.
Fig. 6: Despite being defined initially as 0.0 in our magnet service, the model service has already simulated a better value for bdes! In this case, it has actually retained the value I wrote to it in my last session.
- caput QUAD:LI21:131:BDES -2.6
- caget QUAD:LI21:131:BDES
- Writing a new value to bdes, then checking that it has worked!
- Writing a new value to bdes, then checking that it has worked!
Fig. 7: We have print statements resulting from edits to the putter function! Note that there are "Old..." and "New..." print statements that we did not put in ourselves. These should print by default, even if we removed the putter function entirely. The new value for bdes was verified by another caget command.
In conclusion, user input to some PVs can be done with a caput command. Reading the value of a PV from your terminal can be done with a caget command. You should check out the PVGroup class and the putter function for your desired PV, if such a putter function exists. Putter functions can be removed entirely for operations involving a single PV, but are essential for multi-PV behavior in the next chapter. We can add print statements to putter functions, which will help us resolve bugs when we start writing putters that chain-react off of each other.