1 // $Id: gc_locus.cpp,v 1.35 2011/03/08 19:22:00 bobgian Exp $
2
3 /*
4 Copyright 2002 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 #include <cassert>
12
13 #include "gc_creation_info.h"
14 #include "gc_errhandling.h"
15 #include "gc_data.h" // for ToWxString
16 #include "gc_default.h"
17 #include "gc_locus.h"
18 #include "gc_locus_err.h"
19 #include "gc_strings.h"
20 #include "gc_strings_locus.h"
21 #include "gc_structures_err.h"
22 #include "wx/log.h"
23 #include "wx/string.h"
24 #include "wx/tokenzr.h"
25
26 //------------------------------------------------------------------------------------
27
gcLocus()28 gcLocus::gcLocus()
29 :
30 m_blessed(false),
31 m_hasRegion(false),
32 m_regionId(gcdefault::badIndex),
33 m_inducedByFile(false),
34 m_fileId(gcdefault::badIndex),
35 m_dataType(sdatatype_NONE_SET),
36 m_hasNumMarkers(false),
37 m_numMarkers(0),
38 m_hasTotalLength(false),
39 m_totalLength(0),
40 m_hasLinkedUserValue(false),
41 m_linkedUserValue(false),
42 m_hasOffset(false),
43 m_offset(1),
44 m_hasMapPosition(false),
45 m_mapPosition(1),
46 m_hasUnphasedMarkers(false)
47 {
48 assert(m_unphasedMarkers.NumMarkers() == 0);
49 m_locations.clear(); // shouldn't be necessary
50 }
51
~gcLocus()52 gcLocus::~gcLocus()
53 {
54 }
55
56 bool
GetBlessed() const57 gcLocus::GetBlessed() const
58 {
59 return m_blessed;
60 }
61
62 void
DebugDump(wxString prefix) const63 gcLocus::DebugDump(wxString prefix) const
64 {
65 wxLogDebug("%slocus %s (locus id %ld)", // EWDUMPOK
66 prefix.c_str(),
67 GetName().c_str(),
68 (long)GetId());
69 wxLogDebug("%sdatatype %s",(prefix+gcstr::indent).c_str(),ToWxString(GetDataType()).c_str()); // EWDUMPOK
70 wxLogDebug("%s%s markers",(prefix+gcstr::indent).c_str(),GetNumMarkersString().c_str()); // EWDUMPOK
71 wxLogDebug("%s%s total length",(prefix+gcstr::indent).c_str(),GetLengthString().c_str()); // EWDUMPOK
72 wxLogDebug("%s%s offset",(prefix+gcstr::indent).c_str(),GetOffsetString().c_str()); // EWDUMPOK
73 wxLogDebug("%s%s map position",(prefix+gcstr::indent).c_str(),GetMapPositionString().c_str()); // EWDUMPOK
74 wxLogDebug("%slocations:%s",(prefix+gcstr::indent).c_str(),GetLocationsAsString().c_str()); // EWDUMPOK
75 if(GetLinked())
76 {
77 wxLogDebug("%slinked",(prefix+gcstr::indent).c_str()); // EWDUMPOK
78 }
79 else
80 {
81 wxLogDebug("%sunlinked",(prefix+gcstr::indent).c_str()); // EWDUMPOK
82 }
83 }
84
85 bool
HasLocations() const86 gcLocus::HasLocations() const
87 {
88 return !(m_locations.empty());
89 }
90
91 std::vector<long>
GetLocations() const92 gcLocus::GetLocations() const
93 {
94 return m_locations;
95 }
96
97 wxString
GetLocationsAsString() const98 gcLocus::GetLocationsAsString() const
99 {
100 wxString locationString = " ";
101 for(size_t index=0; index < m_locations.size(); index++)
102 {
103 locationString += wxString::Format("%ld ",m_locations[index]);
104 }
105 return locationString;
106 }
107
108 bool
HasLocationZero() const109 gcLocus::HasLocationZero() const
110 {
111 for(size_t i = 0; i < m_locations.size(); i++)
112 {
113 long loc = m_locations[i];
114 if(loc == 0) return true;
115 }
116 return false;
117 }
118
119 wxString
GetDataTypeString() const120 gcLocus::GetDataTypeString() const
121 {
122 return ToWxString(m_dataType);
123 }
124
125 gcSpecificDataType
GetDataType() const126 gcLocus::GetDataType() const
127 {
128 return m_dataType;
129 }
130
131 void
SetDataType(gcSpecificDataType type)132 gcLocus::SetDataType(gcSpecificDataType type)
133 {
134 m_dataType = type;
135 }
136
137 bool
HasLength() const138 gcLocus::HasLength() const
139 {
140 if(HasTotalLength())
141 {
142 return true;
143 }
144 if(GetDataType() == sdatatype_DNA)
145 {
146 return HasNumMarkers();
147 }
148 return false;
149 }
150
151 size_t
GetLength() const152 gcLocus::GetLength() const
153 {
154 if(HasTotalLength())
155 {
156 return GetTotalLength();
157 }
158 if(HasNumMarkers())
159 {
160 if(GetDataType() == sdatatype_DNA)
161 {
162 return GetNumMarkers();
163 }
164 if(GetNumMarkers() == 1)
165 {
166 return 1;
167 }
168 else
169 {
170 throw gc_locus_without_length(GetName());
171 }
172 }
173 return gcdefault::badLength;
174 }
175
176 wxString
GetLengthString() const177 gcLocus::GetLengthString() const
178 {
179 if(HasLength())
180 {
181 return wxString::Format("%d",(int)GetLength());
182 }
183 return gcstr::unknown;
184 }
185
186 bool
HasTotalLength() const187 gcLocus::HasTotalLength() const
188 {
189 return m_hasTotalLength;
190 }
191
192 size_t
GetTotalLength() const193 gcLocus::GetTotalLength() const
194 {
195 assert(HasTotalLength());
196 return m_totalLength;
197 }
198
199 wxString
GetTotalLengthString() const200 gcLocus::GetTotalLengthString() const
201 {
202 if(HasTotalLength())
203 {
204 return wxString::Format("%d",(int)GetTotalLength());
205 }
206 return gcstr::unknown;
207 }
208
209 void
SetTotalLength(size_t totalLength)210 gcLocus::SetTotalLength(size_t totalLength)
211 {
212 if(HasNumMarkers())
213 {
214 if(totalLength < GetNumMarkers())
215 {
216 throw gc_locus_err(wxString::Format(gcerr::lengthTooShort,(int)totalLength,(int)GetNumMarkers()).c_str());
217 }
218 }
219 m_hasTotalLength = true;
220 m_totalLength = totalLength;
221 }
222
223 void
UnsetTotalLength()224 gcLocus::UnsetTotalLength()
225 {
226 m_hasTotalLength = false;
227 }
228
229 bool
HasNumMarkers() const230 gcLocus::HasNumMarkers() const
231 {
232 return m_hasNumMarkers;
233 }
234
235 size_t
GetNumMarkers() const236 gcLocus::GetNumMarkers() const
237 {
238 if(!HasNumMarkers())
239 {
240 wxString msg = wxString::Format(gcerr_locus::unsetNumMarkers,GetName().c_str());
241 throw gc_implementation_error(msg.c_str());
242 }
243 return m_numMarkers;
244 }
245
246 wxString
GetNumMarkersString() const247 gcLocus::GetNumMarkersString() const
248 {
249 if(HasNumMarkers())
250 {
251 return wxString::Format("%d",(int)GetNumMarkers());
252 }
253 return gcstr::unknown;
254 }
255
256 void
SetNumMarkers(size_t numMarkers)257 gcLocus::SetNumMarkers(size_t numMarkers)
258 {
259 if(numMarkers == 0)
260 {
261 throw gc_num_markers_zero();
262 }
263 m_hasNumMarkers = true;
264 m_numMarkers = numMarkers;
265 }
266
267 bool
HasOffset() const268 gcLocus::HasOffset() const
269 {
270 return m_hasOffset;
271 }
272
273 long
GetOffset() const274 gcLocus::GetOffset() const
275 {
276 if(!HasOffset())
277 {
278 wxString msg = wxString::Format(gcerr_locus::unsetOffset,GetName().c_str());
279 throw gc_implementation_error(msg.c_str());
280 }
281 return m_offset;
282 }
283
284 wxString
GetOffsetString() const285 gcLocus::GetOffsetString() const
286 {
287 if(HasOffset())
288 {
289 return wxString::Format("%d",(int)GetOffset());
290 }
291 return gcstr::unknown;
292 }
293
294 void
UnsetNumMarkers()295 gcLocus::UnsetNumMarkers()
296 {
297 m_hasNumMarkers = false;
298 }
299
300 bool
HasRegion() const301 gcLocus::HasRegion() const
302 {
303 return m_hasRegion;
304 }
305
306 size_t
GetRegionId() const307 gcLocus::GetRegionId() const
308 {
309 if(!HasRegion())
310 {
311 wxString msg = wxString::Format(gcerr::unsetRegionId,GetName().c_str());
312 throw gc_implementation_error(msg.c_str());
313 }
314 return m_regionId;
315 }
316
317 void
SetFileId(size_t id)318 gcLocus::SetFileId(size_t id)
319 {
320 m_inducedByFile = true;
321 m_fileId = id;
322 }
323
324 void
UnsetFileId()325 gcLocus::UnsetFileId()
326 {
327 m_inducedByFile = false;
328 }
329
330 void
SetRegionId(size_t id)331 gcLocus::SetRegionId(size_t id)
332 {
333 m_hasRegion = true;
334 m_regionId = id;
335 }
336
337 void
UnsetRegionId()338 gcLocus::UnsetRegionId()
339 {
340 m_hasRegion = false;
341 }
342
343 bool
HasLinkedUserValue() const344 gcLocus::HasLinkedUserValue() const
345 {
346 return m_hasLinkedUserValue;
347 }
348
349 bool
GetLinkedUserValue() const350 gcLocus::GetLinkedUserValue() const
351 {
352 if(!HasLinkedUserValue())
353 {
354 wxString msg = wxString::Format(gcerr_locus::unsetLinkedUserValue,GetName().c_str());
355 throw gc_implementation_error(msg.c_str());
356 }
357 return m_linkedUserValue;
358 }
359
360 bool
GetLinked() const361 gcLocus::GetLinked() const
362 {
363 if(HasLinkedUserValue())
364 {
365 return GetLinkedUserValue();
366 }
367 if(HasTotalLength())
368 {
369 return true;
370 }
371 if(HasLocations())
372 {
373 return true;
374 }
375 switch(GetDataType())
376 {
377 case sdatatype_NONE_SET:
378 // EWFIX.P4 -- should be able to determine values
379 // by reading data structures
380 return true;
381 break;
382 case sdatatype_DNA:
383 case sdatatype_SNP:
384 return true;
385 break;
386 case sdatatype_KALLELE:
387 case sdatatype_MICROSAT:
388 return false;
389 break;
390 }
391 assert(false);
392 return true;
393 }
394
395 wxString
GetLinkedString() const396 gcLocus::GetLinkedString() const
397 {
398 bool val = GetLinked();
399 if(val) return gcstr::linkageYes;
400 return gcstr::linkageNo;
401 }
402
403 wxString
GetLinkedUserValueString() const404 gcLocus::GetLinkedUserValueString() const
405 {
406 if(HasLinkedUserValue())
407 {
408 bool val = GetLinkedUserValue();
409 if(val) return gcstr::linkageYes;
410 return gcstr::linkageNo;
411 }
412 else
413 {
414 return gcstr::unknown;
415 }
416 }
417
418 void
SetLinkedUserValue(bool linked)419 gcLocus::SetLinkedUserValue(bool linked)
420 {
421 if(! linked)
422 {
423 if(GetDataType() == sdatatype_DNA || GetDataType() == sdatatype_SNP)
424 {
425 throw gc_unlinked_nuc();
426 }
427 }
428 m_hasLinkedUserValue = true;
429 m_linkedUserValue = linked;
430 }
431
432 bool
HasMapPosition() const433 gcLocus::HasMapPosition() const
434 {
435 return m_hasMapPosition;
436 }
437
438 long
GetMapPosition() const439 gcLocus::GetMapPosition() const
440 {
441 if(!HasMapPosition())
442 {
443 wxString msg = wxString::Format(gcerr::unsetMapPosition,GetName().c_str());
444 throw gc_implementation_error(msg.c_str());
445 }
446 return m_mapPosition;
447 }
448
449 wxString
GetMapPositionString() const450 gcLocus::GetMapPositionString() const
451 {
452 if(HasMapPosition())
453 {
454 return wxString::Format("%d",(int)GetMapPosition());
455 }
456 return gcstr::unknown;
457 }
458
459 void
SetMapPosition(long mapPosition)460 gcLocus::SetMapPosition(long mapPosition)
461 {
462 // we don't test the value since during use of the
463 // GUI, the user needs to pass through impossible
464 // states
465 m_hasMapPosition = true;
466 m_mapPosition = mapPosition;
467 }
468
469 void
UnsetMapPosition()470 gcLocus::UnsetMapPosition()
471 {
472 m_hasMapPosition = false;
473 }
474
475 bool
HasUnphasedMarkers() const476 gcLocus::HasUnphasedMarkers() const
477 {
478 return m_hasUnphasedMarkers;
479 }
480
481 const gcUnphasedMarkers *
GetUnphasedMarkers() const482 gcLocus::GetUnphasedMarkers() const
483 {
484 assert(HasUnphasedMarkers());
485 return &m_unphasedMarkers;
486 }
487
488 wxString
GetUnphasedMarkersAsString() const489 gcLocus::GetUnphasedMarkersAsString() const
490 {
491 assert(HasUnphasedMarkers());
492 return m_unphasedMarkers.AsString();
493 }
494
495 void
SetUnphasedMarkers(gcUnphasedMarkers markers)496 gcLocus::SetUnphasedMarkers(gcUnphasedMarkers markers)
497 {
498 m_hasUnphasedMarkers = true;
499 m_unphasedMarkers = markers;
500 }
501
502 void
SetBlessed(bool blessed)503 gcLocus::SetBlessed(bool blessed)
504 {
505 m_blessed = blessed;
506 }
507
508 void
SetCreationInfo(const gcCreationInfo & creationInfo)509 gcLocus::SetCreationInfo(const gcCreationInfo & creationInfo)
510 {
511 m_creationInfo = creationInfo;
512 }
513
514 void
SetOffset(long offset)515 gcLocus::SetOffset(long offset)
516 {
517 // we don't test the value since during use of the
518 // GUI, the user needs to pass through impossible
519 // states
520 m_offset = offset;
521 m_hasOffset = true;
522 }
523
524 void
SetLocations(wxString locationString)525 gcLocus::SetLocations(wxString locationString)
526 {
527 wxStringTokenizer tokenizer(locationString);
528 m_locations.clear();
529 while(tokenizer.HasMoreTokens())
530 {
531 wxString token = tokenizer.GetNextToken();
532 long location;
533 if(!token.ToLong(&location))
534 {
535 wxString msg = wxString::Format(gcerr::notALocation,locationString.c_str());
536 throw gc_data_error(msg.c_str());
537 }
538 if(!m_locations.empty())
539 // cannot check the first one!
540 {
541 long previous = m_locations.back();
542 if(location <= previous)
543 {
544 throw gc_locations_out_of_order(GetName(),previous,location);
545 }
546 }
547 m_locations.push_back(location);
548 }
549 if(HasNumMarkers())
550 {
551 if(m_locations.size() != GetNumMarkers())
552 {
553 throw gc_set_locations_err(GetName(),locationString,GetNumMarkers(),m_locations.size());
554 }
555 }
556 else
557 {
558 SetNumMarkers(m_locations.size());
559 }
560 }
561
562 void
LocusMergeLogic(bool doSettings,gcLocus & locusRef)563 gcLocus::LocusMergeLogic(bool doSettings, gcLocus & locusRef)
564 {
565 // data type
566 if(GetDataType() != sdatatype_NONE_SET)
567 {
568 if(locusRef.GetDataType() != sdatatype_NONE_SET)
569 {
570 if(locusRef.GetDataType() != GetDataType())
571 {
572 throw gc_locus_user_data_type_mismatch(GetName(),locusRef.GetName(),GetDataType(),locusRef.GetDataType());
573 }
574 }
575 }
576
577 // num Markers
578 if(HasNumMarkers())
579 {
580 if(locusRef.HasNumMarkers())
581 {
582 if(locusRef.GetNumMarkers() != GetNumMarkers())
583 {
584 throw gc_locus_site_count_mismatch(GetName(),locusRef.GetName(),GetNumMarkers(),locusRef.GetNumMarkers());
585 }
586 }
587 }
588
589 // EWFIX.P3 -- this is probably not correct
590 // total length
591 if(HasTotalLength())
592 {
593 if(locusRef.HasTotalLength())
594 {
595 if(locusRef.GetLength() != GetLength())
596 {
597 throw gc_locus_length_mismatch(GetName(),locusRef.GetName(),GetLength(),locusRef.GetLength());
598 }
599 }
600 }
601
602 // user-set linked value
603 if(HasLinkedUserValue())
604 {
605 if(locusRef.HasLinkedUserValue())
606 {
607 if(locusRef.GetLinkedUserValue() != GetLinkedUserValue())
608 {
609 throw gc_locus_user_linked_mismatch(GetName(),locusRef.GetName(),GetLinkedUserValue(),locusRef.GetLinkedUserValue());
610 }
611 }
612 }
613
614 // offset
615 if(HasOffset())
616 {
617 if(locusRef.HasOffset())
618 {
619 if(locusRef.GetOffset() != GetOffset())
620 {
621 throw gc_locus_offset_mismatch(GetName(),locusRef.GetName(),GetOffset(),locusRef.GetOffset());
622 }
623 }
624 }
625
626 // map position
627 if(HasMapPosition())
628 {
629 if(locusRef.HasMapPosition())
630 {
631 if(locusRef.GetMapPosition() != GetMapPosition())
632 {
633 throw gc_locus_map_position_mismatch(GetName(),locusRef.GetName(),GetMapPosition(),locusRef.GetMapPosition());
634 }
635 }
636 }
637
638 if(doSettings)
639 // this is a real merge
640 {
641 // order is important -- setting data type and then num Markers can
642 // result in setting the length
643 if(GetDataType() == sdatatype_NONE_SET) SetDataType(locusRef.GetDataType());
644 if(!HasNumMarkers() && locusRef.HasNumMarkers()) SetNumMarkers(locusRef.GetNumMarkers());
645 if(!HasTotalLength() && locusRef.HasTotalLength()) SetTotalLength(locusRef.GetTotalLength());
646 if(!HasLinkedUserValue() && locusRef.HasLinkedUserValue()) SetLinkedUserValue(locusRef.GetLinkedUserValue());
647 if(!HasOffset() && locusRef.HasOffset()) SetOffset(locusRef.GetOffset());
648 if(!HasMapPosition() && locusRef.HasMapPosition()) SetMapPosition(locusRef.GetMapPosition());
649 }
650 }
651
652 bool
CanMergeWith(gcLocus & locus)653 gcLocus::CanMergeWith(gcLocus & locus)
654 {
655 try
656 {
657 LocusMergeLogic(false,locus);
658 }
659 catch (const gc_locus_err& e)
660 {
661 return false;
662 }
663 return true;
664 }
665
666 void
MergeWith(gcLocus & locus)667 gcLocus::MergeWith(gcLocus & locus)
668 {
669 LocusMergeLogic(true,locus);
670 }
671
672 wxString
GetLongName() const673 gcLocus::GetLongName() const
674 {
675 return wxString::Format("%s %s",GetName().c_str(),m_creationInfo.GetDescriptiveName().c_str());
676 }
677
678 //____________________________________________________________________________________
679