Skip to content

Generic Module Framework

Chris Moesel edited this page Jul 28, 2016 · 38 revisions

Synthea contains a framework for defining modules using JSON. A JSON module configuration describes a progression of states and the transitions between them. On each Synthea generation "cycle", the generic framework processes states one at a time to trigger conditions, encounter, medications, and other clinical events.

States

The generic module framework currently supports the following states:

  • Initial
  • Terminal
  • Guard
  • Delay
  • Encounter
  • ConditionOnset
  • MedicationOrder
  • Procedure
  • Death

The following states are also planned for future implementation:

  • Lab
  • ConditionEnd
  • MedicationEnd

Initial

The Initial state type is the first state that is processed in a generic module. It does not provide any specific function except to indicate the starting point, so it has no properties except its type. The Initial state is the only state that requires a specific name: "Initial". In addition, it is the only state for which there can only be one in the whole module.

Supported Properties

  • type: must be "Initial" (required)

Example

Please note that, for simplicity, state examples in this document will not include any transition properties. See the Transitions section for information about transitions.

{
  "type": "Initial"
}

Terminal

The Terminal state type indicates the end of the module progression. Once a Terminal state is reached, no further progress will be made. As such, Terminal states cannot have any transition properties. If desired, there may be multiple Terminal states with different names to indicate different ending points -- but this has no actual effect on the records that are produced.

Supported Properties

  • type: must be "Terminal" (required)

Example

{
  "type": "Terminal"
}

Guard

The Guard state type indicates a point in the module through which a patient can only pass if they meet certain logical conditions. For example, a Guard may block a workflow until the patient reaches a certain age, after which the Guard allows the module to continue to progress. Depending on the condition, a patient may be blocked by a Guard until they die -- in which case they never reach a Terminal state. The Guard state's allow property provides the logical condition which must be met to allow the module to continue to the next state. Please see the Logic section for more information about creating logical conditions.

Guard states are similar to conditional transitions in some ways, but also have an important difference. A conditional transition tests conditions once and uses the result to immediately choose the next state. A Guard state will test the same condition on every time cycle until the condition passes, at which point it progresses to the next state.

Supported Properties

  • type: must be "Guard" (required)
  • allow: the condition under which the Guard allows the module to progress to the next state; otherwise the module remains at the Guard state (required)

Example

The following is an example of a Guard state that only allows the module to continue if the patient is male and at least 40 years old.

{
  "type": "Guard",
  "allow": {
    "condition_type": "And",
    "conditions": [
      {
        "condition_type": "Gender",
        "gender": "M" 
      },
      {
        "condition_type": "Age",
        "operator": ">=",
        "quantity": 40,
        "unit": "years"
      }
    ]
  }
}

Delay

The Delay state type introduces a pre-configured temporal delay in the module's timeline. As a simple example, a Delay state may indicate a one-month gap in time between an initial encounter and a followup encounter. The module will not pass through the Delay state until the proper amount of time has passed. The Delay state may define an exact time to delay (e.g., 4 days) or a range of time to delay (e.g., 5 - 7 days).

Implementation Detail

Synthea generation occurs in time cycles; currently 7-day cycles. This means that if a module is processed on a given date, the next time it is processed will be exactly 7 days later. If a delay expiration falls between cycles (e.g., day 3 of a 7-day cycle), then the first cycle after the delay expiration will effectively rewind the clock to the delay expiration time and process states using that time. Once it reaches a state that it can't pass through, it will process it once more using the original (7-day cycle) time.

Supported Properties

  • type: must be "Delay" (required)
  • exact: an exact amount of time to delay (required if range is not set)
    • quantity: the number of units to delay (e.g., 4) (required)
    • unit: the unit of time pertaining to the quantity (e.g., "days"). Valid unit values are: years, months, weeks, days, hours, minutes, and seconds. (required)
  • range: a range indicating the allowable amounts of delay. The actual delay time will be chosen randomly from the range. (required if exact is not set)
    • low: the lowest number (inclusive) of units to delay (e.g., 5) (required)
    • high: the highest number (inclusive) of units to delay (e.g., 7) (required)
    • unit: the unit of time pertaining to the range (e.g., "days"). Valid unit values are: years, months, weeks, days, hours, minutes, and seconds. (required)

Examples

The following is an example of a Delay state that delays exactly 4 days.

{
  "type": "Delay",
  "exact": {
    "quantity": 4,
    "unit": "days"
  }
}

The following is an example of a Delay state that delays at least 5 days and at most 7 days.

{
  "type": "Delay",
  "range": {
    "low": 5,
    "high": 7,
    "unit": "days"
  }
}

Encounter

The Encounter state type indicates a point in the module where an encounter should take place. Encounters are important in Synthea because they are generally the mechanism through which the actual patient record is updated (a disease is diagnosed, a medication is prescribed, etc). The generic module framework supports integration with scheduled wellness encounters from Synthea's Encounters module, as well as creation of new stand-alone encounters.

Scheduled Wellness Encounters vs. Standalone Encounters

An Encounter state with the wellness property set to true will block until the next scheduled wellness encounter occurs. Scheduled wellness encounters are managed by the Encounters module in Synthea and, depending on the patient's age, typically occur every 1 - 3 years. When a scheduled wellness encounter finally does occur, Synthea will search the generic modules for currently blocked Encounter states and will immediately process them (and their subsequent states). An example where this might be used is for a condition that onsets between encounters, but isn't found and diagnosed until the next regularly scheduled wellness encounter.

An Encounter state without the wellness property set will be processed and recorded in the patient record immediately. Since this creates an encounter, the encounter class and at least one code must be specified in the state configuration. This is how generic modules can introduce encounters that are not already scheduled by other modules.

Encounters and Related Events

Encounters are typically the mechanism through which a patient's record will be updated. This makes sense since most recorded events (diagnoses, prescriptions, and procedures) should happen in the context of an encounter. When an Encounter state is successfully processed, it will look through the previously processed states for un-recorded ConditionOnset instances that indicate it (by name) as the target_encounter. If it finds any, it will record the corresponding diagnosis in the patient's record at the time of the encounter.

As soon as the Encounter state is processed, Synthea will continue to progress through the module. If any subsequent states identify the previous Encounter as their target_encounter and they occur at the same time as the target encounter, then they will be added to the patient record. This is the preferred mechanism for simulating events that happen at the encounter (e.g., MedicationOrders, Procedures, and Encounter-caused ConditionOnsets).

Future Implementation Considerations

Future implementations should also consider a more robust mechanism for defining the length of an encounter and the activities that happen during it. Currently, encounter activities must start at the same exact time as the encounter start in order to be recorded. This, however, is unrealistic for multi-day inpatient encounters.

Supported Properties

  • type: must be "Encounter" (required)
  • wellness: if true, indicates that this state should block until a regularly scheduled wellness encounter occurs (required if class and codes are not set)
  • class: indicates the class of the encounter, as defined in the EncounterClass value set (required if wellness is not set)
  • codes[]: a list of codes indicating the encounter type (at least one required if wellness is not set)
    • system: the code system. Currently, only SNOMED-CT is allowed. (required)
    • code: the code (required)
    • display: the human-readable code description (required)

Examples

The following is an example of an Encounter state that blocks until a regularly scheduled encounter.

{
  "type": "Encounter",
  "wellness": true
}

The following is an example of an Encounter state indicating an ED visit.

{
  "type": "Encounter",
  "class": "emergency",
  "codes": [{
    "system": "SNOMED-CT",
    "code": "50849002",
    "display": "Emergency Room Admission"
  }]
}

ConditionOnset

The ConditionOnset state type indicates a point in the module where the patient acquires a condition. This is not necessarily the same as when the condition is diagnosed and recorded in the patient's record. In fact, it is possible for a condition to onset but never be discovered.

If the ConditionOnset state's target_encounter is set to the name of a future encounter, then the condition will be diagnosed when that future encounter occurs. If the target_encounter is set to the name of a previous encounter, then the condition will only be diagnosed if the ConditionOnset start time is the same as the encounter's start time. See the Encounter section above for more details.

Future Implementation Considerations

Although the generic module framework supports a distinction between a condition's onset date and diagnosis date, currently only the diagnosis date is recorded. In the future, the Synthea::Output::Record::condition method should be updated to support an onset date.

Currently, the generic module framework does not provide a way to resolve (or abate) conditions. There are two ways this could potentially be implemented in the future: (1) by introducing a ConditionEnd state (recommended), or (2) by introducing a property in ConditionOnset to indicate its intended duration.

Supported Properties

  • type: must be "ConditionOnset" (required)
  • target_encounter: the name of the Encounter state at which this condition should be diagnosed and recorded (optional)
  • codes[]: a list of codes indicating the condition (at least one required)
    • system: the code system. Currently, only SNOMED-CT is allowed. (required)
    • code: the code (required)
    • display: the human-readable code description (required)

Example

The following is an example of a ConditionOnset that should be diagnosed at the "ED_Visit" Encounter.

{
  "type": "ConditionOnset",
  "target_encounter": "ED_Visit",
  "codes": [{
    "system": "SNOMED-CT",
    "code": "47693006",
    "display": "Rupture of appendix"
  }]
}

MedicationOrder

The MedicationOrder state type indicates a point in the module where a medication should be prescribed. The MedicationOrder state must come after the target_encounter Encounter state in the module, but must have the same start time as that Encounter; otherwise it will not be recorded in the patient's record. See the Encounter section above for more details.

The MedicationOrder also supports identifying a previous ConditionOnset as the reason for the prescription.

Future Implementation Considerations

Currently, the generic module framework does not provide a way to end medications. There are two ways this could potentially be implemented in the future: (1) by introducing a MedicationEnd state, or (2) by introducing a property in MedicationOrder to indicate its intended duration.

Supported Properties

  • type: must be "MedicationOrder" (required)
  • target_encounter: the name of the Encounter state at which this medication should be prescribed. This Encounter must come before MedicationOrder in the module, but must have the same start time as the MedicationOrder. (required)
  • codes[]: a list of codes indicating the medication (at least one required)
    • system: the code system. Currently, only RxNorm is allowed. (required)
    • code: the code (required)
    • display: the human-readable code description (required)
  • reason: the name of the ConditionOnset state which represents the reason for which the medication is prescribed. This ConditionOnset must come before the MedicationOrder in the module. (optional)

Example

The following is an example of a MedicationOrder that should be prescribed at the "Annual_Checkup" Encounter and cite the "Diabetes" ConditionOnset as the reason.

{
  "type": "MedicationOrder",
  "target_encounter": "Annual_Checkup",
  "codes": [{
    "system": "RxNorm",
    "code": "860975",
    "display": "24 HR Metformin hydrochloride 500 MG Extended Release Oral Tablet"
  }],
  "reason": "Diabetes"
}

Procedure

Death

Transitions

The generic module framework currently supports the following transitions:

  • Direct
  • Distributed
  • Conditional

Logic

The Guard state and Conditional transition use conditional (boolean) logic. The following condition types are currently supported:

  • Gender
  • Age
  • And
  • Or
  • Not
  • True
  • False
Clone this wiki locally