refs/refs/FhirToCdm/CdmPersonBuilder.cs
1380 lines · cs
1using org.ohdsi.cdm.framework.common.Base; 2using org.ohdsi.cdm.framework.common.Builder; 3using org.ohdsi.cdm.framework.common.Enums; 4using org.ohdsi.cdm.framework.common.Extensions; 5using org.ohdsi.cdm.framework.common.Helpers; 6using org.ohdsi.cdm.framework.common.Lookups; 7using org.ohdsi.cdm.framework.common.Omop; 9using System.Collections.Concurrent; 10using System.Collections.Generic; 12using System.Threading.Tasks; 16 public class CdmPersonBuilder : IPersonBuilder 20 private readonly Dictionary<long, VisitOccurrence> _rawVisits = new Dictionary<long, VisitOccurrence>(); 21 private readonly Dictionary<long, List<VisitDetail>> _visitDetails = new Dictionary<long, List<VisitDetail>>(); 23 protected ChunkData ChunkData; 24 protected KeyMasterOffsetManager Offset; 25 protected IVocabulary Vocabulary; 26 public List<EraEntity> ObservationPeriodsRaw = new List<EraEntity>(); 27 protected List<Person> PersonRecords = new List<Person>(); 28 protected List<Death> DeathRecords = new List<Death>(); 29 protected List<Cohort> CohortRecords = new List<Cohort>(); 31 protected List<PayerPlanPeriod> 32 PayerPlanPeriodsRaw = new List<PayerPlanPeriod>(); 34 protected List<ConditionOccurrence> ConditionOccurrencesRaw = 35 new List<ConditionOccurrence>(); 37 protected List<DrugExposure> DrugExposuresRaw = new List<DrugExposure>(); 39 protected List<ProcedureOccurrence> ProcedureOccurrencesRaw = 40 new List<ProcedureOccurrence>(); 42 protected List<Observation> ObservationsRaw = new List<Observation>(); 43 protected List<Measurement> MeasurementsRaw = new List<Measurement>(); 45 protected List<VisitOccurrence> 46 VisitOccurrencesRaw = new List<VisitOccurrence>(); 48 protected List<VisitDetail> 49 VisitDetailsRaw = new List<VisitDetail>(); 51 protected List<VisitCost> VisitCostsRaw = new List<VisitCost>(); 52 protected List<DeviceExposure> DeviceExposureRaw = new List<DeviceExposure>(); 53 protected List<DeviceCost> DeviceCostRaw = new List<DeviceCost>(); 55 protected List<DrugExposure> DrugForEra = new List<DrugExposure>(); 56 protected List<ConditionOccurrence> ConditionForEra = new List<ConditionOccurrence>(); 58 protected List<Note> NoteRecords = new List<Note>(); 65 public bool AddCost(long eventId, IEntity entity, Func<ICostV5, Cost> createCost) 68 var costDataExists = false; 69 if (entity == null) return false; 71 switch (entity.GeEntityType()) 73 case EntityType.DrugExposure: 75 var de = (DrugExposure)entity; 77 if (de.DrugCost != null) 79 costDataExists |= AddCost(eventId, createCost, de, de.DrugCost); 86 case EntityType.ProcedureOccurrence: 88 var p = (ProcedureOccurrence)entity; 89 if (p.ProcedureCosts != null && p.ProcedureCosts.Count > 0) 91 foreach (var pc in p.ProcedureCosts) 93 costDataExists |= AddCost(eventId, createCost, p, pc); 96 p.ProcedureCosts.Clear(); 97 p.ProcedureCosts = null; 103 case EntityType.Observation: 105 var o = (Observation)entity; 106 if (o.ObservationCost != null && o.ObservationCost.Count > 0) 108 foreach (var oc in o.ObservationCost) 110 costDataExists |= AddCost(eventId, createCost, o, oc); 112 o.ObservationCost.Clear(); 113 o.ObservationCost = null; 118 case EntityType.VisitOccurrence: 120 var vo = (VisitOccurrence)entity; 121 if (vo.VisitCosts != null && vo.VisitCosts.Count > 0) 123 foreach (var vc in vo.VisitCosts) 125 costDataExists |= AddCost(eventId, createCost, vo, vc); 127 vo.VisitCosts.Clear(); 128 vo.VisitCosts = null; 133 case EntityType.Measurement: 135 var m = (Measurement)entity; 136 if (m.MeasurementCost != null && m.MeasurementCost.Count > 0) 138 foreach (var mc in m.MeasurementCost) 140 costDataExists |= AddCost(eventId, createCost, m, mc); 142 m.MeasurementCost.Clear(); 143 m.MeasurementCost = null; 148 case EntityType.DeviceExposure: 150 var d = (DeviceExposure)entity; 151 if (d.DeviceCosts != null && d.DeviceCosts.Count > 0) 153 foreach (var dc in d.DeviceCosts) 155 costDataExists |= AddCost(eventId, createCost, d, dc); 158 d.DeviceCosts.Clear(); 159 d.DeviceCosts = null; 165 return costDataExists; 173 ObservationPeriodsRaw.Clear(); 174 ObservationPeriodsRaw = null; 176 PersonRecords.Clear(); 177 PersonRecords = null; 178 DeathRecords.Clear(); 180 CohortRecords.Clear(); 181 CohortRecords = null; 183 PayerPlanPeriodsRaw.Clear(); 184 PayerPlanPeriodsRaw = null; 186 ConditionOccurrencesRaw.Clear(); 187 ConditionOccurrencesRaw = null; 189 DrugExposuresRaw.Clear(); 190 DrugExposuresRaw = null; 192 ProcedureOccurrencesRaw.Clear(); 193 ProcedureOccurrencesRaw = null; 195 ObservationsRaw.Clear(); 196 ObservationsRaw = null; 198 MeasurementsRaw.Clear(); 199 MeasurementsRaw = null; 201 VisitOccurrencesRaw.Clear(); 202 VisitOccurrencesRaw = null; 204 VisitDetailsRaw.Clear(); 205 VisitDetailsRaw = null; 207 VisitCostsRaw.Clear(); 208 VisitCostsRaw = null; 210 DeviceExposureRaw.Clear(); 211 DeviceExposureRaw = null; 213 DeviceCostRaw.Clear(); 214 DeviceCostRaw = null; 219 ConditionForEra.Clear(); 220 ConditionForEra = null; 226 private bool AddCost(long eventId, Func<ICostV5, Cost> createCost, IEntity entity, ICostV5 entityCost) 228 if (entityCost == null) return false; 230 var cost = createCost(entityCost); 231 cost.CostId = Offset.GetKeyOffset(entityCost.PersonId).VisitCostId; 232 cost.EventId = eventId; 234 return ChunkData.AddCostData(cost); 236 public ChunkData Result => ChunkData; 238 public bool Complete { get; set; } 241 public void AddChildData(ProcedureOccurrence parent, ProcedureCost pc) 243 parent.ProcedureCosts = new List<ProcedureCost> { pc }; 246 public void AddChildData(DrugExposure parent, DrugCost child) 248 parent.DrugCost = child; 251 public void AddChildData(DeviceExposure parent, DeviceCost child) 253 parent.DeviceCosts = new List<DeviceCost> { child }; 256 public void AddChildData(Measurement parent, MeasurementCost child) 258 parent.MeasurementCost = new List<MeasurementCost> { child }; 261 public void AddChildData(Observation parent, ObservationCost child) 263 parent.ObservationCost = new List<ObservationCost> { child }; 266 public void AddChildData(VisitOccurrence parent, VisitCost child) 268 parent.VisitCosts = new List<VisitCost> { child }; 271 public void AddNote(Note data) 273 NoteRecords.Add(data); 277 /// Add raw entities to builder for further build 279 /// <param name="data">raw entity</param> 280 public void AddData(IEntity data) 282 switch (data.GeEntityType()) 284 case EntityType.Person: 286 AddEntity((Person)data, PersonRecords); 290 case EntityType.Death: 292 AddEntity((Death)data, DeathRecords); 296 case EntityType.PayerPlanPeriod: 298 AddEntity((PayerPlanPeriod)data, PayerPlanPeriodsRaw); 302 case EntityType.ConditionOccurrence: 304 AddEntity((ConditionOccurrence)data, ConditionOccurrencesRaw); 308 case EntityType.DrugExposure: 310 AddEntity((DrugExposure)data, DrugExposuresRaw); 314 case EntityType.ProcedureOccurrence: 316 AddEntity((ProcedureOccurrence)data, ProcedureOccurrencesRaw); 320 case EntityType.Observation: 322 AddEntity((Observation)data, ObservationsRaw); 326 case EntityType.VisitOccurrence: 328 AddEntity((VisitOccurrence)data, VisitOccurrencesRaw); 332 case EntityType.VisitDetail: 334 AddEntity((VisitDetail)data, VisitDetailsRaw); 338 case EntityType.Cohort: 340 AddEntity((Cohort)data, CohortRecords); 344 case EntityType.Measurement: 346 AddEntity((Measurement)data, MeasurementsRaw); 350 case EntityType.DeviceExposure: 352 AddEntity((DeviceExposure)data, DeviceExposureRaw); 356 case EntityType.Note: 358 //AddEntity((Note)data, NoteRecords); TMP: NOTE 364 protected static void AddEntity<T>(T entity, List<T> list) where T : IEntity 369 protected static bool AddEntity<T>(T entity, ConcurrentDictionary<T, T> dictionary) where T : IEntity 371 return dictionary.TryAdd(entity, entity); 374 // set corresponding ProviderIds 375 protected void SetProviderIds<T>(IEnumerable<T> inputRecords) where T : class, IEntity 377 var records = inputRecords as T[] ?? inputRecords.ToArray(); 378 if (inputRecords == null || !records.Any()) return; 381 foreach (var e in records.Where(e => !string.IsNullOrEmpty(e.ProviderKey))) 383 e.ProviderId = Entity.GetId(e.ProviderKey); 387 // set corresponding PlanPeriodIds to drug exposure entities and procedure occurrence entities 388 protected virtual void SetPayerPlanPeriodId(PayerPlanPeriod[] payerPlanPeriods, DrugExposure[] drugExposures, 389 ProcedureOccurrence[] procedureOccurrences, VisitOccurrence[] visitOccurrences, 390 DeviceExposure[] deviceExposure) 392 if (!payerPlanPeriods.Any()) return; 394 foreach (var de in drugExposures) 396 if (de.DrugCost == null) continue; 397 foreach (var planPeriod in payerPlanPeriods) 399 if (de.StartDate.Between(planPeriod.StartDate, planPeriod.EndDate.Value)) 401 de.DrugCost.PayerPlanPeriodId = planPeriod.Id; 407 foreach (var po in procedureOccurrences) 409 if (po.ProcedureCosts == null) continue; 410 foreach (var planPeriod in payerPlanPeriods) 412 if (po.StartDate.Between(planPeriod.StartDate, planPeriod.EndDate.Value)) 414 foreach (var procedureCost in po.ProcedureCosts) 416 procedureCost.PayerPlanPeriodId = planPeriod.Id; 424 foreach (var vo in visitOccurrences) 426 if (vo.VisitCosts == null) continue; 427 foreach (var planPeriod in payerPlanPeriods) 429 if (vo.StartDate.Between(planPeriod.StartDate, planPeriod.EndDate.Value)) 431 foreach (var visitCost in vo.VisitCosts) 433 visitCost.PayerPlanPeriodId = planPeriod.Id; 441 foreach (var de in deviceExposure) 443 if (de.DeviceCosts == null) continue; 444 foreach (var planPeriod in payerPlanPeriods) 446 if (de.StartDate.Between(planPeriod.StartDate, planPeriod.EndDate.Value)) 448 foreach (var deviceCost in de.DeviceCosts) 450 deviceCost.PayerPlanPeriodId = planPeriod.Id; 460 /// Projects Enumeration of observation period from the raw set of observation period entities. 462 /// <param name="gap">persistence window (duration that is allowed to elapse between two periods) </param> 463 /// <param name="observationPeriods">raw set of observation period entities</param> 464 /// <returns>Enumeration of observation period entities</returns> 465 public virtual IEnumerable<ObservationPeriod> BuildObservationPeriods(int gap, EraEntity[] observationPeriods) 467 if (observationPeriods.Length > 0) 469 yield return new ObservationPeriod 471 Id = observationPeriods[0].Id, 472 PersonId = observationPeriods[0].PersonId, 473 StartDate = observationPeriods[0].StartDate, 474 EndDate = observationPeriods[0].EndDate.Value, 475 TypeConceptId = observationPeriods[0].TypeConceptId 481 /// Projects Enumeration of payerPlanPeriod from the raw set of payerPlanPeriod entities. 483 /// <param name="payerPlanPeriods">raw set of payerPlanPeriod entities</param> 484 /// <param name="visitOccurrences">the visit occurrence entities for current person</param> 485 /// <returns>Enumeration of payerPlanPeriod entities</returns> 486 public virtual IEnumerable<PayerPlanPeriod> BuildPayerPlanPeriods(PayerPlanPeriod[] payerPlanPeriods, 487 Dictionary<long, VisitOccurrence> visitOccurrences) 489 // All overlapping periods will be collapsed into one observation period 490 return EraHelper.GetPayerPlanPeriods(payerPlanPeriods, CanPayerPlanPeriodBeCombined, 495 /// Condition for the combining two periods 497 /// <param name="current">1st period</param> 498 /// <param name="other">2nd period</param> 499 /// <returns>Can those periods be combined</returns> 500 public virtual bool CanPayerPlanPeriodBeCombined(PayerPlanPeriod current, PayerPlanPeriod other) 502 if (string.IsNullOrEmpty(current.PlanSourceValue)) 503 return current.PayerSourceValue == other.PayerSourceValue; 505 return current.PlanSourceValue == other.PlanSourceValue && 506 current.PayerSourceValue == other.PayerSourceValue; 510 /// Projects death entity from the raw set of death entities. 512 /// override the death's start date using the end date of the corresponding visit. 514 /// <param name="death">raw set of death entities</param> 515 /// <param name="visitOccurrences">the visit occurrence entities for current person</param> 516 /// <param name="observationPeriods">the observation period entities for current person</param> 517 /// <returns>death entity</returns> 518 public virtual Death BuildDeath(Death[] death, Dictionary<long, VisitOccurrence> visitOccurrences, 519 ObservationPeriod[] observationPeriods) 521 var ds = Clean(death, observationPeriods, false).ToList(); 524 var pd = ds.Where(d => d.Primary).ToList(); 525 return pd.Any() ? pd.OrderBy(d => d.StartDate).Last() : ds.OrderBy(d => d.StartDate).Last(); 532 /// Projects person etity from the raw set of persons entities. 534 /// <param name="records">raw set of Person entities</param> 535 /// <returns>Person entity</returns> 536 public virtual KeyValuePair<Person, Attrition> BuildPerson(List<Person> records) 538 if (records == null || records.Count == 0) 539 return new KeyValuePair<Person, Attrition>(null, Attrition.UnacceptablePatientQuality); 541 var ordered = records.OrderByDescending(p => p.StartDate).ToArray(); 542 var person = ordered.Take(1).First(); 543 person.StartDate = ordered.Take(1).Last().StartDate; 546 records.GroupBy(p => p.GenderConceptId).OrderByDescending(gp => gp.Count()).Take(1).First().First(); 547 var race = records.GroupBy(p => p.RaceConceptId).OrderByDescending(gp => gp.Count()).Take(1).First() 550 person.GenderConceptId = gender.GenderConceptId; 551 person.GenderSourceValue = gender.GenderSourceValue; 552 person.RaceConceptId = race.RaceConceptId; 553 person.RaceSourceValue = race.RaceSourceValue; 555 if (person.GenderConceptId == 8551) //UNKNOWN 557 return new KeyValuePair<Person, Attrition>(null, Attrition.UnknownGender); 560 return new KeyValuePair<Person, Attrition>(person, Attrition.None); 563 private void AddRawVisitOccurrence(VisitOccurrence rawVisit, VisitOccurrence finalVisit) 565 if (!_rawVisits.ContainsKey(rawVisit.Id)) 566 _rawVisits.Add(rawVisit.Id, finalVisit); 568 _rawVisits[rawVisit.Id] = finalVisit; 572 public IEnumerable<VisitOccurrence> BuildVisitOccurrences(VisitOccurrence[] rawVisitOccurrences, 573 ObservationPeriod[] observationPeriods) 575 var ipVisits = CollapseVisits(rawVisitOccurrences.Where(vo => vo.ConceptId == 9201), 1).ToList(); 577 var erVisits = new List<VisitOccurrence>(); 578 var opVisits = new List<VisitOccurrence>(); 580 var visitOccurrence in 581 rawVisitOccurrences.Where( 582 visitOccurrence => visitOccurrence.ConceptId != 9201)) 584 var ip = ipVisits.FirstOrDefault(v => visitOccurrence.StartDate.Between(v.StartDate, v.EndDate.Value)); 586 if (visitOccurrence.ConceptId == 9203) 588 if (ip == null || (visitOccurrence.StartDate == ip.StartDate && 589 visitOccurrence.EndDate == ip.StartDate)) 592 erVisits.Add(visitOccurrence); 596 AddRawVisitOccurrence(visitOccurrence, ip); 601 opVisits.Add(visitOccurrence); 605 AddRawVisitOccurrence(visitOccurrence, ip); 609 foreach (var ipVisit in ipVisits) 611 yield return ipVisit; 614 foreach (var erGroup in erVisits.GroupBy(v => v.StartDate)) 616 var visit = erGroup.First(); 617 visit.EndDate = erGroup.Max(v => v.EndDate); 618 foreach (var visitOccurrence in erGroup) 620 AddRawVisitOccurrence(visitOccurrence, visit); 626 foreach (var opGroup in opVisits.GroupBy(v => v.StartDate)) 628 foreach (var opGroup1 in opGroup.GroupBy(v => v.ProviderKey)) 630 var visit = opGroup1.First(); 631 visit.EndDate = opGroup1.Max(v => v.EndDate); 632 foreach (var visitOccurrence in opGroup1) 634 AddRawVisitOccurrence(visitOccurrence, visit); 642 private IEnumerable<VisitOccurrence> CollapseVisits(IEnumerable<VisitOccurrence> visitOccurrences, int gap) 644 var visits = new List<VisitOccurrence>(); 646 foreach (var claim in visitOccurrences.OrderBy(vo => vo.StartDate).ThenBy(vo => vo.EndDate)) 648 if (visits.Count > 0) 650 var previousClaim = visits.Last(); 651 if (claim.StartDate <= previousClaim.EndDate.Value.AddDays(gap)) 653 if (claim.EndDate >= previousClaim.EndDate) 655 previousClaim.EndDate = claim.EndDate; 658 AddRawVisitOccurrence(claim, previousClaim); 663 AddRawVisitOccurrence(claim, claim); 670 private VisitOccurrence GetVisitOccurrence(IEntity ent) 672 if (ent.VisitOccurrenceId.HasValue && _rawVisits.ContainsKey(ent.VisitOccurrenceId.Value)) 674 return _rawVisits[ent.VisitOccurrenceId.Value]; 680 public IEnumerable<VisitDetail> BuildVisitDetails(VisitDetail[] visitDetails, 681 VisitOccurrence[] visitOccurrences, ObservationPeriod[] observationPeriods) 683 foreach (var visitOccurrence in visitOccurrences) 686 new VisitDetail(visitOccurrence) 688 Id = visitOccurrence.Id, 689 VisitOccurrenceId = visitOccurrence.Id 692 if (!visitDetail.EndDate.HasValue) 693 visitDetail.EndDate = visitDetail.StartDate; 696 yield return visitDetail; 700 public IEnumerable<Note> BuildNote(Note[] notes, Dictionary<long, VisitOccurrence> visitOccurrences, 701 ObservationPeriod[] observationPeriods) 703 foreach (var e in notes.Where(item => 704 observationPeriods.FirstOrDefault(p => item.StartDate.Between(p.StartDate, p.EndDate.Value)) != 707 if (e.VisitOccurrenceId == null || visitOccurrences.ContainsKey(e.VisitOccurrenceId.Value)) 713 //return BuildEntities(notes, visitOccurrences, observationPeriods, true); TMP: NOTE 717 /// Projects Enumeration of drug exposure from the raw set of drug exposure entities. 719 /// <param name="drugExposures">raw set of drug exposures entities</param> 720 /// <param name="visitOccurrences">the visit occurrences entities for current person</param> 721 /// <param name="observationPeriods">the observation periods entities for current person</param> 722 /// <returns>Enumeration of drug exposure entities</returns> 723 public virtual IEnumerable<DrugExposure> BuildDrugExposures(DrugExposure[] drugExposures, 724 Dictionary<long, VisitOccurrence> visitOccurrences, ObservationPeriod[] observationPeriods) 726 return BuildEntities(drugExposures, visitOccurrences, observationPeriods, false); 730 /// Projects Enumeration of ConditionOccurrence from the raw set of ConditionOccurrence entities. 732 /// <param name="conditionOccurrences">raw set of condition occurrence entities</param> 733 /// <param name="visitOccurrences">the visit occurrence entities for current person</param> 734 /// <param name="observationPeriods">the observation period entities for current person</param> 735 /// <returns>Enumeration of condition occurrence entities</returns> 736 public virtual IEnumerable<ConditionOccurrence> BuildConditionOccurrences( 737 ConditionOccurrence[] conditionOccurrences, Dictionary<long, VisitOccurrence> visitOccurrences, 738 ObservationPeriod[] observationPeriods) 740 return BuildEntities(conditionOccurrences, visitOccurrences, observationPeriods, false); 744 /// Projects Enumeration of ProcedureOccurrence from the raw set of ProcedureOccurence entities. 746 /// <param name="procedureOccurrences">raw set of procedure occurrence entities</param> 747 /// <param name="visitOccurrences">the visit occurrence entities for current person</param> 748 /// <param name="observationPeriods">the observation period entities for current person</param> 749 /// <returns>Enumeration of procedure occurrence entities</returns> 750 public virtual IEnumerable<ProcedureOccurrence> BuildProcedureOccurrences( 751 ProcedureOccurrence[] procedureOccurrences, Dictionary<long, VisitOccurrence> visitOccurrences, 752 ObservationPeriod[] observationPeriods) 754 return BuildEntities(procedureOccurrences, visitOccurrences, observationPeriods, false); 758 /// Projects Enumeration of Observations from the raw set of Observation entities. 760 /// <param name="observations">raw set of observations entities</param> 761 /// <param name="visitOccurrences">the visit occurrences entities for current person</param> 762 /// <param name="observationPeriods">the observation periods entities for current person</param> 763 /// <returns>Enumeration of Observation from the raw set of Observation entities</returns> 764 public virtual IEnumerable<Observation> BuildObservations(Observation[] observations, 765 Dictionary<long, VisitOccurrence> visitOccurrences, ObservationPeriod[] observationPeriods) 767 return BuildEntities(observations, visitOccurrences, observationPeriods, false); 770 public virtual IEnumerable<Measurement> BuildMeasurement(Measurement[] measurements, 771 Dictionary<long, VisitOccurrence> visitOccurrences, 772 ObservationPeriod[] observationPeriods) 774 return BuildEntities(measurements, visitOccurrences, observationPeriods, false); 778 /// CONDITION_ERAs are chronological periods of condition occurrence. 779 /// There will only be one type of persistence window (duration that is allowed to elapse between condition occurrences) applied to this CDM, which is 30 days. 780 /// CONDITION_END_DATE will be the CONDITION_START_DATE. 782 /// <param name="conditionOccurrences">Set of condition occurrence entities</param> 783 /// <param name="observationPeriods">the observation periods entities for current person</param> 784 /// <returns>Enumeration of condition era</returns> 785 public virtual IEnumerable<EraEntity> BuildConditionEra(ConditionOccurrence[] conditionOccurrences, ObservationPeriod[] observationPeriods) 787 foreach (var eraEntity in EraHelper.GetEras( 788 Clean(conditionOccurrences, observationPeriods, false).Where(c => string.IsNullOrEmpty(c.Domain) || c.Domain == "Condition"), 30, 791 eraEntity.Id = Offset.GetKeyOffset(eraEntity.PersonId).ConditionEraId; 792 yield return eraEntity; 797 /// A Drug Era is defined as a span of time when the Person is assumed to be exposed to a particular drug. 798 /// Successive periods of Drug Exposures are combined under certain rules to produce continuous Drug Eras. 799 /// The Drug Era is populated by pulling from the set of drug exposure. A drug era is therefore understood as exposure to a certain compound over a certain period of time. 800 /// There will only be one type of persistence window (duration that is allowed to elapse between drug exposures) applied to this CDM, which is 30 days. 802 /// <param name="drugExposures">set of drug exposure entities</param> 803 /// <param name="observationPeriods">the observation periods entities for current person</param> 804 /// <returns>Enumeration of drug era</returns> 805 public virtual IEnumerable<EraEntity> BuildDrugEra(DrugExposure[] drugExposures, ObservationPeriod[] observationPeriods) 808 var eraEntity in EraHelper.GetEras( 809 Clean(drugExposures, observationPeriods, false).Where(d => string.IsNullOrEmpty(d.Domain) || d.Domain == "Drug"), 30, 38000182)) 811 eraEntity.Id = Offset.GetKeyOffset(eraEntity.PersonId).DrugEraId; 812 yield return eraEntity; 817 /// Projects Enumeration of Cohort from the raw set of Cohort entities. 819 /// <param name="cohort">raw set of Cohort entities</param> 820 /// <param name="observationPeriods">the observation periods entities for current person</param> 821 /// <returns>Enumeration of Cohort from the raw set of Cohort entities</returns> 822 public virtual IEnumerable<Cohort> BuildCohort(Cohort[] cohort, ObservationPeriod[] observationPeriods) 827 public IEnumerable<EraEntity> BuildPregnancyEpisodes(ConditionOccurrence[] conditionOccurrences, 828 ProcedureOccurrence[] procedureOccurrences, Observation[] observations, Measurement[] measurements, DrugExposure[] drugExposures) 834 public virtual IEnumerable<DeviceExposure> BuildDeviceExposure(DeviceExposure[] devExposure, 835 Dictionary<long, VisitOccurrence> visitOccurrences, 836 ObservationPeriod[] observationPeriods) 838 return BuildEntities(devExposure, visitOccurrences, observationPeriods, false); 842 /// Projects Enumeration of drug cost from the set of drug exposure entities. 844 /// <param name="drugExposures">set of drug exposure entities</param> 845 /// <returns>set of drug cost entities</returns> 846 public virtual IEnumerable<DrugCost> BuildDrugCosts(DrugExposure[] drugExposures) 848 foreach (var drugExposure in drugExposures.Where(drugExposure => drugExposure.DrugCost != null)) 850 drugExposure.DrugCost.Id = drugExposure.Id; 851 yield return drugExposure.DrugCost; 856 /// Projects Enumeration of procedure cost from the set of procedure occurrence entities. 858 /// <param name="procedureOccurrences">set of procedure occurrence entities</param> 859 /// <returns>set of procedure cost entities</returns> 860 public virtual IEnumerable<ProcedureCost> BuildProcedureCosts(ProcedureOccurrence[] procedureOccurrences) 862 foreach (var po in procedureOccurrences.Where(i => i.ProcedureCosts != null)) 864 foreach (var pc in po.ProcedureCosts) 872 public virtual IEnumerable<VisitCost> BuildVisitCosts(VisitOccurrence[] visitOccurrences) 874 foreach (var vo in visitOccurrences.Where(i => i.VisitCosts != null)) 876 foreach (var vc in vo.VisitCosts) 884 public virtual IEnumerable<DeviceCost> BuildDeviceCosts(DeviceExposure[] deviceExposure) 886 foreach (var de in deviceExposure.Where(i => i.DeviceCosts != null)) 888 foreach (var dc in de.DeviceCosts) 897 /// Filtering raw set of entities (DrugExposures, ConditionOccurrences, ProcedureOccurrences...) 899 /// <param name="entitiesToBuild">the raw set of entities</param> 900 /// <param name="visitOccurrences">the visit occurrence entities for current person</param> 901 /// <param name="observationPeriods">the observation period entities for current person</param> 902 /// <param name="withinTheObservationPeriod">allow records that are only inside of the observation period</param> 903 /// <returns>Enumeration of filtered entities</returns> 904 public virtual IEnumerable<T> BuildEntities<T>(IEnumerable<T> entitiesToBuild, 905 IDictionary<long, VisitOccurrence> visitOccurrences, IEnumerable<ObservationPeriod> observationPeriods, bool withinTheObservationPeriod) 908 var uniqueEntities = new HashSet<T>(); 909 foreach (var e in Clean(entitiesToBuild, observationPeriods, withinTheObservationPeriod)) 911 if (e.VisitOccurrenceId == null || visitOccurrences.ContainsKey(e.VisitOccurrenceId.Value)) 915 uniqueEntities.Add(e); 924 foreach (var ue in uniqueEntities) 931 /// Build person entity and all person related entities like: DrugExposures, ConditionOccurrences, ProcedureOccurrences... from raw data sets 933 public virtual Attrition Build(ChunkData data, KeyMasterOffsetManager o) 936 this.ChunkData = data; 938 var result = BuildPerson(PersonRecords.ToList()); 939 var person = result.Key; 946 var observationPeriods = 947 BuildObservationPeriods(person.ObservationPeriodGap, ObservationPeriodsRaw.ToArray()).ToArray(); 949 var payerPlanPeriods = BuildPayerPlanPeriods(PayerPlanPeriodsRaw.ToArray(), null).ToArray(); 951 var visitDetails = BuildVisitDetails(null, VisitOccurrencesRaw.ToArray(), observationPeriods).ToArray(); 953 var visitOccurrences = new Dictionary<long, VisitOccurrence>(); 954 var visitIds = new List<long>(); 955 foreach (var visitOccurrence in BuildVisitOccurrences(VisitOccurrencesRaw.ToArray(), observationPeriods)) 957 if (!visitOccurrences.ContainsKey(visitOccurrence.Id)) 959 visitOccurrences.Add(visitOccurrence.Id, visitOccurrence); 960 visitIds.Add(visitOccurrence.Id); 964 foreach (var visitDetail in visitDetails) 966 var vo = GetVisitOccurrence(visitDetail); 967 visitDetail.VisitOccurrenceId = vo?.Id ?? 0; 969 if (visitDetail.VisitOccurrenceId.HasValue && !_visitDetails.ContainsKey(visitDetail.VisitOccurrenceId.Value)) 971 _visitDetails.Add(visitDetail.VisitOccurrenceId.Value, new List<VisitDetail>()); 974 _visitDetails[visitDetail.VisitOccurrenceId.Value].Add(visitDetail); 977 long? prevVisitId = null; 978 foreach (var visitId in visitIds.OrderBy(v => v)) 980 if (prevVisitId.HasValue) 982 visitOccurrences[visitId].PrecedingVisitOccurrenceId = prevVisitId; 985 prevVisitId = visitId; 988 var drugExposures = new List<DrugExposure>(); 989 foreach (var item in BuildDrugExposures(DrugExposuresRaw.ToArray(), visitOccurrences, observationPeriods)) 991 item.Id = Offset.GetKeyOffset(item.PersonId).DrugExposureId; 992 drugExposures.Add(item); 995 var conditionOccurrences = new List<ConditionOccurrence>(); 996 foreach (var item in BuildConditionOccurrences(ConditionOccurrencesRaw.ToArray(), visitOccurrences, observationPeriods)) 998 item.Id = Offset.GetKeyOffset(item.PersonId).ConditionOccurrenceId; 999 conditionOccurrences.Add(item); 1002 var procedureOccurrences = new List<ProcedureOccurrence>(); 1003 foreach (var item in BuildProcedureOccurrences(ProcedureOccurrencesRaw.ToArray(), visitOccurrences, observationPeriods)) 1005 item.Id = Offset.GetKeyOffset(item.PersonId).ProcedureOccurrenceId; 1006 procedureOccurrences.Add(item); 1009 var observations = new List<Observation>(); 1010 foreach (var item in BuildObservations(ObservationsRaw.ToArray(), visitOccurrences, observationPeriods)) 1012 item.Id = Offset.GetKeyOffset(item.PersonId).ObservationId; 1013 observations.Add(item); 1016 var measurements = new List<Measurement>(); 1017 foreach (var item in BuildMeasurement(MeasurementsRaw.ToArray(), visitOccurrences, observationPeriods)) 1019 item.Id = Offset.GetKeyOffset(item.PersonId).MeasurementId; 1020 measurements.Add(item); 1023 var deviceExposure = 1024 BuildDeviceExposure(DeviceExposureRaw.ToArray(), visitOccurrences, observationPeriods).ToArray(); 1026 // set corresponding PlanPeriodIds to drug exposure entities and procedure occurrence entities 1027 SetPayerPlanPeriodId(payerPlanPeriods, drugExposures.ToArray(), procedureOccurrences.ToArray(), 1028 visitOccurrences.Values.ToArray(), 1031 // set corresponding ProviderIds 1032 SetProviderIds(drugExposures); 1033 SetProviderIds(conditionOccurrences); 1034 SetProviderIds(procedureOccurrences); 1035 SetProviderIds(observations); 1037 var death = BuildDeath(DeathRecords.ToArray(), visitOccurrences, observationPeriods); 1039 var cohort = BuildCohort(CohortRecords.ToArray(), observationPeriods).ToArray(); 1040 var notes = BuildNote(NoteRecords.ToArray(), visitOccurrences, observationPeriods).ToArray(); 1042 List<DateTime?> mins = new List<DateTime?>(); 1043 List<DateTime?> maxs = new List<DateTime?>(); 1045 mins.Add(GetMinDate(drugExposures)); 1046 mins.Add(GetMinDate(conditionOccurrences)); 1047 mins.Add(GetMinDate(procedureOccurrences)); 1048 mins.Add(GetMinDate(observations)); 1049 mins.Add(GetMinDate(deviceExposure)); 1050 mins.Add(GetMinDate(measurements)); 1051 mins.Add(GetMinDate(visitOccurrences.Values)); 1052 mins.Add(GetMinDate(visitDetails)); 1054 maxs.Add(GetMaxDate(drugExposures)); 1055 maxs.Add(GetMaxDate(conditionOccurrences)); 1056 maxs.Add(GetMaxDate(procedureOccurrences)); 1057 maxs.Add(GetMaxDate(observations)); 1058 maxs.Add(GetMaxDate(deviceExposure)); 1059 maxs.Add(GetMaxDate(measurements)); 1060 maxs.Add(GetMaxDate(visitOccurrences.Values)); 1061 maxs.Add(GetMaxDate(visitDetails)); 1063 var min = mins.Min(); 1064 var max = maxs.Max(); 1066 var observationPeriodsFinal = new List<ObservationPeriod>(1) 1068 new ObservationPeriod {PersonId = person.PersonId, TypeConceptId = 32817 } 1073 observationPeriodsFinal[0].StartDate = min.Value; 1076 observationPeriodsFinal[0].EndDate = max; 1078 observationPeriodsFinal[0].EndDate = min.Value; 1081 SetVisitOccurrenceId(drugExposures); 1082 SetVisitOccurrenceId(conditionOccurrences); 1083 SetVisitOccurrenceId(procedureOccurrences); 1084 SetVisitOccurrenceId(measurements); 1085 SetVisitOccurrenceId(observations); 1086 SetVisitOccurrenceId(deviceExposure); 1088 // push built entities to ChunkBuilder for further save to CDM database 1089 AddToChunk(person, death, observationPeriodsFinal.ToArray(), payerPlanPeriods, drugExposures.ToArray(), 1090 conditionOccurrences.ToArray(), procedureOccurrences.ToArray(), observations.ToArray(), measurements.ToArray(), 1091 visitOccurrences.Values.ToArray(), visitDetails, cohort, deviceExposure, notes); 1095 return Attrition.None; 1098 private void SetVisitOccurrenceId(IEnumerable<IEntity> entities) 1100 Parallel.ForEach(entities, e => 1102 var vo = GetVisitOccurrence(e); 1106 e.VisitOccurrenceId = vo.Id; 1107 e.ProviderId = vo.ProviderId; 1111 e.VisitOccurrenceId = null; 1116 protected DateTime? GetMinDate<T>(IEnumerable<T> inputRecords) where T : class, IEntity 1118 if (inputRecords == null || inputRecords.Count() == 0) 1121 return inputRecords.Min(e => e.StartDate); 1124 protected DateTime? GetMaxDate<T>(IEnumerable<T> inputRecords) where T : class, IEntity 1126 if (inputRecords == null || inputRecords.Count() == 0) 1129 if (inputRecords.Any(e => e.EndDate.HasValue)) 1130 return inputRecords.Where(e => e.EndDate.HasValue).Max(e => e.EndDate.Value); 1135 protected void AddToChunk(Person person, Death death, ObservationPeriod[] observationPeriods, 1136 PayerPlanPeriod[] ppp, DrugExposure[] drugExposures, 1137 ConditionOccurrence[] conditionOccurrences, 1138 ProcedureOccurrence[] procedureOccurrences, Observation[] observations, 1139 VisitOccurrence[] visitOccurrences, Cohort[] cohort) 1141 AddToChunk(person, death, observationPeriods, 1143 conditionOccurrences, 1144 procedureOccurrences, observations, new Measurement[] { }, 1145 visitOccurrences, null, cohort, new DeviceExposure[] { }, 1150 /// Push built entities to ChunkBuilder for further save to CDM database 1152 /// <param name="person">person entity</param> 1153 /// <param name="death">death entity</param> 1154 /// <param name="observationPeriods">the observation period entities for current person</param> 1155 /// <param name="ppp">the payerplan period entities for current person</param> 1156 /// <param name="drugExposures">the drug exposure entities for current person</param> 1157 /// <param name="conditionOccurrences">the condition occurrence entities for current person</param> 1158 /// <param name="procedureOccurrences">the procedure occurrence entities for current person</param> 1159 /// <param name="observations">the observation entities for current person</param> 1160 /// <param name="visitOccurrences">the visit occurrence entities for current person</param> 1162 /// <param name="cohort">the cohort entities for current person</param> 1163 public virtual void AddToChunk(Person person, Death death, ObservationPeriod[] observationPeriods, 1164 PayerPlanPeriod[] ppp, DrugExposure[] drugExposures, 1165 ConditionOccurrence[] conditionOccurrences, 1166 ProcedureOccurrence[] procedureOccurrences, Observation[] observations, 1167 Measurement[] measurements, VisitOccurrence[] visitOccurrences, VisitDetail[] visitDetails, Cohort[] cohort, 1168 DeviceExposure[] devExposure, Note[] notes) 1170 ChunkData.AddData(person); 1174 if (!death.CauseConceptId.HasValue) 1175 death.CauseConceptId = 0; 1177 ChunkData.AddData(death); 1180 foreach (var observationPeriod in observationPeriods) 1182 ChunkData.AddData(observationPeriod); 1185 foreach (var payerPlanPeriod in ppp) 1187 ChunkData.AddData(payerPlanPeriod); 1190 foreach (var visitOccurrence in visitOccurrences) 1192 ChunkData.AddData(visitOccurrence); 1195 if (visitDetails != null) 1197 foreach (var visitDetail in visitDetails) 1199 ChunkData.AddData(visitDetail); 1205 foreach (var c in cohort) 1207 ChunkData.AddData(c); 1213 foreach (var n in notes) 1215 ChunkData.Note.Add(n); 1217 //ChunkData.AddData(n); 1221 AddToChunk("Condition", conditionOccurrences); 1222 AddToChunk("Drug", drugExposures); 1223 AddToChunk("Procedure", procedureOccurrences); 1224 AddToChunk("Observation", observations); 1225 AddToChunk("Measurement", measurements); 1226 AddToChunk("Device", devExposure); 1228 var drugEra = BuildDrugEra(DrugForEra.ToArray(), observationPeriods).ToArray(); 1229 var conditionEra = BuildConditionEra(ConditionForEra.ToArray(), observationPeriods).ToArray(); 1231 foreach (var eraEntity in drugEra) 1233 ChunkData.AddData(eraEntity, EntityType.DrugEra); 1236 foreach (var eraEntity in conditionEra) 1238 ChunkData.AddData(eraEntity, EntityType.ConditionEra); 1242 public string GetDomain(string entityDomain, string conceptDomain) 1244 switch (conceptDomain) 1253 return conceptDomain; 1256 return entityDomain; 1260 public virtual void AddToChunk(string domain, IEnumerable<IEntity> entities) 1262 foreach (var entity in entities) 1264 var entityDomain = GetDomain(domain, entity.Domain); 1266 switch (entityDomain) 1269 var obs = entity as Observation; 1270 if (obs == null || obs.ValueAsNumber == 1) 1272 var cond = entity as ConditionOccurrence ?? 1273 new ConditionOccurrence(entity) 1275 Id = Offset.GetKeyOffset(entity.PersonId).ConditionOccurrenceId 1277 ConditionForEra.Add(cond); 1278 ChunkData.AddData(cond); 1284 ChunkData.AddData(entity as Measurement ?? new Measurement(entity) 1286 Id = Offset.GetKeyOffset(entity.PersonId).MeasurementId 1291 ChunkData.AddData(entity as Measurement ?? new Measurement(entity) 1293 Id = Offset.GetKeyOffset(entity.PersonId).MeasurementId 1298 ChunkData.AddData(entity as Observation ?? new Observation(entity) 1300 Id = Offset.GetKeyOffset(entity.PersonId).ObservationId 1305 ChunkData.AddData(entity as ProcedureOccurrence ?? 1306 new ProcedureOccurrence(entity) 1309 Offset.GetKeyOffset(entity.PersonId).ProcedureOccurrenceId 1314 ChunkData.AddData(entity as DeviceExposure ?? 1315 new DeviceExposure(entity) 1317 Id = Offset.GetKeyOffset(entity.PersonId).DeviceExposureId 1322 var drg = entity as DrugExposure ?? 1323 new DrugExposure(entity) 1325 Id = Offset.GetKeyOffset(entity.PersonId).DrugExposureId 1328 if (!drg.EndDate.HasValue) 1329 drg.EndDate = drg.StartDate; 1331 DrugForEra.Add(drg); 1332 ChunkData.AddData(drg); 1341 /// exclude records that out of any available observation period records 1342 protected static IEnumerable<T> Clean<T>(IEnumerable<T> input, 1343 IEnumerable<ObservationPeriod> observationPeriods, bool withinTheObservationPeriod) where T : IEntity 1345 if (withinTheObservationPeriod) 1347 return input.Where(item => 1348 observationPeriods.FirstOrDefault(p => item.StartDate.Between(p.StartDate, p.EndDate.Value)) != 1356 /// Delete any individual that has an OBSERVATION_PERIOD that is >= 2 years prior to the YEAR_OF_BIRTH 1358 /// <param name="person">the current person entity</param> 1359 /// <param name="periods">the observation period entities for current person</param> 1360 /// <returns>Enumeration of filtered entities</returns> 1361 //public virtual bool Excluded(Person person, IEnumerable<ObservationPeriod> periods) 1363 // return periods.Any(period => person.YearOfBirth - period.StartDate.Year >= 2); 1366 public void JoinToVocabulary(IVocabulary vocabulary) 1368 if (Vocabulary == null) 1369 Vocabulary = vocabulary; 1372 public bool Excluded(Person person, IEnumerable<ObservationPeriod> periods)