15.2.151. camcops_server.cc_modules.cc_snomed

camcops_server/cc_modules/cc_snomed.py


Copyright (C) 2012, University of Cambridge, Department of Psychiatry. Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

This file is part of CamCOPS.

CamCOPS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

CamCOPS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.


CamCOPS code to support SNOMED-CT.

Note that the licensing arrangements for SNOMED-CT mean that the actual codes must be separate (and not part of the CamCOPS code). See the documentation.

Some tests:

import logging
from cardinal_pythonlib.logs import main_only_quicksetup_rootlogger
from camcops_server.cc_modules.cc_request import get_command_line_request
from camcops_server.cc_modules.cc_snomed import *
from camcops_server.tasks.phq9 import Phq9
main_only_quicksetup_rootlogger(level=logging.DEBUG)
req = get_command_line_request()

# ---------------------------------------------------------------------
# Read the XML, etc.
# ---------------------------------------------------------------------

print(VALID_SNOMED_LOOKUPS)
concepts = get_all_snomed_concepts(req.config.snomed_xml_filename)

# ---------------------------------------------------------------------
# Test a task, and loading SNOMED data from XML via the CamCOPS config
# ---------------------------------------------------------------------

phq9 = Phq9()
print("\n".join(str(x) for x in phq9.get_snomed_codes(req)))
phq9.q1 = 2
phq9.q2 = 2
phq9.q3 = 2
phq9.q4 = 2
phq9.q5 = 2
phq9.q6 = 2
phq9.q7 = 2
phq9.q8 = 2
phq9.q9 = 2
phq9.q10 = 2
print("\n".join(repr(x) for x in phq9.get_snomed_codes(req)))
print("\n".join(str(x) for x in phq9.get_snomed_codes(req)))

Note diagnostic coding maps:

Other testing:

camcops_server dev_cli --verbose
from camcops_server.cc_modules.cc_snomed import *

athena_concepts = get_athena_concepts(config.athena_concept_tsv_filename)
relationships = get_athena_concept_relationships(config.athena_concept_relationship_tsv_filename)
rel_ids = set(r.relationship_id for r in relationships)
icd9, icd10 = get_icd9cm_icd10_snomed_concepts(config.athena_concept_tsv_filename, config.athena_concept_relationship_tsv_filename)

ac = get_athena_concepts(config.athena_concept_tsv_filename, vocabulary_ids=[AthenaVocabularyId.SNOMED], concept_codes=["4303690"])

Regarding temporal coding:

  • SNOMED CT has some concepts relating to time (e.g. “time aspect”, “single point in time”, “date of birth”, “date of event”, “time (property)”, “time (attribute)”). HOWEVER, note that SNOMED-CT isn’t intended for recording event dates:

    • https://confluence.ihtsdotools.org/display/DOCRSG/3.5.+Safely+representing+the+context+of+recorded+codes

      “Contextual information that is not represented by SNOMED CT

      Clinical statements that contain SNOMED CT Concept representations will be associated with some information which is not intended to be represented using SNOMED CT:

      • Dates, times of an activity of recording and activity;

      • Quantitative information including ranges and durations;

      • Identifiers or names of authors, providers of information or other parties involved in a recorded activity.

      • SNOMED CT is not intended to represent this information. Appropriate constructs in a standardized or proprietary record architecture should be used to relate this information to SNOMED CT encoded clinical statements.”

    • https://confluence.ihtsdotools.org/display/DOCRSG/3.4.+Record+architectures%2C+structures+and+semantics

      “Using SNOMED CT in standard architectures

      Each health record component has the potential to include:

      • Dates and times of actual and planned events.

      • Associations with people, organizations, devices and other entities that participate or are used in relations to a recorded event or plan.

      • Codes or other representations that name or provide the semantic information container, link, or statement:

        • SNOMED CT fulfills this role in a structured health record.

      • Additional data including text, numeric values, images and other digital data.”

  • That explains why the grammar has no explanation of how to represent dates/times, perhaps!

class camcops_server.cc_modules.cc_snomed.SnomedConcept(identifier: int, term: str)[source]
classmethod create(concept: cardinal_pythonlib.snomed.SnomedConcept) camcops_server.cc_modules.cc_snomed.SnomedConcept[source]

Creates a CamCOPS-friendly camcops_server.cc_modules.cc_snomed.SnomedConcept from a cardinal_pythonlib.snomed.SnomedConcept.

The result has extra methods.

xml_element(longform: bool = True) camcops_server.cc_modules.cc_xml.XmlElement[source]

Returns a camcops_server.cc_modules.cc_xml.XmlElement for this SNOMED-CT object.

Parameters

longform – print SNOMED-CT concepts in long form?

class camcops_server.cc_modules.cc_snomed.SnomedExpression(focus_concept: Union[cardinal_pythonlib.snomed.SnomedConcept, cardinal_pythonlib.snomed.SnomedFocusConcept], refinement: Optional[Union[cardinal_pythonlib.snomed.SnomedRefinement, Dict[cardinal_pythonlib.snomed.SnomedConcept, Union[cardinal_pythonlib.snomed.SnomedConcept, cardinal_pythonlib.snomed.SnomedExpression, int, float, str]], List[Union[cardinal_pythonlib.snomed.SnomedAttributeSet, cardinal_pythonlib.snomed.SnomedAttributeGroup]]]] = None)[source]
xml_element(longform: bool = True) camcops_server.cc_modules.cc_xml.XmlElement[source]

Returns a camcops_server.cc_modules.cc_xml.XmlElement for this SNOMED-CT object.

Parameters

longform – print SNOMED-CT expressions in long form?

class camcops_server.cc_modules.cc_snomed.SnomedLookup[source]

We’re not allowed to embed SNOMED-CT codes in the CamCOPS code. Therefore, within CamCOPS, we use string constants represented in this class. If the local institution is allowed (e.g. in the UK, as below), then it can install additional data.

Abbreviations:

  • “Finding” is not abbreviated

  • “Obs” or “observable” is short for “observable entity”

  • “Procedure” is not abbreviated

  • “Scale” is short for “assessment scale”

  • “Situation” is not abbreviated

Variable names are designed for clear code. Value strings are designed for clear XML that matches SNOMED-CT, in the format TASK_CONCEPTTYPE_NAME.

class camcops_server.cc_modules.cc_snomed.UmlsIcd9SnomedRow(icd_code: str, icd_name: str, is_current_icd: str, ip_usage: str, op_usage: str, avg_usage: str, is_nec: str, snomed_cid: str, snomed_fsn: str, is_one_to_one_map: str, core_usage: str, in_core: str)[source]

Simple information-holding class for a row of the ICD-9-CM TSV file, from https://www.nlm.nih.gov/research/umls/mapping_projects/icd9cm_to_snomedct.html.

NOT CURRENTLY USED.

__init__(icd_code: str, icd_name: str, is_current_icd: str, ip_usage: str, op_usage: str, avg_usage: str, is_nec: str, snomed_cid: str, snomed_fsn: str, is_one_to_one_map: str, core_usage: str, in_core: str) None[source]

Argument order is important.

Parameters
  • icd_code – ICD-9-CM code

  • icd_name – Name of ICD-9-CM entity

  • is_current_icd

    ?

  • ip_usage

    ?

  • op_usage

    ?

  • avg_usage

    ?

  • is_nec

    ?

  • snomed_cid – SNOMED-CT concept ID

  • snomed_fsn – SNOMED-CT fully specified name

  • is_one_to_one_map – ?; possibly always true in this dataset but not true in a broader dataset including things other than 1:1 mappings?

  • core_usage

    ?

  • in_core

    ?

snomed_concept() camcops_server.cc_modules.cc_snomed.SnomedConcept[source]

Returns the associated SNOMED-CT concept.

class camcops_server.cc_modules.cc_snomed.UmlsSnomedToIcd10Row(row_id: str, effective_time: str, active: str, module_id: str, refset_id: str, referenced_component_id: str, referenced_component_name: str, map_group: str, map_priority: str, map_rule: str, map_advice: str, map_target: str, map_target_name: str, correlation_id: str, map_category_id: str, map_category_name: str)[source]

Simple information-holding class for a row of the ICD-10-CM TSV file from https://www.nlm.nih.gov/research/umls/mapping_projects/snomedct_to_icd10cm.html.

However, that is unhelpful (many to one).

NOT CURRENTLY USED.

__init__(row_id: str, effective_time: str, active: str, module_id: str, refset_id: str, referenced_component_id: str, referenced_component_name: str, map_group: str, map_priority: str, map_rule: str, map_advice: str, map_target: str, map_target_name: str, correlation_id: str, map_category_id: str, map_category_name: str) None[source]

Argument order is important.

Parameters
  • row_id – UUID format or similar

  • effective_time – date in YYYYMMDD format

  • active

    ?

  • module_id

    ?

  • refset_id

    ?

  • referenced_component_id – SNOMED-CT concept ID

  • referenced_component_name – SNOMED-CT concept name

  • map_group – ?; e.g. 1

  • map_priority – ? but e.g. 1, 2; correlates with map_rule

  • map_rule – ?; e.g. “TRUE”; “OTHERWISE TRUE”

  • map_advice – ?, but e.g. “ALWAYS F32.2” or “ALWAYS F32.2 | DESCENDANTS NOT EXHAUSTIVELY MAPPED”

  • map_target – ICD-10 code

  • map_target_name – ICD-10 name

  • correlation_id – a SNOMED-CT concept for the mapping, e.g. 447561005 = “SNOMED CT source code to target map code correlation not specified (foundation metadata concept)”

  • map_category_id – a SNOMED-CT concept for the mapping, e.g. 447637006 = “Map source concept is properly classified (foundation metadata concept)”

  • map_category_name – SNOMED-CT name corresponding to map_category_id, e.g. “MAP SOURCE CONCEPT IS PROPERLY CLASSIFIED”

snomed_concept() camcops_server.cc_modules.cc_snomed.SnomedConcept[source]

Returns the associated SNOMED-CT concept.

camcops_server.cc_modules.cc_snomed.get_all_icd10_snomed_concepts_from_umls(tsv_filename: str) Dict[str, camcops_server.cc_modules.cc_snomed.SnomedConcept][source]

Reads in all ICD-10 SNOMED-CT codes that are supported by the client, from the UMLS data file, from https://www.nlm.nih.gov/research/umls/mapping_projects/snomedct_to_icd10cm.html.

Parameters

tsv_filename – TSV filename to read

Returns

maps lookup strings to SnomedConcept objects

Return type

dict

NOT CURRENTLY USED.

camcops_server.cc_modules.cc_snomed.get_all_icd9cm_snomed_concepts_from_umls(tsv_filename: str) Dict[str, camcops_server.cc_modules.cc_snomed.SnomedConcept][source]

Reads in all ICD-9-CM SNOMED-CT codes that are supported by the client, from the UMLS data file, from https://www.nlm.nih.gov/research/umls/mapping_projects/icd9cm_to_snomedct.html.

Parameters

tsv_filename – TSV filename to read

Returns

maps lookup strings to SnomedConcept objects

Return type

dict

NOT CURRENTLY USED.

camcops_server.cc_modules.cc_snomed.get_all_task_snomed_concepts(xml_filename: str) Dict[str, camcops_server.cc_modules.cc_snomed.SnomedConcept][source]

Reads in all SNOMED-CT codes for CamCOPS tasks, from the custom CamCOPS XML file for this.

Parameters

xml_filename – XML filename to read

Returns

maps lookup strings to SnomedConcept objects

Return type

dict

camcops_server.cc_modules.cc_snomed.get_icd10_snomed_concepts_from_xml(xml_filename: str) Dict[str, List[camcops_server.cc_modules.cc_snomed.SnomedConcept]][source]

Reads in all ICD-10 SNOMED-CT codes from a custom CamCOPS XML file.

Parameters

xml_filename – filename to read

Returns

maps ICD-10 codes to lists of SnomedConcept objects

Return type

dict

camcops_server.cc_modules.cc_snomed.get_icd9_snomed_concepts_from_xml(xml_filename: str) Dict[str, List[camcops_server.cc_modules.cc_snomed.SnomedConcept]][source]

Reads in all ICD-9-CM SNOMED-CT codes from a custom CamCOPS XML file.

Parameters

xml_filename – filename to read

Returns

maps ICD-9-CM codes to lists of SnomedConcept objects

Return type

dict

camcops_server.cc_modules.cc_snomed.get_icd9cm_icd10_snomed_concepts_from_athena(athena_concept_tsv_filename: str, athena_concept_relationship_tsv_filename: str) Tuple[Dict[str, List[camcops_server.cc_modules.cc_snomed.SnomedConcept]], Dict[str, List[camcops_server.cc_modules.cc_snomed.SnomedConcept]]][source]

Takes Athena concept and concept-relationship files, and fetches details of SNOMED-CT code for all ICD-9-CM and ICD-10[-CM] codes used by CamCOPS.

A bit of human review is required; this is probably preferable to using gensim or some other automatic similarity check.

Parameters
  • athena_concept_tsv_filename – path to CONCEPT.csv (a tab-separated value file)

  • athena_concept_relationship_tsv_filename – path to CONCEPT_RELATIONSHIP.csv (a tab-separated value file)

Returns

icd9cm, icd10, where each is a dictionary mapping ICD codes to a list of mapped SnomedConcept objects.

Return type

tuple

camcops_server.cc_modules.cc_snomed.get_multiple_snomed_concepts_from_xml(xml_filename: str, valid_lookups: Optional[Set[str]] = None, require_all: bool = False) Dict[str, List[camcops_server.cc_modules.cc_snomed.SnomedConcept]][source]

Reads in all SNOMED-CT codes for ICD-9 or ICD-10, from the custom CamCOPS XML file for this (made by e.g. send_athena_icd_snomed_to_xml()).

Parameters
  • xml_filename – XML filename to read

  • valid_lookups – possible lookup values

  • require_all – require that valid_lookups is truthy and that all values in it are present in the XML

Returns

maps lookup strings to lists of SnomedConcept objects

Return type

dict

camcops_server.cc_modules.cc_snomed.get_snomed_concepts_from_xml(xml_filename: str) Dict[str, Union[camcops_server.cc_modules.cc_snomed.SnomedConcept, List[camcops_server.cc_modules.cc_snomed.SnomedConcept]]][source]

Reads in all SNOMED-CT concepts from an XML file according to the CamCOPS format.

Parameters

xml_filename – XML filename to read

Returns

mapping each lookup code found to a list of SnomedConcept objects

Return type

dict

camcops_server.cc_modules.cc_snomed.send_athena_icd_snomed_to_xml(athena_concept_tsv_filename: str, athena_concept_relationship_tsv_filename: str, icd9_xml_filename: str, icd10_xml_filename) None[source]

Reads SNOMED-CT codes for ICD-9-CM and ICD10 from Athena OHDSI files, and writes

Parameters
  • athena_concept_tsv_filename – path to CONCEPT.csv (a tab-separated value file)

  • athena_concept_relationship_tsv_filename – path to CONCEPT_RELATIONSHIP.csv (a tab-separated value file)

  • icd9_xml_filename – ICD-9 XML filename to write

  • icd10_xml_filename – ICD-10 XML filename to write

camcops_server.cc_modules.cc_snomed.write_snomed_concepts_to_xml(xml_filename: str, concepts: Dict[str, List[camcops_server.cc_modules.cc_snomed.SnomedConcept]], comment: str = 'Autogenerated XML (see camcops_server.cc_modules.cc_snomed.py); do not edit') None[source]

Writes SNOMED-CT concepts to an XML file in the CamCOPS format.

Parameters
  • xml_filename – XML filename to write

  • concepts – dictionary mapping lookup codes to a list of SnomedConcept objects

  • comment – comment for XML file