synthetichealth / synthea

Synthetic Patient Population Simulator
https://synthetichealth.github.io/synthea
Apache License 2.0
2.13k stars 640 forks source link

Expressions #189

Open jeffeastman opened 7 years ago

jeffeastman commented 7 years ago

Adding an enhancement request that's been discussed on various email threads. I have a working implementation that I use to initialize and age vital signs. In a nutshell, Expressions have the following subtypes that are more fully defined in the attached document:

Expressions for Synthea v2.docx

cmoesel commented 7 years ago

I haven't been a part of these conversations, but incorporating expressions is an interesting idea. One thing I'd suggest is that you consider alignment with the HL7 Clinical Quality Language (CQL).

This is a health IT expression language designed by MITRE (and sponsored by CMS & ONC) that is primarily used in eCQM and CDS, but is also quite fit for other applications. In short, it actually has two components: a human-readable authoring language (CQL) and an abstract syntax tree style logical model (ELM). Looking at your examples, they seem very close to the JSON serialization of ELM -- so I think alignment might not require too much effort and would provide some nice consistency.

Anyway, just throwing that out there as an interested spectator. Let me know if you'd be interested in seeing some ELM JSON examples. Also, the CQL repository has some XML examples available, from which you can easily imagine the corresponding JSON representations.

jeffeastman commented 7 years ago

+1 I have also noted this similarity and would be keen to move to CQL/ELM representation. I need to do more reading on these topics so any suggestions or examples would be appreciated.

jeffeastman commented 7 years ago

I've made some terminology changes to better align with the ELM nomenclature. Here's a revised document that describes them with the vital_signs module updated. I have this working in my implementation. The json is still a ways from what I perceive it should be from the xml definitions and examples I've found, but I have not found any good json examples to reference. Since you MITRE folks designed ELM, perhaps you could help me get this to a better representation?

Expressions for Synthea v3.docx

cmoesel commented 7 years ago

Hi @jeffeastman. Unfortunately, my other projects have been keeping me from being able to provide much guidance here. I just remembered, however, that there are JSON examples available in our execution engine test suite.

https://github.com/cqframework/clinical_quality_language/tree/master/Src/coffeescript/cql-execution/test/elm

One thing that's kind of nice is that the examples are split up nicely into folders by the functional aspect of the expression (e.g., aggregate, arithmetic, clinical, comparison, conditional, etc). So if you want to see an example for a specific CQL/ELM feature, it should be fairly easy to find (if the example exists). In each subfolder, you'll find a data.cql file with CQL snippets and a data.coffee file with corresponding ELM JSON expressions (generated by the CQL-to-ELM tool).

Again, I apologize I haven't been able to provide more hands-on support with this...

jeffeastman commented 7 years ago

Oh yes, that helps a lot! Thanks Chris,

eJeff

On Apr 20, 2017, at 9:11 AM, Chris Moesel notifications@github.com wrote:

Hi @jeffeastman https://github.com/jeffeastman. Unfortunately, my other projects have been keeping me from being able to provide much guidance here. I just remembered, however, that there are JSON examples available in our execution engine test suite.

https://github.com/cqframework/clinical_quality_language/tree/master/Src/coffeescript/cql-execution/test/elm https://github.com/cqframework/clinical_quality_language/tree/master/Src/coffeescript/cql-execution/test/elm One thing that's kind of nice is that the examples are split up nicely into folders by the functional aspect of the expression (e.g., aggregate, arithmetic, clinical, comparison, conditional, etc). So if you want to see an example for a specific CQL/ELM feature, it should be fairly easy to find (if the example exists). In each subfolder, you'll find a data.cql file with CQL snippets and a data.coffee file with corresponding ELM JSON expressions (generated by the CQL-to-ELM tool).

Again, I apologize I haven't been able to provide more hands-on support with this...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/synthetichealth/synthea/issues/189#issuecomment-295732825, or mute the thread https://github.com/notifications/unsubscribe-auth/AIO2lJo1l0bFDyNYbMAe5FFOdFTFyYJKks5rx1lygaJpZM4M_I2f.

jeffeastman commented 7 years ago

I took a stab at refactoring Operands. Since its still a work in progress I'll save the document update for later. Here's an example of Creatinine Clearance. Looks pretty good except for the Variable stuff. Still working on that and looking over the other examples.

Do you have any suggestions for accessing patient information? Variables don't seem to have an ELM precedent.

{
  "type": "Multiply",
  "operand": [
    {
      "type": "Divide",
      "operand": [
        {
          "type": "Multiply",
          "operand": [
            {
              "type": "Subtract",
              "operand": [
                {
                  "valueType": "Decimal",
                  "value": 140.0,
                  "type": "Literal"
                },
                {
                  "context": "Patient",
                  "sign": "Age(yr)",
                  "type": "Variable"
                }
              ]
            },
            {
              "context": "Patient",
              "sign": "Weight",
              "type": "Variable"
            }
          ]
        },
        {
          "type": "Multiply",
          "operand": [
            {
              "valueType": "Decimal",
              "value": 72.0,
              "type": "Literal"
            },
            {
              "context": "Patient",
              "sign": "Creatinine",
              "type": "Variable"
            }
          ]
        }
      ]
    },
    {
      "condition": {
        "context": "Patient",
        "sign": "isMale",
        "type": "Variable"
      },
      "then": {
        "valueType": "Decimal",
        "value": 1.0,
        "type": "Literal"
      },
      "else": {
        "valueType": "Decimal",
        "value": 0.85,
        "type": "Literal"
      },
      "type": "If"
    }
  ]
}
jeffeastman commented 7 years ago

Ditching Variables and Ranges in favor of predefined Functions. Here's an example of Creatinine Clearance (eGFR). Much simpler and fully ELM:

{
  "type": "Multiply",
  "operand": [
    {
      "type": "Divide",
      "operand": [
        {
          "type": "Multiply",
          "operand": [
            {
              "type": "Subtract",
              "operand": [
                {
                  "valueType": "Decimal",
                  "value": 140.0,
                  "type": "Literal"
                },
                {
                  "name": "AgeInYrs",
                  "type": "FunctionRef",
                  "operand": []
                }
              ]
            },
            {
              "name": "VitalSign",
              "type": "FunctionRef",
              "operand": [
                {
                  "valueType": "String",
                  "value": "Weight",
                  "type": "Literal"
                }
              ]
            }
          ]
        },
        {
          "type": "Multiply",
          "operand": [
            {
              "valueType": "Decimal",
              "value": 72.0,
              "type": "Literal"
            },
            {
              "name": "VitalSign",
              "type": "FunctionRef",
              "operand": [
                {
                  "valueType": "String",
                  "value": "Creatinine",
                  "type": "Literal"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "condition": {
        "name": "isMale",
        "type": "FunctionRef",
        "operand": []
      },
      "then": {
        "valueType": "Decimal",
        "value": 1.0,
        "type": "Literal"
      },
      "else": {
        "valueType": "Decimal",
        "value": 0.85,
        "type": "Literal"
      },
      "type": "If"
    }
  ]
}
jeffeastman commented 7 years ago

If we chose this path, then a module authoring tool could use CQL to specify the expressions. This could then be parsed into EML to live in the Json representation. Still editable by mortals, but pretty verbose in comparison with CQL.

In the above, I considered using Retrieve for the Vital Signs but took the KISS path instead. If we wanted to refactor all module Logic to use CQL/ELM, then this would be needed.

jeffeastman commented 6 years ago

Here's a link to a good Java CQL engine. Here's another link that I've found has useful clinical_quality_language artifacts. I've found ELM Expressions useful in computing values for Observation, SetAttribute, Symptom, VitalSign and Logic.