... | ... | @@ -5,5 +5,133 @@ Conditions are the method used to get instructions into Pulse and direct a physi |
|
|
|
|
|
In this post we will discuss how to create the infrastructure to design and implement a new condition in the Common Data Model so it can be included in scenario and used by Pulse integrators. We will also look at how a physiology modeler can use the condition in their methodology implementation.
|
|
|
|
|
|
Modify the Common Data Model
|
|
|
---------------------------- |
|
|
\ No newline at end of file |
|
|
Create the Common Data Model Condition Proto buffer
|
|
|
---------------------------------------------------
|
|
|
You will need to define the data structure for your condition. The data structures are defined in google protocol buffers. The condition structures are organized by the object the condition takes place on. The following files are where we define conditions associated with various objects.
|
|
|
|
|
|
* [Environment Conditions](https://gitlab.kitware.com/physiology/engine/blob/master/schema/proto/cdm/EnvironmentConditions.proto)
|
|
|
* [Patient Conditions](https://gitlab.kitware.com/physiology/engine/blob/master/schema/proto/cdm/PatientConditions.proto)
|
|
|
|
|
|
For this discussion, we will look at adding a patient condition, but the same principles can be applied to other object related conditions.
|
|
|
|
|
|
Open the PatientConditions.proto file in your favorite editor and add the following. (Typically we strive to keep the conditions in alphabetical order)
|
|
|
Note the naming convention is to end each data structure with ``Data``
|
|
|
|
|
|
```
|
|
|
message MyNewConditionData
|
|
|
{
|
|
|
// Set the first field to be the encapsulation of the base class
|
|
|
// protobuf does support inheritance..
|
|
|
PatientConditionData PatientCondition = 1;
|
|
|
// Next add the properties associated with your action definition
|
|
|
Scalar0To1Data Severity = 2;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Next, add your new condition object to the list of available patient conditions.
|
|
|
|
|
|
```
|
|
|
message AnyPatientConditionData
|
|
|
{
|
|
|
oneof Condition
|
|
|
{
|
|
|
ChronicAnemiaData ChronicAnemia = 1;
|
|
|
ChronicObstructivePulmonaryDiseaseData ChronicObstructivePulmonaryDisease = 2;
|
|
|
ChronicPericardialEffusionData ChronicPericardialEffusion = 3;
|
|
|
ChronicRenalStenosisData ChronicRenalStenosis = 4;
|
|
|
ChronicVentricularSystolicDysfunctionData ChronicVentricularSystolicDysfunction = 5;
|
|
|
ConsumeMealData ConsumeMeal = 6;
|
|
|
ImpairedAlveolarExchangeData ImpairedAlveolarExchange = 7;
|
|
|
LobarPneumoniaData LobarPneumonia = 8;
|
|
|
|
|
|
// 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
|
|
|
MyNewConditionData MyNewCondition = 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:
|
|
|
```
|
|
|
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
|
|
|
run protoc
|
|
|
# or, on Linux
|
|
|
./run.sh protoc
|
|
|
```
|
|
|
|
|
|
Create the Common Data Model C++ Condition
|
|
|
------------------------------------------
|
|
|
Now we are ready to create the C++ files specific to this condition class.
|
|
|
The easiest thing to do is to create copies of [engine/cdm/cpp/patient/conditions/SEChronicAnemia.h](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/patient/conditions/SEChronicAnemia.h) and [engine/cdm/cpp/patient/conditions/SEAcuteStress.cpp](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/patient/conditions/SEChronicAnemia.cpp) files and rename them to SE``your_condition_name``.h/.cpp Then replace the string ``AcuteStress`` with the name of your condition, then create the properties to match your condition protobuf structure. Note the naming convention is to start each file and class name with ``SE``
|
|
|
|
|
|
Add the Common Data Model Action to the Condition Manager
|
|
|
---------------------------------------------------------
|
|
|
The condition manager contains different classes to organize the collection of conditions associated with the engine. Since there are so few conditions, there is only one manager for managing environment and patient conditions (unlike the action manager).
|
|
|
|
|
|
* [Condition Manager](https://gitlab.kitware.com/physiology/engine/blob/master/cdm/cpp/scenario/SEConditionManager.h.cpp)
|
|
|
|
|
|
In this example we will basically duplicate the code that manages the SEChronicAnemia condition. Just like we used the SEChronicAnemia condition files as a basis, you can go through the SEConditionManager files and look for SEChronicAnemia and copy the patterns in the file. (Again, we organize instructions alphabetically)
|
|
|
|
|
|
In the header file you will need to :
|
|
|
```cpp
|
|
|
// Include the header to your action file
|
|
|
#include "patient/conditions/SEMyNewCondition.h"
|
|
|
|
|
|
// Create methods to expose your new condition
|
|
|
bool HasMyNewCondition() const;
|
|
|
SEMyNewCondition* GetMyNewCondition() const;
|
|
|
|
|
|
// Add the member variable
|
|
|
SEMyNewCondition* m_MyNewCondition;
|
|
|
|
|
|
```
|
|
|
In the cpp file you will need to :
|
|
|
```cpp
|
|
|
// initialize the member variable in the constructor
|
|
|
m_MyNewCondition = nullptr;
|
|
|
// Support the clearing the condition
|
|
|
SAFE_DELETE(m_MyNewCondition);
|
|
|
// Support serialization of the condition
|
|
|
if (src.HasMyNewCondition())
|
|
|
dst.mutable_anycondition()->AddAllocated(SECondition::Unload(*src.m_MyNewCondition));
|
|
|
// Support Processing the condition
|
|
|
// Notice how we make a copy of any incoming condition,
|
|
|
// so for a user to change an condition they must call Process
|
|
|
const SEMyNewCondition* mine = dynamic_cast<const SEMyNewCondition*>(&condition);
|
|
|
if (mine != nullptr)
|
|
|
{
|
|
|
if (HasMyNewCondition())
|
|
|
{
|
|
|
Error("Cannot have multiple MyNewCondition conditions");
|
|
|
m_Conditions.mutable_anycondition()->RemoveLast();
|
|
|
return false;
|
|
|
}
|
|
|
m_MyNewCondition = new SEMyNewCondition();
|
|
|
cData->mutable_patientcondition()->set_allocated_mynewcondition(SEMyNewCondition::Unload(*a));
|
|
|
SEMyNewCondition::Load(cData->mutable_patientcondition()->mynewcondition(), *m_MyNewCondition);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// Fill out your exposed methods
|
|
|
bool SEConditionManager::HasMyNewCondition() const
|
|
|
{
|
|
|
return m_MyNewCondition == nullptr ? false : m_MyNewCondition->IsValid();
|
|
|
}
|
|
|
SEMyNewCondition* SEConditionManager::GetMyNewCondition() const
|
|
|
{
|
|
|
return m_MyNewCondition;
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
With this file complete, the condition has been added to the Common Data Model and the engine is able to accept this condition and the engine may now implement logic based on this condition.
|
|
|
|
|
|
Adding Support for a Condition to the Engine
|
|
|
--------------------------------------------
|
|
|
You will need to identify the system(s) you wish to check for this condition and put the following code inside
|
|
|
|
|
|
|
|
|
TODO |