... | @@ -2,21 +2,22 @@ Actions are the method used to get instructions into Pulse and direct a physiolo |
... | @@ -2,21 +2,22 @@ Actions are the method used to get instructions into Pulse and direct a physiolo |
|
|
|
|
|
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
|
|
## 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.
|
|
|
|
|
|
|
|
* [Anesthesia Machine Actions](https://gitlab.kitware.com/physiology/engine/blob/master/schema/proto/cdm/AnesthesiaMachineActions.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.
|
|
* [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)
|
|
|
|
|
|
|
|
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)
|
|
For this discussion, we will look at adding a patient action, but the same principles can be applied to other object-related actions.
|
|
Note the naming convention is to end each data structure with ``Data``
|
|
|
|
|
|
|
|
```
|
|
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
|
|
message MyNewActionData
|
|
{
|
|
{
|
|
// Set the first field to be the encapsulation of the base class
|
|
// Set the first field to be the encapsulation of the base class
|
... | @@ -29,35 +30,46 @@ message MyNewActionData |
... | @@ -29,35 +30,46 @@ 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
|
|
message AnyPatientActionData
|
|
{
|
|
{
|
|
oneof Action
|
|
oneof Action
|
|
{
|
|
{
|
|
PatientAssessmentRequestData Assessment = 1;
|
|
PatientAssessmentRequestData Assessment = 1;
|
|
AcuteStressData AcuteStress = 2;
|
|
AcuteRespiratoryDistressSyndromeExacerbationData AcuteRespiratoryDistressSyndromeExacerbation = 2;
|
|
AirwayObstructionData AirwayObstruction = 3;
|
|
AcuteStressData AcuteStress = 3;
|
|
ApneaData Apnea = 4;
|
|
AirwayObstructionData AirwayObstruction = 4;
|
|
AsthmaAttackData AsthmaAttack = 5;
|
|
ArrhythmiaData Arrhythmia = 5;
|
|
BrainInjuryData BrainInjury = 6;
|
|
AsthmaAttackData AsthmaAttack = 6;
|
|
BronchoconstrictionData Bronchoconstriction = 7;
|
|
BrainInjuryData BrainInjury = 7;
|
|
CardiacArrestData CardiacArrest = 8;
|
|
BronchoconstrictionData Bronchoconstriction = 8;
|
|
ChestCompressionForceData ChestCompressionForce = 9;
|
|
ChestCompressionData ChestCompression = 9;
|
|
ChestCompressionForceScaleData ChestCompressionForceScale = 10;
|
|
ChestCompressionAutomatedData ChestCompressionAutomated = 10;
|
|
ChestOcclusiveDressingData ChestOcclusiveDressing = 11;
|
|
ChestCompressionInstantaneousData ChestCompressionInstantaneous = 11;
|
|
ConsciousRespirationData ConsciousRespiration = 12;
|
|
ChestOcclusiveDressingData ChestOcclusiveDressing = 12;
|
|
ConsumeNutrientsData ConsumeNutrients = 13;
|
|
ChronicObstructivePulmonaryDiseaseExacerbationData ChronicObstructivePulmonaryDiseaseExacerbation = 13;
|
|
ExerciseData Exercise = 14;
|
|
ConsciousRespirationData ConsciousRespiration = 14;
|
|
HemorrhageData Hemorrhage = 15;
|
|
ConsumeNutrientsData ConsumeNutrients = 15;
|
|
IntubationData Intubation = 16;
|
|
DyspneaData Dyspnea = 16;
|
|
MechanicalVentilationData MechanicalVentilation = 17;
|
|
ExerciseData Exercise = 17;
|
|
NeedleDecompressionData NeedleDecompression = 18;
|
|
HemorrhageData Hemorrhage = 18;
|
|
PericardialEffusionData PericardialEffusion = 19;
|
|
HemothoraxData Hemothorax = 19;
|
|
TensionPneumothoraxData TensionPneumothorax = 20;
|
|
ImpairedAlveolarExchangeExacerbationData ImpairedAlveolarExchangeExacerbation = 20;
|
|
SubstanceBolusData SubstanceBolus = 21;
|
|
IntubationData Intubation = 21;
|
|
SubstanceCompoundInfusionData SubstanceCompoundInfusion = 22;
|
|
MechanicalVentilationData MechanicalVentilation = 22;
|
|
SubstanceInfusionData SubstanceInfusion = 23;
|
|
NeedleDecompressionData NeedleDecompression = 23;
|
|
UrinateData Urinate = 24;
|
|
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
|
|
// 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
|
|
// As a merge request into the master branch, we will assign it a new id
|
... | @@ -66,9 +78,10 @@ message AnyPatientActionData |
... | @@ -66,9 +78,10 @@ message AnyPatientActionData |
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
```
|
|
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
|
|
cmake -DTYPE:STRING=protoc -P run.cmake
|
|
# There is also .bat and .sh scripts to make this a little easier
|
|
# There is also .bat and .sh scripts to make this a little easier
|
|
# On windows, you can type
|
|
# On windows, you can type
|
... | @@ -77,15 +90,13 @@ run protoc |
... | @@ -77,15 +90,13 @@ run protoc |
|
./run.sh protoc
|
|
./run.sh protoc
|
|
```
|
|
```
|
|
|
|
|
|
Create the Common Data Model C++ Action
|
|
## Create the Common Data Model C++ Action
|
|
---------------------------------------
|
|
|
|
Now we are ready to create the C++ files specific to this action class.
|
|
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`
|
|
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``
|
|
|
|
|
|
## 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**
|
|
**Headers**
|
|
|
|
|
... | @@ -116,8 +127,7 @@ static void Copy(const SEMyNewAction& src, SEMyNewAction& dst); |
... | @@ -116,8 +127,7 @@ static void Copy(const SEMyNewAction& src, SEMyNewAction& dst); |
|
|
|
|
|
Implement the newly added methods. I suggest you just copy another action class method set and use the correct class names.
|
|
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.
|
|
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.
|
|
You will need to update the following methods to ensure generic action support.
|
|
|
|
|
|
|
|
```cpp
|
|
```cpp
|
|
|
|
|
... | @@ -149,18 +159,19 @@ cdm::AnyPatientActionData* PBPatientAction::Unload(const SEPatientAction& action |
... | @@ -149,18 +159,19 @@ cdm::AnyPatientActionData* PBPatientAction::Unload(const SEPatientAction& action |
|
...
|
|
...
|
|
```
|
|
```
|
|
|
|
|
|
Add the Common Data Model Action to the Action Manager
|
|
## 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:
|
|
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)
|
|
* [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)
|
|
* [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)
|
|
* [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)
|
|
* [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 :
|
|
In the header file you will need to :
|
|
|
|
|
|
```cpp
|
|
```cpp
|
|
// Include the header to your action file
|
|
// Include the header to your action file
|
|
#include "patient/actions/SEMyNewAction.h"
|
|
#include "patient/actions/SEMyNewAction.h"
|
... | @@ -172,9 +183,10 @@ void RemoveMyNewAction(); |
... | @@ -172,9 +183,10 @@ void RemoveMyNewAction(); |
|
|
|
|
|
// Add the member variable
|
|
// Add the member variable
|
|
SEMyNewAction* m_MyNewAction;
|
|
SEMyNewAction* m_MyNewAction;
|
|
|
|
|
|
```
|
|
```
|
|
|
|
|
|
In the cpp file you will need to :
|
|
In the cpp file you will need to :
|
|
|
|
|
|
```cpp
|
|
```cpp
|
|
// initialize the member variable in the constructor
|
|
// initialize the member variable in the constructor
|
|
m_AcuteStress = nullptr;
|
|
m_AcuteStress = nullptr;
|
... | @@ -221,9 +233,9 @@ void SEPatientActionCollection::GetActiveActions(std::vector<const SEAction*>& a |
... | @@ -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.
|
|
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
|
|
## 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
|
|
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
|
|
```cpp
|
|
if (m_data.GetActions().GetPatientActions().HasMyNewAction())
|
|
if (m_data.GetActions().GetPatientActions().HasMyNewAction())
|
... | @@ -238,6 +250,7 @@ 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);
|
|
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 |