@@ -16,93 +16,71 @@ def passes_relatedness_check(
16
16
relatedness_check_lookup : dict [tuple [str , str ], list ],
17
17
sample_id : str ,
18
18
other_id : str ,
19
- relation : Relation ,
19
+ expected_relation : Relation ,
20
+ additional_allowed_relation : Relation | None ,
20
21
) -> tuple [bool , str | None ]:
21
22
# No relationship to check, return true
22
23
if other_id is None :
23
24
return True , None
24
25
coefficients = relatedness_check_lookup .get (
25
26
(min (sample_id , other_id ), max (sample_id , other_id )),
26
27
)
27
- if not coefficients or not np .allclose (
28
- coefficients ,
29
- relation .coefficients ,
30
- atol = RELATEDNESS_TOLERANCE ,
28
+ if not coefficients or not any (
29
+ np .allclose (
30
+ coefficients ,
31
+ relation .coefficients ,
32
+ atol = RELATEDNESS_TOLERANCE ,
33
+ )
34
+ for relation in (
35
+ [expected_relation , additional_allowed_relation ]
36
+ if additional_allowed_relation
37
+ else [expected_relation ]
38
+ )
31
39
):
32
40
return (
33
41
False ,
34
- f'Sample { sample_id } has expected relation "{ relation .value } " to { other_id } but has coefficients { coefficients or []} ' ,
42
+ f'Sample { sample_id } has expected relation "{ expected_relation .value } " to { other_id } but has coefficients { coefficients or []} ' ,
35
43
)
36
44
return True , None
37
45
38
46
39
- def all_relatedness_checks ( # noqa: C901
47
+ def all_relatedness_checks (
40
48
relatedness_check_lookup : dict [tuple [str , str ], list ],
49
+ family : Family ,
41
50
sample : Sample ,
42
51
) -> list [str ]:
43
52
failure_reasons = []
44
- for parent_id in [sample . mother , sample . father ]:
45
- success , reason = passes_relatedness_check (
46
- relatedness_check_lookup ,
47
- sample . sample_id ,
48
- parent_id ,
49
- Relation . PARENT ,
50
- )
51
- if not success :
52
- failure_reasons . append ( reason )
53
-
54
- for grandparent_id in [
55
- sample . maternal_grandmother ,
56
- sample .maternal_grandfather ,
57
- sample .paternal_grandmother ,
58
- sample .paternal_grandfather ,
53
+ for relationship_set , relation , additional_allowed_relation in [
54
+ ([ sample . mother , sample . father ], Relation . PARENT_CHILD , None ),
55
+ (
56
+ [
57
+ sample . maternal_grandmother ,
58
+ sample . maternal_grandfather ,
59
+ sample . paternal_grandmother ,
60
+ sample . paternal_grandfather ,
61
+ ],
62
+ Relation . GRANDPARENT_GRANDCHILD ,
63
+ None ,
64
+ ) ,
65
+ ( sample .siblings , Relation . SIBLING , None ) ,
66
+ ( sample .half_siblings , Relation . HALF_SIBLING , Relation . SIBLING ) ,
67
+ ( sample .aunt_nephews , Relation . AUNT_NEPHEW , None ) ,
59
68
]:
60
- success , reason = passes_relatedness_check (
61
- relatedness_check_lookup ,
62
- sample .sample_id ,
63
- grandparent_id ,
64
- Relation .GRANDPARENT ,
65
- )
66
- if not success :
67
- failure_reasons .append (reason )
68
-
69
- for sibling_id in sample .siblings :
70
- success , reason = passes_relatedness_check (
71
- relatedness_check_lookup ,
72
- sample .sample_id ,
73
- sibling_id ,
74
- Relation .SIBLING ,
75
- )
76
- if not success :
77
- failure_reasons .append (reason )
78
-
79
- for half_sibling_id in sample .half_siblings :
80
- # NB: A "half sibling" parsed from the pedigree may actually be a sibling, so we allow those
81
- # through as well.
82
- success1 , _ = passes_relatedness_check (
83
- relatedness_check_lookup ,
84
- sample .sample_id ,
85
- half_sibling_id ,
86
- Relation .SIBLING ,
87
- )
88
- success2 , reason = passes_relatedness_check (
89
- relatedness_check_lookup ,
90
- sample .sample_id ,
91
- half_sibling_id ,
92
- Relation .HALF_SIBLING ,
93
- )
94
- if not success1 and not success2 :
95
- failure_reasons .append (reason )
96
-
97
- for aunt_nephew_id in sample .aunt_nephews :
98
- success , reason = passes_relatedness_check (
99
- relatedness_check_lookup ,
100
- sample .sample_id ,
101
- aunt_nephew_id ,
102
- Relation .AUNT_NEPHEW ,
103
- )
104
- if not success :
105
- failure_reasons .append (reason )
69
+ for other_id in relationship_set :
70
+ # Handle case where relation is identified in the
71
+ # pedigree as a "dummy" but is not included in
72
+ # the list of samples to load.
73
+ if other_id not in family .samples :
74
+ continue
75
+ success , reason = passes_relatedness_check (
76
+ relatedness_check_lookup ,
77
+ sample .sample_id ,
78
+ other_id ,
79
+ relation ,
80
+ additional_allowed_relation ,
81
+ )
82
+ if not success :
83
+ failure_reasons .append (reason )
106
84
return failure_reasons
107
85
108
86
@@ -162,6 +140,7 @@ def get_families_failed_relatedness_check(
162
140
for sample in family .samples .values ():
163
141
failure_reasons = all_relatedness_checks (
164
142
relatedness_check_lookup ,
143
+ family ,
165
144
sample ,
166
145
)
167
146
if failure_reasons :
0 commit comments