|
|
Actions are the method used to get instructions into Pulse and direct a physiology model to change. The physiology model is dependent on the model implementation, while an action is generic and usually associated with a general procedure done to the patient. An engine is free to interpret and modify its models according to the intent of the action and the data it provides.
|
|
|
Actions are the method used to get instructions into Pulse and direct a physiology model to change. The physiology model is dependent on the model implementation, while an action is generic and usually associated with a general procedure done to the patient. An engine is free to interpret and modify its models according to the intent of the action and the data it provides.
|
|
|
|
|
|
In this post, we will discuss how to create the infrastructure to design and implement a new action in the Common Data Model so it can be included in a scenario and used by Pulse integrators. We will also look at how a physiology modeler can use the action in their methodology implementation.
|
|
|
In this post, we will discuss how to create the infrastructure to design and implement a new action in the Common Data Model so it can be included in a scenario and used by Pulse integrators. We will also look at how a physiology modeler can use the action in their methodology implementation.
|
|
|
|
|
|
Create the Common Data Model Action Proto buffer
|
|
|
------------------------------------------------
|
|
|
You will need to define the data structure for your action. The data structures are defined in google protocol buffers. The actions structures are organized by the object the action takes place on. The following files are where we define actions associated with various objects.
|
|
|
## Create the Common Data Model Action Proto buffer
|
|
|
|
|
|
* [Anesthesia Machine Actions](https://gitlab.kitware.com/physiology/engine/blob/master/schema/proto/cdm/AnesthesiaMachineActions.proto)
|
|
|
* [Environment Actions](https://gitlab.kitware.com/physiology/engine/blob/master/schema/proto/cdm/EnvironmentActions.proto)
|
|
|
* [Inhaler Actions](https://gitlab.kitware.com/physiology/engine/blob/master/schema/proto/cdm/InhalerActions.proto)
|
|
|
* [Patient Actions](https://gitlab.kitware.com/physiology/engine/blob/master/schema/proto/cdm/PatientActions.proto)
|
|
|
You will need to define the data structure for your action. The data structures are defined in Google Protocol Buffers. The action structures are organized by the object on which the action takes place. The following files are where we define actions associated with various objects.
|
|
|
|
|
|
For this discussion, we will look at adding a patient action, but the same principles can be applied to other object related actions.
|
|
|
* [Anesthesia Machine Actions](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/schema/pulse/cdm/bind/AnesthesiaMachineActions.proto)
|
|
|
* [Bag Valve Mask Actions](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/schema/pulse/cdm/bind/BagValveMask.proto)
|
|
|
* [Environment Actions](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/schema/pulse/cdm/bind/EnvironmentActions.proto)
|
|
|
* [Inhaler Actions](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/schema/pulse/cdm/bind/Inhaler.proto)
|
|
|
* [Mechanical Ventilator Actions](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/schema/pulse/cdm/bind/MechanicalVentilatorActions.proto)
|
|
|
* [Patient Actions](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/schema/pulse/cdm/bind/PatientActions.proto)
|
|
|
|
|
|
Open this PatientActions.proto file in your favorite editor and add the following. (Typically we strive to keep the actions in alphabetical order)
|
|
|
Note the naming convention is to end each data structure with ``Data``
|
|
|
For this discussion, we will look at adding a patient action, but the same principles can be applied to other object-related actions.
|
|
|
|
|
|
```
|
|
|
Open this PatientActions.proto file in your favorite editor and add the following. (Typically we strive to keep the actions in alphabetical order) Note the naming convention is to end each data structure with `Data`
|
|
|
|
|
|
```plaintext
|
|
|
message MyNewActionData
|
|
|
{
|
|
|
// Set the first field to be the encapsulation of the base class
|
... | ... | @@ -27,48 +28,60 @@ message MyNewActionData |
|
|
}
|
|
|
```
|
|
|
|
|
|
Next, add your new action object to the list of available patient actions.
|
|
|
Next, add your new action object to the list of available patient actions.
|
|
|
|
|
|
```
|
|
|
```plaintext
|
|
|
message AnyPatientActionData
|
|
|
{
|
|
|
oneof Action
|
|
|
{
|
|
|
PatientAssessmentRequestData Assessment = 1;
|
|
|
AcuteStressData AcuteStress = 2;
|
|
|
AirwayObstructionData AirwayObstruction = 3;
|
|
|
ApneaData Apnea = 4;
|
|
|
AsthmaAttackData AsthmaAttack = 5;
|
|
|
BrainInjuryData BrainInjury = 6;
|
|
|
BronchoconstrictionData Bronchoconstriction = 7;
|
|
|
CardiacArrestData CardiacArrest = 8;
|
|
|
ChestCompressionForceData ChestCompressionForce = 9;
|
|
|
ChestCompressionForceScaleData ChestCompressionForceScale = 10;
|
|
|
ChestOcclusiveDressingData ChestOcclusiveDressing = 11;
|
|
|
ConsciousRespirationData ConsciousRespiration = 12;
|
|
|
ConsumeNutrientsData ConsumeNutrients = 13;
|
|
|
ExerciseData Exercise = 14;
|
|
|
HemorrhageData Hemorrhage = 15;
|
|
|
IntubationData Intubation = 16;
|
|
|
MechanicalVentilationData MechanicalVentilation = 17;
|
|
|
NeedleDecompressionData NeedleDecompression = 18;
|
|
|
PericardialEffusionData PericardialEffusion = 19;
|
|
|
TensionPneumothoraxData TensionPneumothorax = 20;
|
|
|
SubstanceBolusData SubstanceBolus = 21;
|
|
|
SubstanceCompoundInfusionData SubstanceCompoundInfusion = 22;
|
|
|
SubstanceInfusionData SubstanceInfusion = 23;
|
|
|
UrinateData Urinate = 24;
|
|
|
PatientAssessmentRequestData Assessment = 1;
|
|
|
AcuteRespiratoryDistressSyndromeExacerbationData AcuteRespiratoryDistressSyndromeExacerbation = 2;
|
|
|
AcuteStressData AcuteStress = 3;
|
|
|
AirwayObstructionData AirwayObstruction = 4;
|
|
|
ArrhythmiaData Arrhythmia = 5;
|
|
|
AsthmaAttackData AsthmaAttack = 6;
|
|
|
BrainInjuryData BrainInjury = 7;
|
|
|
BronchoconstrictionData Bronchoconstriction = 8;
|
|
|
ChestCompressionData ChestCompression = 9;
|
|
|
ChestCompressionAutomatedData ChestCompressionAutomated = 10;
|
|
|
ChestCompressionInstantaneousData ChestCompressionInstantaneous = 11;
|
|
|
ChestOcclusiveDressingData ChestOcclusiveDressing = 12;
|
|
|
ChronicObstructivePulmonaryDiseaseExacerbationData ChronicObstructivePulmonaryDiseaseExacerbation = 13;
|
|
|
ConsciousRespirationData ConsciousRespiration = 14;
|
|
|
ConsumeNutrientsData ConsumeNutrients = 15;
|
|
|
DyspneaData Dyspnea = 16;
|
|
|
ExerciseData Exercise = 17;
|
|
|
HemorrhageData Hemorrhage = 18;
|
|
|
HemothoraxData Hemothorax = 19;
|
|
|
ImpairedAlveolarExchangeExacerbationData ImpairedAlveolarExchangeExacerbation = 20;
|
|
|
IntubationData Intubation = 21;
|
|
|
MechanicalVentilationData MechanicalVentilation = 22;
|
|
|
NeedleDecompressionData NeedleDecompression = 23;
|
|
|
PericardialEffusionData PericardialEffusion = 24;
|
|
|
PneumoniaExacerbationData PneumoniaExacerbation = 25;
|
|
|
PulmonaryShuntExacerbationData PulmonaryShuntExacerbation = 26;
|
|
|
RespiratoryFatigueData RespiratoryFatigue = 27;
|
|
|
RespiratoryMechanicsConfigurationData RespiratoryMechanicsConfiguration = 28;
|
|
|
SubstanceBolusData SubstanceBolus = 29;
|
|
|
SubstanceCompoundInfusionData SubstanceCompoundInfusion = 30;
|
|
|
SubstanceInfusionData SubstanceInfusion = 31;
|
|
|
SupplementalOxygenData SupplementalOxygen = 32;
|
|
|
TensionPneumothoraxData TensionPneumothorax = 33;
|
|
|
TubeThoracostomyData TubeThoracostomy = 34;
|
|
|
UrinateData Urinate = 35;
|
|
|
|
|
|
// Set this property to a large number, if you do submit this new action
|
|
|
// As a merge request into the master branch, we will assign it a new id
|
|
|
// And properly integrate it into the system
|
|
|
MyNewActionData MyNewAction = 1001;
|
|
|
MyNewActionData MyNewAction = 1001;
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
With our changes in place, we will need to generate the appropriate bindings classes.
|
|
|
From the <path/to/pulse/build>/install/bin directory run the following command:
|
|
|
```
|
|
|
|
|
|
With our changes in place, we will need to generate the appropriate bindings classes. From the \<path/to/pulse/build\>/install/bin directory run the following command:
|
|
|
|
|
|
```plaintext
|
|
|
cmake -DTYPE:STRING=protoc -P run.cmake
|
|
|
# There is also .bat and .sh scripts to make this a little easier
|
|
|
# On windows, you can type
|
... | ... | @@ -77,22 +90,20 @@ run protoc |
|
|
./run.sh protoc
|
|
|
```
|
|
|
|
|
|
Create the Common Data Model C++ Action
|
|
|
---------------------------------------
|
|
|
Now we are ready to create the C++ files specific to this action class.
|
|
|
The easiest thing to do is to create copies of [engine/cdm/cpp/patient/actions/SEAcuteStress.h](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/patient/actions/SEAcuteStress.h) and [engine/cdm/cpp/patient/actions/SEAcuteStress.cpp](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/patient/actions/SEAcuteStress.cpp) files and rename them to SE``your_action_name``.h/.cpp Then replace the string ``AcuteStress`` with the name of your action, then create the properties to match your action protobuf structure. Note the naming convention is to start each file and class name with ``SE``
|
|
|
## Create the Common Data Model C++ Action
|
|
|
|
|
|
Now we are ready to create the C++ files specific to this action class. The easiest thing to do is to create copies of [engine/src/cpp/cdm/patient/actions/SEAcuteStress.h](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/cpp/cdm/patient/actions/SEAcuteStress.h) and [engine/src/cpp/cdm/patient/actions/SEAcuteStress.cpp](https://gitlab.kitware.com/physiology/engine/-/blob/stable/src/cpp/cdm/patient/actions/SEAcuteStress.cpp) files and rename them to SE`your_action_name`.h/.cpp Then replace the string `AcuteStress` with the name of your action, then create the properties to match your action Protobuf structure. Note the naming convention is to start each file and class name with `SE`
|
|
|
|
|
|
## Add the Serialization Support for your Action Class
|
|
|
|
|
|
Add the Serialization Support for your Action Class
|
|
|
---------------------------------------------------
|
|
|
All CDM classes support serialization to and from a binding class.
|
|
|
You will need to update the appropriate binding class for your action type.
|
|
|
All CDM classes support serialization to and from a binding class. You will need to update the appropriate binding class for your action type.
|
|
|
|
|
|
**Headers**
|
|
|
|
|
|
* [Anesthesia Machine Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBAnesthesiaMachineActions.h)
|
|
|
* [Environment Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBEnvironmentActions.h)
|
|
|
* [Inhaler Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBInhalerActions.h)
|
|
|
* [Patient Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBInhalerActions.h)
|
|
|
* [Patient Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBInhalerActions.h)
|
|
|
|
|
|
In our example, for adding a patient action we will add something like the following code to the appropriate header
|
|
|
|
... | ... | @@ -112,12 +123,11 @@ static void Copy(const SEMyNewAction& src, SEMyNewAction& dst); |
|
|
* [Anesthesia Machine Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBAnesthesiaMachineActions.cpp)
|
|
|
* [Environment Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBEnvironmentActions.cpp)
|
|
|
* [Inhaler Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBInhalerActions.cpp)
|
|
|
* [Patient Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBInhalerActions.cpp)
|
|
|
* [Patient Action](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/io/protobuf/PBInhalerActions.cpp)
|
|
|
|
|
|
Implement the newly added methods. I suggest you just copy another action class method set and use the correct class names.
|
|
|
|
|
|
The Serialization class is also responsible for translating the action object to and from the AnyAction object.
|
|
|
You will need to update the following methods to ensure generic action support.
|
|
|
The Serialization class is also responsible for translating the action object to and from the AnyAction object. You will need to update the following methods to ensure generic action support.
|
|
|
|
|
|
```cpp
|
|
|
|
... | ... | @@ -149,18 +159,19 @@ cdm::AnyPatientActionData* PBPatientAction::Unload(const SEPatientAction& action |
|
|
...
|
|
|
```
|
|
|
|
|
|
Add the Common Data Model Action to the Action Manager
|
|
|
------------------------------------------------------
|
|
|
The action manager contains different classes to organize the *collection* of actions associated with the object that the actions takes place on. The following files are those action collection managers:
|
|
|
## Add the Common Data Model Action to the Action Manager
|
|
|
|
|
|
The action manager contains different classes to organize the _collection_ of actions associated with the object on which the actions take place. The following files are those action collection managers:
|
|
|
|
|
|
* [Anesthesia Machine Action Collection](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/scenario/SEAnesthesiaMachineActionCollection.cpp)
|
|
|
* [Environment Action Collection](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/scenario/SEEnvironmentActionCollection.cpp)
|
|
|
* [Inhaler Action Collection](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/scenario/SEInhalerActionCollection.cpp)
|
|
|
* [Patient Action Collection](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/scenario/SEPatientActionCollection.cpp)
|
|
|
|
|
|
Since we are adding a patient action, we will edit the SEPatientActionCollection.h/.cpp files. Note this example is for one instance of the action for the entire engine, there are patterns in this file if want to, for example, have an instance of the action be associated with a compartment or some other way to handle multiple instances of the action type. Also note the example of the Tension Pneumothorax actions. The one action can be of 2 different types, and associated with the two lungs. Hence the interface was designed to check if any pneumothorax actions are present, then method for each combination of type/location. This exposure is up to you and what makes the most sense for your action to present to model developers. In this example we are taking a simple approach to adding this new action. Just like we used the SEAcuteStress action files as a basis, you can go through the SEPatientActionCollection files and look for SEAcuteStress and copy the patterns in the file. (Again, we organize instructions alphabetically)
|
|
|
Since we are adding a patient action, we will edit the SEPatientActionCollection.h/.cpp files. Note this example is for one instance of the action for the entire engine, there are patterns in this file if want to, for example, have an instance of the action be associated with a compartment or some other way to handle multiple instances of the action type. Also, note the example of the Tension Pneumothorax actions. The one action can be of 2 different types and associated with the two lungs. Hence the interface was designed to check if any pneumothorax actions are present, then method for each combination of type/location. This exposure is up to you and what makes the most sense for your action to present to model developers. In this example, we are taking a simple approach to adding this new action. Just like we used the SEAcuteStress action files as a basis, you can go through the SEPatientActionCollection files, look for SEAcuteStress, and copy the patterns in the file. Note again that we organize instructions alphabetically.
|
|
|
|
|
|
In the header file you will need to :
|
|
|
|
|
|
```cpp
|
|
|
// Include the header to your action file
|
|
|
#include "patient/actions/SEMyNewAction.h"
|
... | ... | @@ -172,9 +183,10 @@ void RemoveMyNewAction(); |
|
|
|
|
|
// Add the member variable
|
|
|
SEMyNewAction* m_MyNewAction;
|
|
|
|
|
|
```
|
|
|
|
|
|
In the cpp file you will need to :
|
|
|
|
|
|
```cpp
|
|
|
// initialize the member variable in the constructor
|
|
|
m_AcuteStress = nullptr;
|
... | ... | @@ -221,9 +233,9 @@ void SEPatientActionCollection::GetActiveActions(std::vector<const SEAction*>& a |
|
|
|
|
|
With this file complete, the action has been added to the Common Data Model and the engine is able to accept these actions and the engine may now implement logic based on this action.
|
|
|
|
|
|
Adding Support for an Action to the Engine
|
|
|
------------------------------------------
|
|
|
You will need to identify the system(s) you wish to check for this action and put the following code inside a method that gets called during PreProcess
|
|
|
## Adding Support for an Action to the Engine
|
|
|
|
|
|
You will need to identify the system(s) you wish to check for this action and put the following code inside a method that gets called during PreProcess.
|
|
|
|
|
|
```cpp
|
|
|
if (m_data.GetActions().GetPatientActions().HasMyNewAction())
|
... | ... | @@ -238,6 +250,7 @@ if (m_data.GetActions().GetPatientActions().HasMyNewAction()) |
|
|
CircuitPath->GetNextResistance().SetValue(new_next, FlowResistanceUnit::mmHg_s_Per_mL);
|
|
|
}
|
|
|
```
|
|
|
Note that this code will get executed every time-step. You should take into consideration that circuit elements (i.e, resistances, compliances, etc.) store three temporal parameters - the “next” value that will be used in the upcoming circuit calculation for the state of the next time-step, the “current” value that is value used for the last circuit calculation, and the “baseline” value that is the unmodified original homeostatic value. At the beginning of each time-step, the next value is replaced with the baseline value.
|
|
|
|
|
|
A model should create a multiplier value based on the action data. That multiplier should then be applied to the next value each time-step (The next value may or may not have already been already modified by a different action). Actions should not modify baseline values or current values, since they are merely used as input for transient calculations. Typically speaking, an action that remains active will call the same code to modify next values every time-step. |
|
|
Note that this code will get executed every time-step. You should take into consideration that circuit elements (i.e, resistances, compliances, etc.) store three temporal parameters - the “next” value that will be used in the upcoming circuit calculation for the state of the next time-step, the “current” value that is used for the last circuit calculation, and the “baseline” value that is the unmodified original homeostatic value. At the beginning of each time-step, the next value is replaced with the baseline value.
|
|
|
|
|
|
A model should create a multiplier value based on the action data. That multiplier should then be applied to the next value each time-step (the next value may or may not have already been modified by a different action). Actions should not modify baseline values or current values, since they are merely used as input for transient calculations. Typically speaking, an action that remains active will call the same code to modify the next values every time-step. |
|
|
\ No newline at end of file |