a b/tests/test_ontology.py
1
# flake8: noqa: E501
2
3
import pathlib
4
5
import femr.ontology
6
7
8
def create_fake_athena(tmp_path: pathlib.Path) -> pathlib.Path:
9
    athena = tmp_path / "athena"
10
    athena.mkdir()
11
12
    concept = athena / "CONCEPT.csv"
13
    concept.write_text(
14
        """concept_id   concept_name    domain_id   vocabulary_id   concept_class_id    standard_concept    concept_code    valid_start_date    valid_end_date  invalid_reason
15
37200198\tType 2 diabetes mellitus with mild nonproliferative diabetic retinopathy with macular edema, right eye\tCondition\tICD10CM\t7-char billing code\t\tE11.3211\t19700101\t20991231\t
16
380097\tMacular edema due to diabetes mellitus\tCondition\tSNOMED\tClinical Finding\tS\t312912001\t20020131\t20991231
17
4334884 Disorder of macula due to diabetes mellitus Condition   SNOMED  Clinical Finding    S   232020009   20020131    20991231
18
4174977 Retinopathy due to diabetes mellitus    Condition   SNOMED  Clinical Finding    S   4855003 20020131    20991231
19
4208223 Disorder of macula of retina    Condition   SNOMED  Clinical Finding    S   312999006   20020131    20991231
20
4290333 Macular retinal edema   Condition   SNOMED  Clinical Finding    S   37231002    20020131    20991231
21
35626904    Retinal edema due to diabetes mellitus  Condition   SNOMED  Clinical Finding    S   770323005   20180731    20991231
22
45757435    Mild nonproliferative retinopathy due to type 2 diabetes mellitus   Condition   SNOMED  Clinical Finding    S   138911000119106 20150131    20991231
23
"""
24
    )
25
    relationship = athena / "CONCEPT_RELATIONSHIP.csv"
26
    relationship.write_text(
27
        """concept_id_1 concept_id_2    relationship_id valid_start_date    valid_end_date  invalid_reason
28
37200198    380097  Maps to 20171001    20991231
29
37200198    1567956 Is a    20170428    20991231
30
37200198    1567959 Is a    20170428    20991231
31
37200198    45757435    Maps to 20171001    20991231
32
37200198    1567961 Is a    20170428    20991231
33
37200198    45552385    Is a    20170428    20991231
34
35977781    35977781    Mapped from 20200913    20991231
35
46135811    40642538    Has status  20220128    20991231
36
46135811    35631990    Has Module  20220128    20991231"""
37
    )
38
39
    ancestor = athena / "CONCEPT_ANCESTOR.csv"
40
    ancestor.write_text(
41
        """ancestor_concept_id\tdescendant_concept_id\tmin_levels_of_separation\tmax_levels_of_separation
42
373499  4334884 4   6
43
442793  4334884 3   3
44
255919  4334884 6   9
45
433128  4334884 4   4
46
4180628 4334884 6   8
47
4209989 4334884 3   3
48
441840  4334884 6   10
49
4274025 4334884 5   9
50
4082284 4334884 2   2
51
4042836 4334884 5   7
52
443767  4334884 2   2
53
4038502 4334884 5   8
54
4174977 4334884 1   1
55
4334884 4334884 0   0
56
4134440 4334884 5   7
57
4247371 4334884 5   8
58
375252  4334884 3   5
59
4027883 4334884 4   4
60
4208223 4334884 1   1
61
378416  4334884 2   2
62
4080992 4334884 4   6
63
4162092 4334884 3   3
64
255919  380097  7   10
65
433128  380097  5   5
66
442793  380097  4   4
67
373499  380097  5   7
68
4180628 380097  7   9
69
4209989 380097  4   4
70
37018677    380097  3   3
71
441840  380097  5   11
72
380097  380097  0   0
73
4274025 380097  4   10
74
372903  380097  2   2
75
433595  380097  4   4
76
4042836 380097  6   8
77
4082284 380097  3   3
78
443767  380097  3   3
79
4038502 380097  6   9
80
4174977 380097  2   2
81
4334884 380097  1   1
82
4134440 380097  6   8
83
4247371 380097  6   9
84
4290333 380097  1   1
85
375252  380097  4   6
86
4027883 380097  5   5
87
4040388 380097  3   3
88
4208223 380097  2   2
89
35626904    380097  1   1
90
378416  380097  3   3
91
4080992 380097  5   7
92
4162092 380097  4   4
93
"""
94
    )
95
96
    return athena
97
98
99
def test_only_athena(tmp_path: pathlib.Path) -> None:
100
    fake_athena = create_fake_athena(tmp_path)
101
102
    ontology = femr.ontology.Ontology(str(fake_athena))
103
104
    assert (
105
        ontology.get_description("ICD10CM/E11.3211")
106
        == "Type 2 diabetes mellitus with mild nonproliferative diabetic retinopathy with macular edema, right eye"
107
    )
108
109
    assert ontology.get_parents("ICD10CM/E11.3211") == {"SNOMED/312912001", "SNOMED/138911000119106"}
110
    assert ontology.get_parents("SNOMED/312912001") == {"SNOMED/37231002", "SNOMED/232020009", "SNOMED/770323005"}
111
112
    assert ontology.get_all_parents("ICD10CM/E11.3211") == {
113
        "SNOMED/37231002",
114
        "SNOMED/138911000119106",
115
        "SNOMED/4855003",
116
        "SNOMED/312999006",
117
        "SNOMED/312912001",
118
        "ICD10CM/E11.3211",
119
        "SNOMED/770323005",
120
        "SNOMED/232020009",
121
    }
122
123
    assert ontology.get_children("SNOMED/312912001") == {"ICD10CM/E11.3211"}
124
    assert ontology.get_children("SNOMED/37231002") == {"SNOMED/312912001"}
125
126
    assert ontology.get_all_children("SNOMED/37231002") == {"ICD10CM/E11.3211", "SNOMED/312912001", "SNOMED/37231002"}
127
128
129
def test_athena_and_custom(tmp_path: pathlib.Path) -> None:
130
    fake_athena = create_fake_athena(tmp_path)
131
132
    code_metadata = {
133
        "CUSTOM/CustomDiabetes": {"description": "A nice diabetes code", "parent_codes": ["ICD10CM/E11.3211"]}
134
    }
135
136
    ontology = femr.ontology.Ontology(str(fake_athena), code_metadata)
137
138
    assert ontology.get_description("CUSTOM/CustomDiabetes") == "A nice diabetes code"
139
    assert ontology.get_all_parents("CUSTOM/CustomDiabetes") == {
140
        "CUSTOM/CustomDiabetes",
141
        "SNOMED/37231002",
142
        "SNOMED/138911000119106",
143
        "SNOMED/4855003",
144
        "SNOMED/312999006",
145
        "SNOMED/312912001",
146
        "ICD10CM/E11.3211",
147
        "SNOMED/770323005",
148
        "SNOMED/232020009",
149
    }
150
151
    assert ontology.get_all_children("SNOMED/37231002") == {
152
        "CUSTOM/CustomDiabetes",
153
        "ICD10CM/E11.3211",
154
        "SNOMED/312912001",
155
        "SNOMED/37231002",
156
    }