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