1 /*
2  *  Copyright (C) 2010  Regents of the University of Michigan
3  *
4  *   This program is free software: you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation, either version 3 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "PedigreePerson.h"
19 #include "Constant.h"
20 #include "StringArray.h"
21 #include "Error.h"
22 
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <limits.h>
27 
Person()28 Person::Person()
29 {
30     zygosity = sex = 0;
31     serial = traverse = -1;
32 
33     markers = new Alleles [markerCount];
34     traits = new double [traitCount];
35     covariates = new double [covariateCount];
36     affections = new char [affectionCount];
37     strings = new String [stringCount];
38 
39     for (int i = 0; i < traitCount; i++) traits[i] = _NAN_;
40     for (int i = 0; i < covariateCount; i++) covariates[i] = _NAN_;
41     for (int i = 0; i < affectionCount; i++) affections[i] = 0;
42 
43     filter = false;
44 
45     father = mother = NULL;
46     sibs = NULL;
47     sibCount = 0;
48 
49     ngeno = 0;
50     hasBothParents = hasAllTraits = hasAllAffections = hasAllCovariates = false;
51 }
52 
~Person()53 Person::~Person()
54 {
55     delete [] markers;
56     delete [] traits;
57     delete [] affections;
58     delete [] covariates;
59     delete [] strings;
60 
61     if (sibCount) delete [] sibs;
62 }
63 
Copy(Person & rhs)64 void Person::Copy(Person & rhs)
65 {
66     CopyIDs(rhs);
67     CopyPhenotypes(rhs);
68 }
69 
CopyPhenotypes(Person & rhs)70 void Person::CopyPhenotypes(Person & rhs)
71 {
72     for (int i = 0; i < Person::traitCount; i++)
73         traits[i] = rhs.traits[i];
74     for (int i = 0; i < Person::affectionCount; i++)
75         affections[i] = rhs.affections[i];
76     for (int i = 0; i < Person::covariateCount; i++)
77         covariates[i] = rhs.covariates[i];
78     for (int i = 0; i < Person::markerCount; i++)
79         markers[i] = rhs.markers[i];
80     ngeno = rhs.ngeno;
81 }
82 
WipePhenotypes(bool remove_genotypes)83 void Person::WipePhenotypes(bool remove_genotypes)
84 {
85     for (int i = 0; i < traitCount; i++) traits[i] = _NAN_;
86     for (int i = 0; i < covariateCount; i++) covariates[i] = _NAN_;
87     for (int i = 0; i < affectionCount; i++) affections[i] = 0;
88 
89     if (remove_genotypes)
90     {
91         for (int i = 0; i < markerCount; i++)
92             markers[i][0] = markers[i][1] = 0;
93         ngeno = 0;
94     }
95 }
96 
CopyIDs(Person & rhs)97 void Person::CopyIDs(Person & rhs)
98 {
99     famid = rhs.famid;
100     pid = rhs.pid;
101     fatid = rhs.fatid;
102     motid = rhs.motid;
103     sex = rhs.sex;
104     zygosity = rhs.zygosity;
105 }
106 
CheckParents()107 bool Person::CheckParents()
108 {
109     hasBothParents = father != NULL && mother != NULL;
110 
111     if (!hasBothParents)
112     {
113         if (father != NULL || mother != NULL)
114         {
115             printf("Parent named %s for Person %s in Family %s is missing\n",
116                    (father == NULL) ? (const char *) fatid : (const char *) motid,
117                    (const char *) pid, (const char *) famid);
118             return false;
119         }
120         else
121             return true;
122     }
123 
124     if (father->sex == SEX_FEMALE || mother->sex == SEX_MALE)
125         // If parents are switched around, we can fix it...
126     {
127         Person * swap = father;
128         father = mother;
129         mother = swap;
130 
131         String temp = fatid;
132         fatid = motid;
133         motid = temp;
134     }
135 
136     if (father->sex == SEX_FEMALE || mother->sex == SEX_MALE)
137         // If things still don't make sense then the problem is more serious ...
138     {
139         printf("Parental sex codes don't make sense for Person %s in Family %s\n",
140                (const char *) pid, (const char *) famid);
141         return false;
142     }
143 
144     return true;
145 }
146 
AssessStatus()147 void Person::AssessStatus()
148 {
149     hasBothParents = father != NULL && mother != NULL;
150 
151     hasAllTraits = hasAllAffections = hasAllCovariates = true;
152 
153     ngeno = 0;
154     for (int m = 0; m < markerCount; m++)
155         if (isGenotyped(m))
156             ngeno++;
157 
158     for (int t = 0; t < traitCount; t++)
159         if (!isPhenotyped(t))
160         {
161             hasAllTraits = false;
162             break;
163         }
164 
165     for (int c = 0; c < covariateCount; c++)
166         if (!isControlled(c))
167         {
168             hasAllCovariates = false;
169             break;
170         }
171 
172     for (int a = 0; a < affectionCount; a++)
173         if (!isDiagnosed(a))
174         {
175             hasAllAffections = false;
176             break;
177         }
178 }
179 
Order(Person * & p1,Person * & p2)180 void Person::Order(Person * & p1, Person * & p2)
181 {
182     if (p1->traverse > p2->traverse)
183     {
184         Person * temp = p1;
185         p1 = p2;
186         p2 = temp;
187     }
188 }
189 
GenotypedMarkers()190 int Person::GenotypedMarkers()
191 {
192     int count = 0;
193 
194     for (int m = 0; m < Person::markerCount; m++)
195         if (markers[m].isKnown())
196             count++;
197 
198     return count;
199 }
200 
haveData()201 bool Person::haveData()
202 {
203     if (ngeno)
204         return true;
205 
206     for (int i = 0; i < affectionCount; i++)
207         if (affections[i] != 0)
208             return true;
209 
210     for (int i = 0; i < traitCount; i++)
211         if (traits[i] != _NAN_)
212             return true;
213 
214     return false;
215 }
216 
isAncestor(Person * descendant)217 bool Person::isAncestor(Person * descendant)
218 {
219     if (traverse > descendant->traverse)
220         return false;
221 
222     if (serial == descendant->serial)
223         return true;
224 
225     if (descendant->isFounder())
226         return false;
227 
228     return (isAncestor(descendant->mother) ||
229             isAncestor(descendant->father));
230 }
231