Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Technical Docs #28

Open
jamais-vu opened this issue Jul 3, 2021 · 0 comments
Open

Technical Docs #28

jamais-vu opened this issue Jul 3, 2021 · 0 comments
Assignees
Labels
documentation Improvements or additions to documentation

Comments

@jamais-vu
Copy link
Contributor

jamais-vu commented Jul 3, 2021

Here's what I've summed up from my notes with respect to technical documentation. I tried to include only details which an implementer may be curious about, but this should still probably be edited down.

This does not necessarily need to go in index.md, we could split it up and have additional pages with varying levels of detail.

Issues

(new issues may not appear here; check (Github)[https://github.com/Automate-Medical/pft-ig/issues] for more up-to-date information)

IG build errors

The primary error is with evaluating slices.

"Slicing cannot be evaluated: Profile based discriminators must have a type with a profile (Reference.reference in profile https://automatemedical.com/fhir/pulmonary-function-test/StructureDefinition/PulmonaryFunctionTestDiagnosticReport)"

This currently only affects our DiagnosticReport instance, but in theory will affect any slicing where we discriminate on profile. The suspected solution is to have the canonical URL resolve to the specified profile (further discussion at issue #26).

Limitations

TODO: Maybe this is more "Future Development"

Gaps in Coding (TODO: This is an addition to our current section)

Many pulmonary function test observations lack an appropriate LOINC or SNOMED code (for non-comprehensive list, see the Coding Gaps table in the IG docs). In those cases, we use Observation.code.text to unambiguously specify what each observation is.

There are two cases where we need to convey information not included in a terminology system.

Code exists, but is ambiguous

Many observations lack a code which specifies whether they were performed pre or post bronchodilator.

For example, ForcedExpiratoryVolume1Sec_PercentOfPredicted has the corresponding LOINC code 20152-5 "FEV1 measured/predicted" but no such code exists for ForcedExpiratoryVolume1SecPreBronchodilator_PercentOfPredicted or ForcedExpiratoryVolume1SecPostBronchodilator_PercentOfPredicted.

In these cases, we use Observation.code.text to include that missing information, while still assigning the appropriate LOINC or SNOMED code. I've tried to adhere to the LOINC style, where possible.

For example:

ForcedExpiratoryVolume1Sec_PercentOfPredicted:

* code = $LNC#20152-5 "FEV1 measured/predicted"
{
  "id": "Observation.code",
  "path": "Observation.code",
  "patternCodeableConcept": {
    "coding": [
      {
        "code": "20152-5",
        "system": "http://loinc.org",
        "display": "FEV1 measured/predicted"
      }
    ]
  }
},

ForcedExpiratoryVolume1SecPreBronchodilator_PercentOfPredicted:

* code
  * coding = $LNC#20152-5 "FEV1 measured/predicted"
  * text = "FEV1 measured/predicted pre-bronchodilator"
{
  "id": "Observation.code.coding",
  "path": "Observation.code.coding",
  "patternCoding": {
    "code": "20152-5",
    "system": "http://loinc.org",
    "display": "FEV1 measured/predicted"
  }
},
{
  "id": "Observation.code.text",
  "path": "Observation.code.text",
  "patternString": "FEV1 measured/predicted pre-bronchodilator"
},

And likewise for ForcedExpiratoryVolume1SecPostBronchodilator_PercentOfPredicted.

Code does not exist

For observations with no appropriate LOINC or SNOMED code we have been assigning Observation.code.text an unambiguous human-readable name. In some cases I've mimicked the LOINC style.

There exist some inconsistencies between our Profile names and the text we give for the code.

For example, KCO has LOINC code 19916-6 "Diffusion capacity/Alveolar volume", so I give KCO_Zscore the text "Diffusion capacity/Alveolar volume (z-score)" and KCO_PercentedOfPredicted the text "Diffusion capacity/Alveolar volume (measured/predicted)".

These inconsistencies may be resolved in the future. Maybe we define a schema for the text we add based on the profile name or id.

"Best" values

Observations in pulmonary function tests may be performed multiple times, and only the "best" value is recorded. Our Profiles do not provide any constraints for whether an Observation was "best" or not.

Reference values

It is important to note where the reference values for a test originate from because these are used to calculate measures of abnormality (Zscore, percent of predicted). The lack of universally-recognized reference values for many pulmonary function test observation presents a difficulty for implementers, as we must rely on the author of the resource to provide an unambiguous identifier for the source of the values.

The reference value on its own is unnecessary and does not need to be included. It is only relevant in relation to the measured value.

We could use Observation.note or an extension on Observation to include the source of the reference values.

Use of note could be plain language (e.g. "GLI 2012"). An extension could use a DOI.

Test quality

Pulmonary function tests may include a note about test quality. As far as we know, there is no popularly-adopted standard for coding this.

We could use Observation.note or an extension on Observation to include test quality.

If PFT reports tend to denote test quality with only a letter ("A", "B", etc) then I think an extension is best. But if it is usually recorded in plain language, note is better.

I'd like to put each as a separate entry in Observation.note but the IG renderer raises an error if an Observation Instance as more than one note, even though the standard permits multiple notes (TODO: Add my discussion of this error)

Technician notes

We currently have no way to associate relevant notes from the technician who performed the PFT with the DiagnosticReport (we do for Composition). This could maybe be an extension. I don't think the text element is the appropriate place for it and see no other element of DiagnosticReport in which we could put it.

Diffusing capacity: barometric pressure (PB) and hemoglobin (Hb)

We provide no examples of how to include values of barometric pressure or hemoglobin used in DLCO tests.

For example, a PFT report may note that a DLCO test was done with PB = 721 mmHg

"DLCO (pred adj Hb 13.8 g/dL" see #21

No constraints on referenceRange

In the future we might want to slice Observation.referenceRange in our profiles to constrain the reference range to the same units as the corresponding valueQuantity to ensure validity of entered data.

ValueSets for Observation.code

TODO: Update - I actually just created these for FVC, FVC % pred, and FEV1.

We have many Profiles for Observations performed with respect to application of a bronchodilator.

For example, there is ForcedVitalCapacity, ForcedVitalCapacityPreBronchodilator, and ForcedVitalCapacityPostBronchodilator, each with a constraint on code.coding for their respective LOINC codes.

Ideally, any resource which conforms to either the ForcedVitalCapacityPreBronchodilator or ForcedVitalCapacityPostBronchodilator Profile would also conform to the ForcedVitalCapacity Profile. This is not currently the case because the ForcedVitalCapacity Profile constrains code.coding to:

"coding": [
  {
    "code": "19870-5",
    "system": "http://loinc.org",
    "display": "Forced vital capacity [Volume] Respiratory system"
  }
]

while ForcedVitalCapacityPreBronchodilator is:

"coding": [
  {
    "code": "19876-2",
    "system": "http://loinc.org",
    "display": "Forced vital capacity [Volume] Respiratory system by Spirometry --pre bronchodilation"
  }
]

and ForcedVitalCapacityPostBronchodilator is:

"coding": [
  {
    "code": "19874-7",
    "system": "http://loinc.org",
    "display": "Forced vital capacity [Volume] Respiratory system by Spirometry --post bronchodilation"
  }
]

We think it would be better to define ForcedVitalCapacity (and other such Profiles exhibiting these same relations) with a constraint on code.coding which permits a CodeableConcept from a ValueSet containing the codings for all three of these.

Grouping Observations

Intuitively, Observations of the same category (like FVC) should indicate they're all of that category.

Currently the only relations we define between Observations are via the derivedFrom element, which we use to say the Observations for Zscore, percent of predicted, and other calculated quantities are derived from other Observations. The only indication that Observations like FVC PRE and FVC POST are similar is in the name (so a human might know but a machine would not).

We provide an example Composition(TODO: link to Instance) resource to demonstrate how such a grouping may occur. This is still a draft and has no corresponding Profile.

Observations in multiple panels

Some Observations may be performed in more than one test panel. For example, vital capacity (VC) may be performed as part of "Slow vital capacity", "Multi-breath nitrogen washout", and "Plethysmography" test panels, and have a different value for each. Our Profiles do not provide any constraints for which panel of tests an Observation was part of (see Grouping Observations).

Images

Pulmonary function tests may generate plots or charts. For example, a spirometry may generate plots of volume over time, or a diffusing capacity may generate a plot of tracer gas over exhaled volume or time.

While these can be included in DiagnosticReport.media, we provide no examples of this. We also make no suggestions for how they should be relate to any other relevant resource.

Miscellaneous

Naming schema (TODO: This section may not be necessary to include)

We decided on a naming schema for Profiles (#13). However, FEV1, FEV1/FVC, DLCO, and VI/VC Profiles do not fully conform to this naming schema (see: #16).

FEV1/FVC units

Unlike every other ratio, FEV1/FVC is coded with unit {Number} instead of %. There's no special reason for this - the example PFT doesn't specify it as a percent and I don't want to add my own interpretation.

KCO vs DLCO/VA

We name our profiles with "KCO", but otherwise use these terms (as well as "carbon monoxide transfer coefficient" and "diffusion capacity/alveolar volume") interchangeably. It is unclear if this is fine.

LOINC uses "Diffusion capacity/Alveolar volume" (https://loinc.org/19916-6/) as the long common name.

Bronchodilator vs Bronchodilation; Diffusing Capacity vs Diffusion Capacity

We use these interchangeably but primarily use "bronchodilator" and "diffusing capacity". LOINC tends to use "bronchodilation" and "diffusion capacity".

Formatting: subscripts

Many terms use subscripts, but we don't include those because systems may be expecting a character encoding which does not include those code points (e.g., ASCII). In some cases we indicate a subscript with an underscore; in other cases we don't.

Design decisions

TODO: This section is bare, but I think most of the decisions are covered above

We have opted for a flat list of Observations rather than grouping by categories (see Grouping Observations).

Our slicing on Observation.derivedFrom is open to permit additional references to other observations they may be derived from.

Our slicing on DiagnosticReport is open to permit additional references to other observations included in the diagnostic report.

@jamais-vu jamais-vu added the documentation Improvements or additions to documentation label Jul 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants