Packages

Pure Elixir DICOM toolkit for P10 files, DICOM JSON, de-identification, and structured reports (all 33 PS3.16 root templates)

Current section

Files

Jump to
dicom lib dicom sr templates ecg_report.ex
Raw

lib/dicom/sr/templates/ecg_report.ex

defmodule Dicom.SR.Templates.ECGReport do
@moduledoc """
Builder for a practical TID 3700 ECG Report document.
The current builder covers the normative root title, procedure modifier,
observer context, global measurements, lead measurement groups, generic
findings, and summary impressions.
"""
alias Dicom.SR.{Code, Codes, ContentItem, Document, Measurement, MeasurementGroup, Observer}
import Dicom.SR.Templates.Helpers
@spec new(keyword()) :: {:ok, Document.t()} | {:error, term()}
def new(opts) when is_list(opts) do
observer_name = Keyword.fetch!(opts, :observer_name)
procedure_reported = Keyword.get(opts, :procedure_reported)
language =
Keyword.get(opts, :language, Code.new("en-US", "RFC5646", "English (United States)"))
root_children =
[]
|> add_optional([Observer.language(language)])
|> add_optional(observer_items(opts, observer_name))
|> add_optional(optional_procedure_item(procedure_reported))
|> add_optional(map_text_or_code_items(Keyword.get(opts, :reasons, []), "CONTAINS"))
|> add_optional(optional_global_measurements(Keyword.get(opts, :global_measurements, [])))
|> add_optional(optional_lead_measurements(Keyword.get(opts, :lead_measurements, [])))
|> add_optional(map_findings(Keyword.get(opts, :findings, [])))
|> add_optional(map_impressions(Keyword.get(opts, :summary, [])))
root = ContentItem.container(Codes.ecg_report(), children: root_children)
Document.new(
root,
Keyword.merge(opts,
template_identifier: "3700",
series_description: Keyword.get(opts, :series_description, "ECG Report")
)
)
end
defp optional_procedure_item(nil), do: nil
defp optional_procedure_item(%Code{} = code) do
ContentItem.code(Codes.procedure_reported(), code, relationship_type: "HAS CONCEPT MOD")
end
defp optional_global_measurements([]), do: nil
defp optional_global_measurements(measurements) do
ContentItem.container(Codes.ecg_global_measurements(),
relationship_type: "CONTAINS",
children: Enum.map(measurements, &Measurement.to_content_item/1)
)
end
defp optional_lead_measurements([]), do: nil
defp optional_lead_measurements(lead_groups) do
ContentItem.container(Codes.ecg_lead_measurements(),
relationship_type: "CONTAINS",
children:
Enum.map(lead_groups, fn lead_group ->
lead = Map.fetch!(lead_group, :lead)
measurements = Map.get(lead_group, :measurements, [])
MeasurementGroup.new("lead:#{lead}", Dicom.UID.generate(),
activity_session: lead,
measurements: measurements
)
|> MeasurementGroup.to_content_item()
end)
)
end
defp map_text_or_code_items(values, relationship_type) do
Enum.map(values, fn
%Code{} = code ->
ContentItem.code(Codes.finding(), code, relationship_type: relationship_type)
text when is_binary(text) ->
ContentItem.text(Codes.finding(), text, relationship_type: relationship_type)
end)
end
end