line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Convert::Pheno::BFF; |
2
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
44
|
use strict; |
|
6
|
|
|
|
|
29
|
|
|
6
|
|
|
|
|
203
|
|
4
|
6
|
|
|
6
|
|
46
|
use warnings; |
|
6
|
|
|
|
|
27
|
|
|
6
|
|
|
|
|
165
|
|
5
|
6
|
|
|
6
|
|
35
|
use autodie; |
|
6
|
|
|
|
|
22
|
|
|
6
|
|
|
|
|
42
|
|
6
|
6
|
|
|
6
|
|
34583
|
use feature qw(say); |
|
6
|
|
|
|
|
23
|
|
|
6
|
|
|
|
|
575
|
|
7
|
6
|
|
|
6
|
|
50
|
use Convert::Pheno::Mapping; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
702
|
|
8
|
6
|
|
|
6
|
|
52
|
use Convert::Pheno::PXF; |
|
6
|
|
|
|
|
19
|
|
|
6
|
|
|
|
|
351
|
|
9
|
6
|
|
|
6
|
|
41
|
use Exporter 'import'; |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
4396
|
|
10
|
|
|
|
|
|
|
our @EXPORT = qw(do_bff2pxf); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
############# |
13
|
|
|
|
|
|
|
############# |
14
|
|
|
|
|
|
|
# BFF2PXF # |
15
|
|
|
|
|
|
|
############# |
16
|
|
|
|
|
|
|
############# |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub do_bff2pxf { |
19
|
|
|
|
|
|
|
|
20
|
583
|
|
|
583
|
0
|
846
|
my ( $self, $bff ) = @_; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Premature return |
23
|
583
|
50
|
|
|
|
1109
|
return unless defined($bff); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Define defaults |
26
|
583
|
|
|
|
|
785
|
my $default_timestamp = '1900-01-01T00:00:00Z'; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
######################################### |
29
|
|
|
|
|
|
|
# START MAPPING TO PHENOPACKET V2 TERMS # |
30
|
|
|
|
|
|
|
######################################### |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# We need to shuffle a bit some Beacon v2 properties to be Phenopacket compliant |
33
|
|
|
|
|
|
|
# Order of terms (not alphabetical) taken from: |
34
|
|
|
|
|
|
|
# - https://phenopacket-schema.readthedocs.io/en/latest/phenopacket.html |
35
|
|
|
|
|
|
|
|
36
|
583
|
|
|
|
|
629
|
my $pxf; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# == |
39
|
|
|
|
|
|
|
# id |
40
|
|
|
|
|
|
|
# == |
41
|
|
|
|
|
|
|
|
42
|
583
|
100
|
|
|
|
1198
|
$pxf->{id} = $self->{test} ? undef : 'phenopacket_id.' . randStr(8); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# ======= |
45
|
|
|
|
|
|
|
# subject |
46
|
|
|
|
|
|
|
# ======= |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
$pxf->{subject} = { |
49
|
|
|
|
|
|
|
id => $bff->{id}, |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
#alternateIds => [], |
52
|
|
|
|
|
|
|
#_age => $bff->{info}{age} |
53
|
|
|
|
|
|
|
#timeAtLastEncounter => {}, |
54
|
|
|
|
|
|
|
vitalStatus => { status => 'ALIVE' }, #["UNKNOWN_STATUS", "ALIVE", "DECEASED"] |
55
|
583
|
|
|
|
|
2483
|
sex => uc( $bff->{sex}{label} ), |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
#taxonomy => {} ; |
58
|
|
|
|
|
|
|
#_age => $bff->{info}{age} |
59
|
|
|
|
|
|
|
}; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Miscellanea |
62
|
583
|
|
|
|
|
1054
|
for (qw(dateOfBirth)) { |
63
|
583
|
100
|
|
|
|
1703
|
$pxf->{subject}{$_} = $bff->{info}{$_} if exists $bff->{info}{$_}; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# karyotypicSex |
67
|
|
|
|
|
|
|
$pxf->{subject}{karyotypicSex} = $bff->{karyotypicSex} |
68
|
583
|
50
|
|
|
|
1067
|
if exists $bff->{karyotypicSex}; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# =================== |
71
|
|
|
|
|
|
|
# phenotypicFeatures |
72
|
|
|
|
|
|
|
# =================== |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
$pxf->{phenotypicFeatures} = [ |
75
|
|
|
|
|
|
|
map { |
76
|
|
|
|
|
|
|
{ |
77
|
|
|
|
|
|
|
type => delete $_->{featureType}, |
78
|
|
|
|
|
|
|
excluded => delete $_->{excluded} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
#_notes => $_->{notes} |
81
|
|
|
|
|
|
|
} |
82
|
243
|
|
|
|
|
1036
|
} @{ $bff->{phenotypicFeatures} } |
|
124
|
|
|
|
|
824
|
|
83
|
|
|
|
|
|
|
] |
84
|
583
|
100
|
|
|
|
932
|
if defined $bff->{phenotypicFeatures}; |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# ============ |
87
|
|
|
|
|
|
|
# measurements |
88
|
|
|
|
|
|
|
# ============ |
89
|
583
|
100
|
|
|
|
1043
|
if ( defined $bff->{measures} ) { |
90
|
83
|
|
|
|
|
114
|
$pxf->{measurements} = []; # Initialize as an empty array reference |
91
|
|
|
|
|
|
|
|
92
|
83
|
|
|
|
|
97
|
for my $measure ( @{ $bff->{measures} } ) { |
|
83
|
|
|
|
|
170
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Check if measurementValue hash contain the typedQuantities key |
95
|
|
|
|
|
|
|
my $has_typedQuantities = |
96
|
1147
|
50
|
|
|
|
3101
|
exists $measure->{measurementValue}{typedQuantities} ? 1 : 0; |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# Construct the hash |
99
|
1147
|
|
|
|
|
2231
|
my $result = { assay => $measure->{assayCode} }; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Add the complexValue key if typedQuantities was found |
102
|
1147
|
50
|
|
|
|
1290
|
if ($has_typedQuantities) { |
103
|
0
|
|
|
|
|
0
|
$result->{complexValue} = $measure->{measurementValue}; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
else { |
106
|
1147
|
|
|
|
|
1243
|
$result->{value} = $measure->{measurementValue}; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# Push the resulting hash onto the pxf measurements array |
111
|
1147
|
|
|
|
|
1019
|
push @{ $pxf->{measurements} }, $result; |
|
1147
|
|
|
|
|
1862
|
|
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# ========== |
116
|
|
|
|
|
|
|
# biosamples |
117
|
|
|
|
|
|
|
# ========== |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# =============== |
120
|
|
|
|
|
|
|
# interpretations |
121
|
|
|
|
|
|
|
# =============== |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
#$bff->{interpretation} = {}; |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# ======== |
126
|
|
|
|
|
|
|
# diseases |
127
|
|
|
|
|
|
|
# ======== |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
$pxf->{diseases} = |
130
|
569
|
|
|
|
|
1668
|
[ map { { term => $_->{diseaseCode}, onset => $_->{ageOfOnset} } } |
131
|
583
|
|
|
|
|
698
|
@{ $bff->{diseases} } ]; |
|
583
|
|
|
|
|
1336
|
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# =============== |
134
|
|
|
|
|
|
|
# medicalActions |
135
|
|
|
|
|
|
|
# =============== |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# **** procedures **** |
138
|
|
|
|
|
|
|
my @procedures = map { |
139
|
|
|
|
|
|
|
{ |
140
|
|
|
|
|
|
|
procedure => { |
141
|
|
|
|
|
|
|
code => $_->{procedureCode}, |
142
|
|
|
|
|
|
|
performed => { |
143
|
|
|
|
|
|
|
timestamp => exists $_->{dateOfProcedure} |
144
|
|
|
|
|
|
|
? _map2iso8601( $_->{dateOfProcedure} ) |
145
|
576
|
100
|
|
|
|
1657
|
: $default_timestamp |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
} |
149
|
583
|
|
|
|
|
830
|
} @{ $bff->{interventionsOrProcedures} }; |
|
583
|
|
|
|
|
1202
|
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# **** treatments **** |
152
|
|
|
|
|
|
|
my @treatments = map { |
153
|
|
|
|
|
|
|
{ |
154
|
|
|
|
|
|
|
treatment => { |
155
|
|
|
|
|
|
|
agent => $_->{treatmentCode}, |
156
|
|
|
|
|
|
|
routeOfAdministration => $_->{routeOfAdministration}, |
157
|
|
|
|
|
|
|
doseIntervals => $_->{doseIntervals} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
#performed => { timestamp => exists $_->{dateOfProcedure} ? $_->{dateOfProcedure} : undef} |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
} |
162
|
583
|
|
|
|
|
697
|
} @{ $bff->{treatments} }; |
|
300
|
|
|
|
|
1228
|
|
|
583
|
|
|
|
|
1480
|
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Load |
165
|
583
|
100
|
|
|
|
1187
|
push @{ $pxf->{medicalActions} }, @procedures if @procedures; |
|
157
|
|
|
|
|
400
|
|
166
|
583
|
100
|
|
|
|
934
|
push @{ $pxf->{medicalActions} }, @treatments if @treatments; |
|
48
|
|
|
|
|
214
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# ===== |
169
|
|
|
|
|
|
|
# files |
170
|
|
|
|
|
|
|
# ===== |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# ========= |
173
|
|
|
|
|
|
|
# metaData |
174
|
|
|
|
|
|
|
# ========= |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# Depending on the origion (redcap) , _info and resources may exist |
177
|
|
|
|
|
|
|
$pxf->{metaData} = |
178
|
|
|
|
|
|
|
$self->{test} ? undef |
179
|
|
|
|
|
|
|
: exists $bff->{info}{metaData} ? $bff->{info}{metaData} |
180
|
583
|
50
|
|
|
|
1058
|
: get_metaData($self); |
|
|
100
|
|
|
|
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# ========= |
183
|
|
|
|
|
|
|
# exposures |
184
|
|
|
|
|
|
|
# ========= |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# Can't be mapped as Sept-2023 from pxf-tools |
187
|
|
|
|
|
|
|
# Message type "org.phenopackets.schema.v2.Phenopacket" has no field named "exposures" at "Phenopacket". |
188
|
|
|
|
|
|
|
# Available Fields(except extensions): "['id', 'subject', 'phenotypicFeatures', 'measurements', 'biosamples', 'interpretations', 'diseases', 'medicalActions', 'files', 'metaData']" at line 22 |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# $pxf->{exposures} = |
191
|
|
|
|
|
|
|
# |
192
|
|
|
|
|
|
|
# [ |
193
|
|
|
|
|
|
|
# map { |
194
|
|
|
|
|
|
|
# { |
195
|
|
|
|
|
|
|
# type => $_->{exposureCode}, |
196
|
|
|
|
|
|
|
# occurrence => { timestamp => $_->{date} } |
197
|
|
|
|
|
|
|
# } |
198
|
|
|
|
|
|
|
# } @{ $bff->{exposures} } |
199
|
|
|
|
|
|
|
# ] |
200
|
|
|
|
|
|
|
# if exists $bff->{exposures}; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
####################################### |
203
|
|
|
|
|
|
|
# END MAPPING TO PHENOPACKET V2 TERMS # |
204
|
|
|
|
|
|
|
####################################### |
205
|
|
|
|
|
|
|
|
206
|
583
|
|
|
|
|
1299
|
return $pxf; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
1; |