Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
engine
engine
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 5
    • Issues 5
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Merge Requests 0
    • Merge Requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Incidents
    • Environments
  • Packages & Registries
    • Packages & Registries
    • Container Registry
  • Analytics
    • Analytics
    • CI/CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Pulse Physiology Suite
  • engineengine
  • Wiki
  • Creating a condition

Last edited by Aaron Bray Oct 25, 2018
Page history

Creating a condition

Conditions are the method used to get instructions into Pulse and direct a physiology model to change its patient physiology to a new homeostatic stabilization point. This happens during stabilization, which is when Pulse examines the patient data and configure itself to meet the provided inputs (i.e. stabilize to the requested mean arterial blood pressure). The physiology model is dependent on the model implementation, while an condition is a generic data structure usually associated with a general long term state of the patient. An engine is free to interpret and modify its models according to the intent of the condition and the data it provides. The engine will take the condition into account during stabilization and modify the patient to come to a new homeostatic physiology with the condition taken into account.

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.

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
  • Patient Conditions

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;
  }
}
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

Update Convergence Criteria

A condition is applied during patient stabilization in order to ensure the homeostatic baselines properly take into account any and all condition data set on the patient. Each condition can modify any values in the engine, with the goal of affecting various system level properties. At the end of stabilization all of these affected system properties need to be in a homeostatic state, i.e. at a relatively level value. We provide a way to define your convergence criteria for your condition in our Data Spread Sheet. You will need to add a convergence criteria block for your condition in this spreadsheet. We suggest you copy the standard convergence block and add system level data specific associated with your condition. You provide the amount change the value needs to stay within during stabilization to signal that the condition is stable and the engine can start simulation.

With our changes in place, we will need to generate the convergence data file. From the <path/to/pulse/build>/install/bin directory run the following command:

cmake -DTYPE:STRING=genData -P run.cmake 
# There is also .bat and .sh scripts to make this a little easier
# On windows, you can type
run genData
# or, on Linux
./run.sh genData

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 and engine/cdm/cpp/patient/conditions/SEAcuteStress.cpp files and rename them to SEyour_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 Serialization Support for your Condition 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.

Headers

  • Environment Condition
  • Patient Condition

In our example, for adding a patient condition we will add something like the following code to the appropriate header

  // Forward declare
  CDM_BIND_DECL2(MyNewAction)
  // Methods to implement
  static void Load(const cdm::MyNewConditionData& src, SEMyNewCondition& dst);
  static cdm::MyNewConditionData* Unload(const SEMyNewCondition& src);
  static void Serialize(const cdm::MyNewConditionData& src, SEMyNewCondition& dst);
  static void Serialize(const SEMyNewCondition& src, cdm::MyNewConditionData& dst);
  static void Copy(const SEMyNewCondition& src, SEMyNewCondition& dst);

Code

  • Environment Condition
  • Patient Condition

Implement the newly added methods. I suggest you just copy another condition class method set and use the correct class names.

The Serialization class is also responsible for translating the condition object to and from the AnyCondition object. You will need to update the following methods to ensure generic condition support.


// Update the Load method
SEPatientCondition* PBPatientCondition::Load(const cdm::AnyPatientConditionData& any, SESubstanceManager& subMgr)
{
  switch (any.Condition_case())
  {
    case cdm::AnyPatientConditionData::ConditionCase::kMyNewCondition:
    {
      SEMyNewCondition* c = new SEMyNewCondition();
      SEMyNewCondition::Load(any.mynewcondition(), *c);
      return c;
    }
    ...

// Update the Unload Method
// Note we will want the cast/if block to be alphabetical order
cdm::AnyPatientConditionData* PBPatientCondition::Unload(const SEPatientCondition& action)
{
  cdm::AnyPatientConditionData* any = new cdm::AnyPatientConditionData();
  const SEMyNewCondition* mnc= dynamic_cast<const SEMyNewCondition*>(&action);
  if (mnc!= nullptr)
  {
    any->set_allocated_mynewcondition(SEMyNewCondition::Unload(*mnc));
    return any;
  }
  ...

Add the Common Data Model Condition 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

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 :

// 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 :

// 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;
}

// Go to the condition manager and add logic to the GetActiveConditions method
void SEConditionManager::GetActiveConditions(std::vector<const SECondition*>& conditions) const
{
  if(HasMyNewCondition())
    conditions.push_back(GetMyNewCondition());
}

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

Clone repository
  • Adding a Parameter
  • Contributing to Pulse
  • Creating a Scenario
  • Creating a Unit Test
  • Creating a condition
  • Creating an Action
  • Extending a System
  • Generating Documentation
  • Modifying a System Circuit
  • Pulse Scenario Driver
  • Test Suite
  • Updating Baselines
  • Updating Documentation
  • Using C#
  • Using CLion
View All Pages