1 // $Id: ui_vars_traitmodels.cpp,v 1.17 2012/01/07 00:31:58 ewalkup Exp $
2
3 /*
4 * Copyright 2004 Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein
5 *
6 * This software is distributed free of charge for non-commercial use
7 * and is copyrighted. Of course, we do not guarantee that the software
8 * works, and are not responsible for any damage you may cause or have.
9 *
10 */
11
12 #include <cassert>
13
14 #include "locus.h"
15 #include "ui_regid.h"
16 #include "ui_vars.h"
17 #include "ui_vars_traitmodels.h"
18
19 #define DEFAULTMLOC mloc_mapfloat
20 #define MAXMULTIHAP 20
21
22 using namespace std;
23
24 //------------------------------------------------------------------------------------
25
ToString(mloc_type type)26 string ToString(mloc_type type)
27 {
28 switch(type)
29 {
30 case mloc_data:
31 return "use as data";
32 case mloc_mapjump:
33 return "mapping (jump)";
34 case mloc_mapfloat:
35 return "mapping (float)";
36 case mloc_partition:
37 return "partition the data";
38 }
39 assert(false);
40 throw implementation_error("Uncaught moving locus analysis type.");
41 }
42
ToXMLString(mloc_type type)43 string ToXMLString(mloc_type type)
44 {
45 switch(type)
46 {
47 case mloc_data:
48 return "data";
49 case mloc_mapjump:
50 return "jump";
51 case mloc_mapfloat:
52 return "float";
53 case mloc_partition:
54 return "partition";
55 }
56 assert(false);
57 throw implementation_error("Uncaught moving locus analysis type.");
58 }
59
ProduceMlocTypeOrBarf(const string & in)60 mloc_type ProduceMlocTypeOrBarf(const string& in)
61 {
62 std::string st = in;
63 LowerCase(st);
64 if (st == "data") { return mloc_data; };
65 if (st == "jump") { return mloc_mapjump; };
66 if (st == "float") { return mloc_mapfloat; };
67 if (st == "partition") { return mloc_partition; };
68 throw data_error("Illegal trait analysis setting \""+in+"\"");
69 }
70
UIVarsSingleTraitModel(UIRegId regionId,string name,rangeset mrange,rangepair fullr,const Locus * locus,long multihapnum)71 UIVarsSingleTraitModel::UIVarsSingleTraitModel(UIRegId regionId, string name,
72 rangeset mrange,rangepair fullr,
73 const Locus* locus,
74 long multihapnum)
75 : m_region(regionId.GetRegion()),
76 m_locus(regionId.GetLocus()),
77 m_datatype(regionId.GetDataType()),
78 m_type(DEFAULTMLOC),
79 m_range(mrange),
80 m_fullrange(fullr),
81 m_name(name),
82 m_phenotypes(regionId.GetRegion(), locus->GetName()),
83 m_multihapnum(multihapnum)
84 {
85 assert(m_datatype == dtype_kallele); //We don't have models for other types.
86 assert(m_range.size() > 0);
87 if (m_range.size() == 1)
88 {
89 if (m_range.begin()->first +1 == m_range.begin()->second)
90 {
91 m_type = mloc_data;
92 }
93 }
94 if ((m_type != mloc_data) && (m_multihapnum > MAXMULTIHAP))
95 {
96 m_type = mloc_mapjump;
97 }
98 }
99
~UIVarsSingleTraitModel()100 UIVarsSingleTraitModel::~UIVarsSingleTraitModel()
101 {
102 }
103
SetAnalysisType(mloc_type type)104 void UIVarsSingleTraitModel::SetAnalysisType(mloc_type type)
105 {
106 m_type = type;
107 }
108
SetRange(rangeset range)109 void UIVarsSingleTraitModel::SetRange(rangeset range)
110 {
111 m_range = range;
112 }
113
AddPhenotype(StringVec1d & alleles,string name,double penetrance)114 void UIVarsSingleTraitModel::AddPhenotype(StringVec1d& alleles, string name, double penetrance)
115 {
116 m_phenotypes.AddPhenotype(alleles, name, penetrance);
117 }
118
119 //------------------------------------------------------------------------------------
120
UIVarsTraitModels(UIVars * myUIVars)121 UIVarsTraitModels::UIVarsTraitModels(UIVars* myUIVars)
122 : UIVarsComponent(myUIVars),
123 m_individualModels()
124 {
125 //Requires that datapackplus be set up in the uivars.
126 long nregions = GetConstUIVars().datapackplus.GetNumRegions();
127 for(long regionIndex=0; regionIndex < nregions; regionIndex++)
128 {
129 long numLoci = GetConstUIVars().datapackplus.GetNumLoci(regionIndex);
130 for(long locusIndex=0; locusIndex < numLoci; locusIndex++)
131 {
132 if (GetConstUIVars().datapackplus.IsMovable(regionIndex, locusIndex))
133 {
134 UIRegId regID(regionIndex, locusIndex, GetConstUIVars());
135 AddTraitModel(regID);
136 }
137 }
138 }
139 }
140
UIVarsTraitModels(UIVars * myUIVars,const UIVarsTraitModels & clone)141 UIVarsTraitModels::UIVarsTraitModels(UIVars* myUIVars, const UIVarsTraitModels& clone)
142 : UIVarsComponent(myUIVars),
143 m_individualModels(clone.m_individualModels)
144 {
145 }
146
~UIVarsTraitModels()147 UIVarsTraitModels::~UIVarsTraitModels()
148 {
149 }
150
AddTraitModel(UIRegId regID)151 void UIVarsTraitModels::AddTraitModel(UIRegId regID)
152 {
153 assert(m_individualModels.find(regID) == m_individualModels.end());
154 string name = GetConstUIVars().datapackplus.GetName(regID.GetRegion(), regID.GetLocus());
155 rangeset mrange = GetConstUIVars().datapackplus.GetRange(regID.GetRegion(), regID.GetLocus());
156 rangepair fullrange = GetConstUIVars().datapackplus.GetRegionSiteSpan(regID.GetRegion());
157 long multihapnum = GetConstUIVars().datapackplus.GetNumIndividualsWithMultipleHaplotypes(regID.GetRegion(), name);
158 if (mrange.size() == 0)
159 {
160 //Nothing originally set, so we'll allow the whole thing.
161 mrange.insert(fullrange);
162 }
163 const Locus* locus = GetConstUIVars().datapackplus.GetConstLocusPointer(regID.GetRegion(), regID.GetLocus());
164 fullrange.second++; // EWFIX. WHY WHY WHY
165 UIVarsSingleTraitModel tmodel(regID, name, mrange, fullrange, locus, multihapnum);
166 m_individualModels.insert(make_pair(regID, tmodel));
167 }
168
169 //Setters
170
SetAnalysisType(UIRegId regID,mloc_type type)171 void UIVarsTraitModels::SetAnalysisType(UIRegId regID, mloc_type type)
172 {
173 assert(m_individualModels.find(regID) != m_individualModels.end());
174 UIVarsSingleTraitModel& model = m_individualModels.find(regID)->second;
175 switch(type)
176 {
177 case mloc_data:
178 //We need to make sure there's only one site where it can be placed.
179 if (!OneSite(model.GetRange()))
180 {
181 throw data_error("You may not set the trait analysis type to 'data' without specifying the exact position of your trait.");
182 }
183 break;
184 case mloc_partition:
185 throw data_error("We are not set up to use trait data to set partitions yet. Soon!");
186 case mloc_mapfloat:
187 if (model.GetMultiHapNum() > MAXMULTIHAP)
188 {
189 throw data_error("You have too many individuals (" + ToString(model.GetMultiHapNum()) + ", which is more than maximum " + ToString(MAXMULTIHAP) + " allowed) with multiple haplotype resolutions (such as heterozygotes or individuals with a dominant phenotype) to perform a 'floating' analysis--the number of complete likelihood calculations required per tree is 2^N, with N the number of individuals with multiple resolutions. We recommend either a 'jumping' analysis, or that you remove (at random) individuals from your data set.");
190 }
191 //Otherwise, fall through to:
192 case mloc_mapjump:
193 if (OneSite(model.GetRange()))
194 {
195 GetConstUIVars().GetUI()->AddWarning("You currently have only a single site where your trait is allowed. The mapping analysis will not have anything to compare it to. Use the 'A' option to add more sites to the analysis.");
196 }
197 break;
198 }
199 model.SetAnalysisType(type);
200 }
201
AddRange(UIRegId regID,rangepair addpart)202 void UIVarsTraitModels::AddRange(UIRegId regID, rangepair addpart)
203 {
204 assert(m_individualModels.find(regID) != m_individualModels.end());
205 rangeset rset = m_individualModels.find(regID)->second.GetRange();
206 rset = AddPairToRange(addpart, rset);
207 SetRange(regID, rset);
208 }
209
RemoveRange(UIRegId regID,rangepair removepart)210 void UIVarsTraitModels::RemoveRange(UIRegId regID, rangepair removepart)
211 {
212 assert(m_individualModels.find(regID) != m_individualModels.end());
213 rangeset rset = m_individualModels.find(regID)->second.GetRange();
214 rset = RemovePairFromRange(removepart, rset);
215 SetRange(regID, rset);
216 }
217
SetRangeToPoint(UIRegId regID,long site)218 void UIVarsTraitModels::SetRangeToPoint(UIRegId regID, long site)
219 {
220 assert(m_individualModels.find(regID) != m_individualModels.end());
221 rangepair rp(make_pair(site, site+1));
222 rangeset rset;
223 rset.insert(rp);
224 SetRange(regID, rset);
225 }
226
AddPhenotype(UIRegId regID,StringVec1d & alleles,string name,double penetrance)227 void UIVarsTraitModels::AddPhenotype(UIRegId regID, StringVec1d& alleles, string name, double penetrance)
228 {
229 assert(m_individualModels.find(regID) != m_individualModels.end());
230 m_individualModels.find(regID)->second.AddPhenotype(alleles, name, penetrance);
231 }
232
233 //Getters:
GetNumMovableLoci() const234 long UIVarsTraitModels::GetNumMovableLoci() const
235 {
236 return m_individualModels.size();
237 }
238
GetAnalysisType(UIRegId regID) const239 mloc_type UIVarsTraitModels::GetAnalysisType(UIRegId regID) const
240 {
241 assert(m_individualModels.find(regID) != m_individualModels.end());
242 return m_individualModels.find(regID)->second.GetAnalysisType();
243 }
244
GetRange(UIRegId regID) const245 rangeset UIVarsTraitModels::GetRange(UIRegId regID) const
246 {
247 assert(m_individualModels.find(regID) != m_individualModels.end());
248 return m_individualModels.find(regID)->second.GetRange();
249 }
250
GetInitialMapPosition(UIRegId regID) const251 long UIVarsTraitModels::GetInitialMapPosition(UIRegId regID) const
252 {
253 //Just use the leftmost valid point.
254 return GetRange(regID).begin()->first;
255 }
256
GetName(UIRegId regID) const257 string UIVarsTraitModels::GetName(UIRegId regID) const
258 {
259 assert(m_individualModels.find(regID) != m_individualModels.end());
260 return m_individualModels.find(regID)->second.GetName();
261 }
262
GetPhenotypes(UIRegId regID) const263 Phenotypes UIVarsTraitModels::GetPhenotypes(UIRegId regID) const
264 {
265 assert(m_individualModels.find(regID) != m_individualModels.end());
266 return m_individualModels.find(regID)->second.GetPhenotypes();
267 }
268
GetRegIDs() const269 vector<UIRegId> UIVarsTraitModels::GetRegIDs() const
270 {
271 vector<UIRegId> retvec;
272 for (std::map<UIRegId, UIVarsSingleTraitModel>::const_iterator model = m_individualModels.begin(); model != m_individualModels.end(); model++)
273 {
274 retvec.push_back(model->first);
275 }
276 return retvec;
277 }
278
AnyJumpingAnalyses() const279 bool UIVarsTraitModels::AnyJumpingAnalyses() const
280 {
281 for (std::map<UIRegId, UIVarsSingleTraitModel>::const_iterator model = m_individualModels.begin(); model != m_individualModels.end(); model++)
282 {
283 if (model->second.GetAnalysisType() == mloc_mapjump) return true;
284 }
285 return false;
286 }
287
AnyMappingAnalyses() const288 bool UIVarsTraitModels::AnyMappingAnalyses() const
289 {
290 for (std::map<UIRegId, UIVarsSingleTraitModel>::const_iterator model = m_individualModels.begin(); model != m_individualModels.end(); model++)
291 {
292 if (model->second.GetAnalysisType() == mloc_mapjump) return true;
293 if (model->second.GetAnalysisType() == mloc_mapfloat) return true;
294 }
295 return false;
296 }
297
SetRange(UIRegId regID,rangeset rset)298 void UIVarsTraitModels::SetRange(UIRegId regID, rangeset rset)
299 {
300 UIVarsSingleTraitModel& model = m_individualModels.find(regID)->second;
301
302 rangepair fullrange = model.GetFullRange();
303 if (rset.size() == 0)
304 {
305 throw data_error("You must leave at least one allowable site for this trait. The sites must be chosen from the range " + ToString(fullrange) + ".");
306 }
307
308 rangepair below = make_pair(rset.begin()->first-1, fullrange.first);
309 rangepair above = make_pair(fullrange.second, rset.rbegin()->second);
310 rangeset truerange = rset;
311
312 if (below.first < below.second)
313 {
314 truerange = RemovePairFromRange(below, truerange);
315 }
316 if (above.first < above.second)
317 {
318 truerange = RemovePairFromRange(above, truerange);
319 }
320
321 if (truerange.size() == 0)
322 {
323 throw data_error("You must leave at least one allowable site for this trait. The sites must be chosen from the range "
324 + ToString(fullrange)
325 + ".");
326 }
327 if (truerange != rset)
328 {
329 GetConstUIVars().GetUI()->AddWarning("One or more of the added sites for this trait are outside of the range of the segments in this region. Truncating the added range.");
330 }
331
332 switch (model.GetAnalysisType())
333 {
334 case mloc_data:
335 case mloc_partition:
336 if (!OneSite(truerange))
337 {
338 model.SetAnalysisType(mloc_mapfloat);
339 GetConstUIVars().GetUI()->AddWarning("If you don't know where your trait is located, you may perform a mapping analysis,"
340 " but you may not use the trait as data or use it to partition your data. "
341 "Changing the analysis type to map the trait after collecting trees ('float').");
342 }
343 break;
344 case mloc_mapjump:
345 case mloc_mapfloat:
346 if (OneSite(truerange))
347 {
348 //LS DEBUG MAPPING: change after implementation
349 #ifdef NDEBUG
350 GetConstUIVars().GetUI()->AddWarning("You currently have only a single site where your trait is allowed. "
351 "The mapping analysis will not have anything to compare it to. "
352 "Use the 'A' option to add more sites.");
353 #else
354 GetConstUIVars().GetUI()->AddWarning("You currently have only a single site where your trait is allowed. "
355 "The mapping analysis will not have anything to compare it to. "
356 "Use the 'A' option to add more sites, or the 'U' or 'P' options to change the type of analysis.");
357 #endif
358 }
359 }
360 model.SetRange(truerange);
361 }
362
363 //Private functions
364
OneSite(rangeset rset)365 bool UIVarsTraitModels::OneSite(rangeset rset)
366 {
367 assert(rset.size() > 0);
368 if (rset.size() > 1) return false;
369 if (rset.begin()->first+1 == rset.begin()->second) return true;
370 return false;
371 }
372
373 //____________________________________________________________________________________
374