///<summary>Generates a list of all the quality measures for 2011. Performs all calculations and manipulations. Returns list for viewing/output.</summary> public static List<QualityMeasure> GetAll(DateTime dateStart,DateTime dateEnd,long provNum) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { return Meth.GetObject<List<QualityMeasure>>(MethodBase.GetCurrentMethod(),dateStart,dateEnd,provNum); } List<QualityMeasure> list=new List<QualityMeasure>(); //add one of each type QualityMeasure measure; for(int i=0;i<Enum.GetValues(typeof(QualityType)).Length;i++) { measure=new QualityMeasure(); measure.Type=(QualityType)i; measure.Id=GetId(measure.Type); measure.Descript=GetDescript(measure.Type); DataTable table=GetTable(measure.Type,dateStart,dateEnd,provNum); if(table!=null) { measure.Denominator=table.Rows.Count; measure.Numerator=CalcNumerator(table); measure.Exclusions=CalcExclusions(table); measure.NotMet=measure.Denominator-measure.Exclusions-measure.Numerator; measure.ReportingRate=100; measure.PerformanceRate=0; if(measure.Numerator > 0) { measure.PerformanceRate=(int)((float)(measure.Numerator*100)/(float)(measure.Numerator+measure.NotMet)); } measure.DenominatorExplain=GetDenominatorExplain(measure.Type); measure.NumeratorExplain=GetNumeratorExplain(measure.Type); measure.ExclusionsExplain=GetExclusionsExplain(measure.Type); } list.Add(measure); } return list; }
///<summary></summary> public QualityMeasure Copy() { QualityMeasure qualityMeasure = (QualityMeasure)this.MemberwiseClone(); qualityMeasure.ListEhrPats = new List <EhrCqmPatient>(); for (int i = 0; i < ListEhrPats.Count; i++) { qualityMeasure.ListEhrPats.Add(ListEhrPats[i].Copy()); } return(qualityMeasure); }
///<summary>Generates a list of all the quality measures for 2014. Performs all calculations and manipulations. Returns list for viewing/output.</summary> public static List<QualityMeasure> GetAll2014(DateTime dateStart,DateTime dateEnd,long provNum) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { return Meth.GetObject<List<QualityMeasure>>(MethodBase.GetCurrentMethod(),dateStart,dateEnd,provNum); } List<QualityMeasure> list=new List<QualityMeasure>(); //add one of each type QualityMeasure measureCur; _measureWeightAssessAll=new QualityMeasure(); _measureWeightAssess3To11=new QualityMeasure(); _measureWeightAssess12To16=new QualityMeasure(); #if DEBUG System.Diagnostics.Stopwatch s=new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch stot=new System.Diagnostics.Stopwatch(); _elapsedtimetext="Elapsed time for each measure.\r\n"; stot.Restart(); #endif for(int i=0;i<Enum.GetValues(typeof(QualityType2014)).Length;i++) { #if DEBUG s.Restart(); #endif measureCur=GetEhrCqmData((QualityType2014)i,dateStart,dateEnd,provNum); measureCur.Type2014=(QualityType2014)i; measureCur.Id=GetId2014(measureCur.Type2014); measureCur.Descript=GetDescript2014(measureCur.Type2014); if(measureCur.ListEhrPats!=null) { if((QualityType2014)i==QualityType2014.Influenza) { //only have to count IsDenominator pats for influenza measure, all other measures will have every patient marked IsDenominator (denom=initial pat population) //influenza measure applies additional restriction to initial pat population, but ListEhrPats will still have IPP in it, but only some will be in denominator measureCur.Denominator=CalcDenominator2014(measureCur.ListEhrPats); } else if((QualityType2014)i==QualityType2014.MedicationsEntered) { //we have to count the number of encounters, not the number of patients, for the denominator count measureCur.Denominator=CalcDenominator2014_Encs(measureCur.DictPatNumListEncounters); } else { measureCur.Denominator=measureCur.ListEhrPats.Count; } if((QualityType2014)i==QualityType2014.MedicationsEntered) { measureCur.Numerator=CalcNumerator2014_Encs(measureCur.DictPatNumListEncounters); measureCur.Exceptions=CalcException2014_Encs(measureCur.DictPatNumListEncounters); measureCur.Exclusions=0; } else { measureCur.Numerator=CalcNumerator2014(measureCur.ListEhrPats); measureCur.Exclusions=CalcExclusions2014(measureCur.ListEhrPats); measureCur.Exceptions=CalcExceptions2014(measureCur.ListEhrPats); } measureCur.NotMet=measureCur.Denominator-measureCur.Exclusions-measureCur.Numerator-measureCur.Exceptions; //Reporting rate is (Numerator+Exclusions+Exceptions)/Denominator. Percentage of qualifying pats classified in one of the three groups Numerator, Exception, Exclusion. measureCur.ReportingRate=0; if(measureCur.Denominator>0) { measureCur.ReportingRate=Math.Round(((decimal)((measureCur.Numerator+measureCur.Exclusions+measureCur.Exceptions)*100)/(decimal)(measureCur.Denominator)),1,MidpointRounding.AwayFromZero); } //Performance rate is Numerator/(Denominator-Exclusions-Exceptions). Percentage of qualifying pats (who were not in the Exclusions or Exceptions) who were in the Numerator. measureCur.PerformanceRate=0; if(measureCur.Numerator>0) { measureCur.PerformanceRate=Math.Round(((decimal)(measureCur.Numerator*100)/(decimal)(measureCur.Denominator-measureCur.Exclusions-measureCur.Exceptions)),1,MidpointRounding.AwayFromZero); } measureCur.DenominatorExplain=GetDenominatorExplain2014(measureCur.Type2014); measureCur.NumeratorExplain=GetNumeratorExplain2014(measureCur.Type2014); measureCur.ExclusionsExplain=GetExclusionsExplain2014(measureCur.Type2014); measureCur.ExceptionsExplain=GetExceptionsExplain2014(measureCur.Type2014); measureCur.eMeasureNum=GetEMeasureNum(measureCur.Type2014); measureCur.eMeasureTitle=GetEMeasureTitle(measureCur.Type2014); measureCur.eMeasureVersion=GetEMeasureVersion(measureCur.Type2014); measureCur.eMeasureVNeutralId=GetEMeasureVNeutralId(measureCur.Type2014); measureCur.eMeasureVSpecificId=GetEMeasureVSpecificId(measureCur.Type2014); measureCur.eMeasureSetId=GetEMeasureSetId(measureCur.Type2014); measureCur.eMeasureIppId=GetEMeasureIppId(measureCur.Type2014); measureCur.eMeasureDenomId=GetEMeasureDenomId(measureCur.Type2014); measureCur.eMeasureDenexId=GetEMeasureDenexId(measureCur.Type2014); measureCur.eMeasureDenexcepId=GetEMeasureDenexcepId(measureCur.Type2014); measureCur.eMeasureNumerId=GetEMeasureNumerId(measureCur.Type2014); } list.Add(measureCur); #if DEBUG s.Stop(); _elapsedtimetext+=((QualityType2014)i).ToString()+": "+s.Elapsed.ToString()+"\r\n"; #endif } #if DEBUG stot.Stop(); _elapsedtimetext+="Total elapsed time: "+stot.Elapsed.ToString(); System.Windows.Forms.MessageBox.Show(_elapsedtimetext); #endif return list; }
///<summary>Using the data in alldata, determine if the patients in alldata.ListEhrPats are in the 'Numerator', 'Exclusion', or 'Exception' category for this measure and enter an explanation if applicable. All of the patients in ListEhrPats are the initial patient population (almost always equal to the Denominator).</summary> private static void ClassifyPatients(QualityMeasure alldata,QualityType2014 qtype,DateTime dateStart,DateTime dateEnd) { switch(qtype) { #region MedicationsEntered case QualityType2014.MedicationsEntered: //THIS IS ENCOUNTER BASED, NOT PATIENT BASED //alldata.ListEhrPats: All unique patients with necessary reporting data. This is the initial patient population (Denominator). //alldata.DictPatNumListEncounters: PatNums linked to a list of all encounters from the eligble value sets for patients 18 or over at the start of the measurement period. //alldata.DictPatNumListMeasureEvents: All Current Meds Documented 'procedures' that occurred during the measurement period //alldata.DictPatNumListNotPerfs: All Current Meds Documented events not performed with valid reasons that occurred during the measurement period //No exclusions for this measure //Strategy: For each patient in ListEhrPats, loop through the encounters in dictionary DictPatNumListEncounters; key=PatNum, value=List<EhrCqmEncounter> //For each encounter, loop through the measure events in DictPatNumListMeasureEvents and try to locate a meds documented 'proc' on the same date. //If one exists for that encounter, mark the encounter as being in the numerator //If no procedure exists, look for a not performed item for Exception //Otherwise unclassified bool isClassified=false;//used to indicate that the encounter has been included in the numerator, so do not try to apply exception foreach(KeyValuePair<long,List<EhrCqmEncounter>> kvpair in alldata.DictPatNumListEncounters) { List<EhrCqmMeasEvent> listMedsDocProcsCur=new List<EhrCqmMeasEvent>(); if(alldata.DictPatNumListMeasureEvents.ContainsKey(kvpair.Key)) { listMedsDocProcsCur=alldata.DictPatNumListMeasureEvents[kvpair.Key]; } List<EhrCqmNotPerf> listNotPerfCur=new List<EhrCqmNotPerf>(); if(alldata.DictPatNumListNotPerfs.ContainsKey(kvpair.Key)) { listNotPerfCur=alldata.DictPatNumListNotPerfs[kvpair.Key]; } //first try to apply the numerator criteria to the encounters, if there is no ehrmeasureevent on the same day, try to apply the exception criteria for(int i=0;i<kvpair.Value.Count;i++) {//for every encounter for this patient isClassified=false; for(int j=0;j<listMedsDocProcsCur.Count;j++) {//this might be an empty list if no meds documented procs for this patient if(kvpair.Value[i].DateEncounter.Date==listMedsDocProcsCur[j].DateTEvent.Date) {//if meds documented proc on the same day as the encounter, then numerator isClassified=true; kvpair.Value[i].IsNumerator=true; kvpair.Value[i].Explanation="There is an encounter on "+kvpair.Value[i].DateEncounter.ToShortDateString()+" with a current medications documented procedure on the same date."; break; } } if(isClassified) {//don't try to apply exception criteria if already in the numerator continue; } for(int j=0;j<listNotPerfCur.Count;j++) {//if encounter is not in the numerator, try to apply the exception criteria if(kvpair.Value[i].DateEncounter.Date==listNotPerfCur[j].DateEntry.Date) { kvpair.Value[i].IsException=true; kvpair.Value[i].Explanation="There is an encounter on "+kvpair.Value[i].DateEncounter.ToShortDateString()+" with a not performed item with valid reason on the same date."; isClassified=true; break; } } if(isClassified) {//it is an exception encounter, move to next encounter continue; } //otherwise the encounter is NotMet kvpair.Value[i].Explanation="There is an encounter on "+kvpair.Value[i].DateEncounter.ToShortDateString()+" but no current medications documented procedure or not performed item on the same date."; } } break; #endregion #region WeightAdultAndOver65 case QualityType2014.WeightAdult: case QualityType2014.WeightOver65: //Strategy: All patients in alldata.ListEhrPats are the initial patient population for this measure //Denominator - Inital Patient Population //Exclusions - Pregnant during any of the measurement period //Find the most recent vitalsign exam date such that there is a valid encounter within the 6 months after the exam //If there is more than one encounter within that 6 months, one of them must meet the numerator criteria for the patient to be in the numerator //If that most recent exam found the patient with BMI >= 23 kg/m2 and < 30 kg/m2 for Over65, >= 18.5 and < 25 for Adult, 'Numerator' //If the most recent exam found the patient with BMI < 23 kg/m2 or >= 30 kg/m2 for Over65, < 18.5 or >= 25 for Adult, check for Intervention or Medication Order //The intervention/medication order must be within 6 months of one of the encounters, which are within 6 months of the exam //If order exists for any encounter, 'Numerator' //If no intervention/medication order for any of the encounters for the exam, not classified for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; bool isCategorized=false; //first apply pregnancy exclusion List<EhrCqmProblem> listProbsCur=new List<EhrCqmProblem>(); if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { listProbsCur=alldata.DictPatNumListProblems[patNumCur]; } for(int j=0;j<listProbsCur.Count;j++) { if(listProbsCur[j].ValueSetOID=="2.16.840.1.113883.3.600.1.1623") {//Pregnancy Dx Grouping Value Set alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had a pregnancy diagnosis that started on "+listProbsCur[j].DateStart.ToShortDateString()+" that is either still active or ended after the start of the measurement period."; isCategorized=true; break; } } if(isCategorized) { continue; } //get vital sign exams that took place in the measurement period for the patient. Ordered by DateTaken DESC, so index 0 will hold the most recent exam List<EhrCqmVitalsign> listVitalsignsCur=new List<EhrCqmVitalsign>(); if(alldata.DictPatNumListVitalsigns.ContainsKey(patNumCur)) { listVitalsignsCur=alldata.DictPatNumListVitalsigns[patNumCur]; } if(listVitalsignsCur.Count==0) {//no vitalsign exams within 6 months of start of measurement period, but encounters exist or they would not be in the IPP alldata.ListEhrPats[i].Explanation="Valid encounters exist, but there are no BMI vital sign exams within 6 months of the measurement period."; continue; } //get eligible enounters that took place in the measurement period for the patient. Ordered by DateEncounter DESC, so index 0 will hold the most recent. List<EhrCqmEncounter> listEncsCur=new List<EhrCqmEncounter>(); if(alldata.DictPatNumListEncounters.ContainsKey(patNumCur)) { listEncsCur=alldata.DictPatNumListEncounters[patNumCur]; } //Find the most recent exam date such that there is an eligible encounter on that date or within the 6 months after the exam date DateTime dateMostRecentExam=DateTime.MinValue; int indexMostRecentExam=-1; for(int j=0;j<listVitalsignsCur.Count;j++) { if(dateMostRecentExam.Date>listVitalsignsCur[j].DateTaken.Date) {//most recent exam date already set and set to a date more recent than current, continue continue; } for(int k=0;k<listEncsCur.Count;k++) { if(listVitalsignsCur[j].DateTaken.Date<=listEncsCur[k].DateEncounter.Date && listVitalsignsCur[j].DateTaken.Date>=listEncsCur[k].DateEncounter.AddMonths(-6).Date && listVitalsignsCur[j].DateTaken.Date>=dateMostRecentExam.Date) { dateMostRecentExam=listVitalsignsCur[j].DateTaken; indexMostRecentExam=j; break; } } } //If there are no exams that occurred within 6 months of an eligible encounter, not classified if(indexMostRecentExam==-1) { alldata.ListEhrPats[i].Explanation="Valid encounters exist and BMI vital sign exams exist, but no BMI exam date is within 6 months of a valid encounter in the measurement period."; continue; } //If WeightOver65 measure AND the most recent BMI was in the allowed range of >=23 and <30 kg/m2, then no intervention required, patient in 'Numerator' if(qtype==QualityType2014.WeightOver65 && listVitalsignsCur[indexMostRecentExam].BMI>=23m && listVitalsignsCur[indexMostRecentExam].BMI<30m) {//'m' converts to decimal alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="BMI in normal range. Most recent BMI exam date: "+listVitalsignsCur[indexMostRecentExam].DateTaken.ToShortDateString()+". BMI result: "+listVitalsignsCur[indexMostRecentExam].BMI.ToString(); continue; } //If WeightAdult measure AND the most recent BMI was in the allowed range of >=23 and <30 kg/m2, then no intervention required, patient in 'Numerator' if(qtype==QualityType2014.WeightAdult && listVitalsignsCur[indexMostRecentExam].BMI>=18.5m && listVitalsignsCur[indexMostRecentExam].BMI<25m) {//'m' converts to decimal alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="BMI in normal range. Most recent BMI exam date: "+listVitalsignsCur[indexMostRecentExam].DateTaken.ToShortDateString()+". BMI result: "+listVitalsignsCur[indexMostRecentExam].BMI.ToString(); continue; } //BMI must be out of range, for each encounter of which this exam is within the previous 6 months, look for an intervention/medication order that took place within the 6 months prior to the encounter //If an encounter and intervention/medication order exist for this encounter, 'Numerator' List<EhrCqmIntervention> listInterventionsCur=new List<EhrCqmIntervention>(); if(alldata.DictPatNumListInterventions.ContainsKey(patNumCur)) { listInterventionsCur=alldata.DictPatNumListInterventions[patNumCur]; } List<EhrCqmMedicationPat> listMedPatsCur=new List<EhrCqmMedicationPat>(); if(alldata.DictPatNumListMedPats.ContainsKey(patNumCur)) { listMedPatsCur=alldata.DictPatNumListMedPats[patNumCur]; } for(int j=0;j<listEncsCur.Count;j++) { //if encounter is before exam or more than 6 months after the exam, move to next encounter if(listEncsCur[j].DateEncounter.Date<listVitalsignsCur[indexMostRecentExam].DateTaken.Date || listEncsCur[j].DateEncounter.Date>listVitalsignsCur[indexMostRecentExam].DateTaken.AddMonths(6).Date) { continue; } for(int k=0;k<listInterventionsCur.Count;k++) { //if intervention order is within 6 months of the encounter, classify as 'Numerator' if(listInterventionsCur[k].DateEntry.Date<=listEncsCur[j].DateEncounter.Date && listInterventionsCur[k].DateEntry.Date>=listEncsCur[j].DateEncounter.AddMonths(-6).Date) { //encounter within 6 months of the most recent exam and intervention within 6 months of encounter, 'Numerator' alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="Most recent exam on "+listVitalsignsCur[indexMostRecentExam].DateTaken.ToShortDateString()+" with encounter on " +listEncsCur[j].DateEncounter.ToShortDateString()+" resulted in a BMI of "+listVitalsignsCur[indexMostRecentExam].BMI.ToString()+" " +"and intervention on "+listInterventionsCur[k].DateEntry.ToShortDateString()+"."; isCategorized=true; break; } } if(isCategorized) { break; } for(int k=0;k<listMedPatsCur.Count;k++) { //if medication order is within 6 months of the encounter, classify as 'Numerator' if(listMedPatsCur[k].DateStart.Date<=listEncsCur[j].DateEncounter.Date && listMedPatsCur[k].DateStart.Date>=listEncsCur[j].DateEncounter.AddMonths(-6).Date) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="Most recent exam on "+listVitalsignsCur[indexMostRecentExam].DateTaken.ToShortDateString()+" with encounter on " +listEncsCur[j].DateEncounter.ToShortDateString()+" resulted in a BMI of "+listVitalsignsCur[indexMostRecentExam].BMI.ToString()+" " +"and medication order on "+listMedPatsCur[k].DateStart.ToShortDateString()+"."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } //If we get here, the most recent BMI exam that had eligible encounters on the exam date or within the 6 months after that date resulted in a BMI outside of normal range //but there were no intervention/medication orders entered alldata.ListEhrPats[i].Explanation="Most recent exam on "+listVitalsignsCur[indexMostRecentExam].DateTaken.ToShortDateString()+" with BMI of " +listVitalsignsCur[indexMostRecentExam].BMI.ToString()+" had valid encounters within 6 months of the exam but no valid intervention or medication order."; } break; #endregion #region CariesPrevent case QualityType2014.CariesPrevent: case QualityType2014.CariesPrevent_1: case QualityType2014.CariesPrevent_2: case QualityType2014.CariesPrevent_3: //Strategy: alldata.ListEhrPats will be the initial patient population, already restricted by appropriate age for all, _1, _2 and _3 stratification //No Exclusions, denominator is initial patient population //alldata.DictPatNumListProcs will hold the eligible procs in the measurement period for the patients in the initial patient population //if Dict contains PatNum, 'Numerator' for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; if(alldata.DictPatNumListProcs.ContainsKey(patNumCur)) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="This patient had an eligible encounter in the measurement period and a flouride varnish application procedure with code " +alldata.DictPatNumListProcs[patNumCur][0].ProcCode+" on "+alldata.DictPatNumListProcs[patNumCur][0].ProcDate.ToShortDateString()+"."; continue; } alldata.ListEhrPats[i].Explanation="This patient had an eligible encounter in the measurement period, but did not have a flouride varnish application procedure with a valid code in the measurement period."; } break; #endregion #region ChildCaries case QualityType2014.ChildCaries: //This measure is misleading, A lower score indicates better quality, so a high percentage means they have a lot of kids with cavities or dental decay //Strategy: alldata.ListEhrPats will be the initial patient population, already restricted by age >=0 and < 20 at start of measurement period //No Exclusions, denominator is initial patient population //alldata.DictPatNumListProblems will hold all eligible problems for dental caries with a start date before the end of the measurement period and either no end date or an end date after the start of the measurement period //if patient is in ListEhrPats and Dict contains PatNum, 'Numerator' for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="This patient had an eligible encounter in the measurement period and had an active diagnosis of caries with code " +alldata.DictPatNumListProblems[patNumCur][0].CodeValue+" that started on "+alldata.DictPatNumListProblems[patNumCur][0].DateStart.ToShortDateString()+"."; continue; } alldata.ListEhrPats[i].Explanation="This patient had an eligible encounter in the measurement period, but did not have an active diagnosis of caries with a valid code in the measurement period."; } break; #endregion #region Pneumonia case QualityType2014.Pneumonia: //Strategy: alldata.ListEhrPats is IPP and denominator, non exclusions //Numerator: if medicationpat, procedure, or problem exists, numerator //Otherwise: not categorized for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; bool isCategorized=false; //first see if medicationpat exists List<EhrCqmMedicationPat> listMedPatsCur=new List<EhrCqmMedicationPat>(); if(alldata.DictPatNumListMedPats.ContainsKey(patNumCur)) { listMedPatsCur=alldata.DictPatNumListMedPats[patNumCur]; } for(int j=0;j<listMedPatsCur.Count;j++) { if(listMedPatsCur[j].ValueSetOID=="2.16.840.1.113883.3.464.1003.110.12.1027") {//Pneumococcal Vaccine Grouping Value Set alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The patient had a Pneumococcal medication administered on "+listMedPatsCur[j].DateStart.ToShortDateString()+"."; isCategorized=true; break; } } if(isCategorized) { continue; } List<EhrCqmProc> listProcsCur=new List<EhrCqmProc>(); if(alldata.DictPatNumListProcs.ContainsKey(patNumCur)) { listProcsCur=alldata.DictPatNumListProcs[patNumCur]; } for(int j=0;j<listProcsCur.Count;j++) { if(listProcsCur[j].ValueSetOID=="2.16.840.1.113883.3.464.1003.110.12.1034") {//Pneumococcal Vaccine Administered Grouping Value Set alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The patient had a Pneumococcal administered procedure on "+listProcsCur[j].ProcDate.ToShortDateString()+"."; isCategorized=true; break; } } if(isCategorized) { continue; } List<EhrCqmProblem> listProbsCur=new List<EhrCqmProblem>(); if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { listProbsCur=alldata.DictPatNumListProblems[patNumCur]; } for(int j=0;j<listProbsCur.Count;j++) { if(listProbsCur[j].ValueSetOID=="2.16.840.1.113883.3.464.1003.110.12.1028") {//History of Pneumococcal Vaccine Grouping Value Set alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The patient has a history of Pneumococcal vaccination on "+listProbsCur[j].DateStart.ToShortDateString()+"."; isCategorized=true; break; } } if(isCategorized) { continue; } alldata.ListEhrPats[i].Explanation="The patient had eligible encounters in the date range but no Pneumococcal vaccine was administered and no history of having had the vaccine was recorded."; } break; #endregion #region TobaccoCessation case QualityType2014.TobaccoCessation: //alldata.ListEhrPats: All unique patients with necessary reporting data. This is the initial patient population (Denominator). //alldata.ListEncounters: All encounters from the eligble value sets for patients 18 or over at the start of the measurement period. //alldata.ListMeasureEvents: All tobacco use assessment ehrmeasureevents with recorded status that occurred within 24 months of the end of the measurement period //alldata.ListInterventions: All eligible interventions performed within 24 months of the end of the measurement period //alldata.ListMedPats: All eligible medications, active or ordered, that started within 24 months of the end of the measurement period //alldata.ListNotPerfs: All tobacco assessment events not performed with valid reasons that occurred during the measurement period //alldata.ListProblems: All eligible problems that were active during any of the measurement period. for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; //No exclusions for this measure //Strategy: Find the most recent tobacco assessment for the patient. //If Non-User, this patient is in the Numerator. //If User, check for intervention, medication active or order, if one exists, then Numerator. //If User and no intervention/med, or no assessment at all, then check notperformed and problems for possible Exception. //Finally, if none of the above, then only fill the Explanation column with the appropriate text. #region Get most recent assessment date and value set OID for patient DateTime mostRecentAssessDate=DateTime.MinValue; string mostRecentAssessValueSetOID=""; List<EhrCqmMeasEvent> listMeasEventsCur=new List<EhrCqmMeasEvent>(); if(alldata.DictPatNumListMeasureEvents.ContainsKey(patNumCur)) { listMeasEventsCur=alldata.DictPatNumListMeasureEvents[patNumCur]; } for(int j=0;j<listMeasEventsCur.Count;j++) { if(listMeasEventsCur[j].DateTEvent>mostRecentAssessDate) { mostRecentAssessDate=listMeasEventsCur[j].DateTEvent; mostRecentAssessValueSetOID=listMeasEventsCur[j].ValueSetOID; } } #endregion //if most recently (all assessments in our list are in the last 24 months prior to the measurement period end date) assessed Non-User, then Numerator #region Most recently assessed Non-User if(mostRecentAssessDate>DateTime.MinValue && mostRecentAssessValueSetOID=="2.16.840.1.113883.3.526.3.1189") {//Non-User alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="Patient categorized as Non-User on "+mostRecentAssessDate.Date.ToShortDateString(); continue; } #endregion //if most recently assessed User, check for intervention or medication active/order #region Most recently assessed User if(mostRecentAssessDate>DateTime.MinValue && mostRecentAssessValueSetOID=="2.16.840.1.113883.3.526.3.1170") {//User //check for intervention. If in the list, it is already guaranteed to be valid and in the date range and order by PatNum and DateEntry, so first one found will be the most recent for the patient List<EhrCqmIntervention> listIntervensCur=new List<EhrCqmIntervention>(); if(alldata.DictPatNumListInterventions.ContainsKey(patNumCur)) { listIntervensCur=alldata.DictPatNumListInterventions[patNumCur]; } if(listIntervensCur.Count>0) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="Patient categorized as User with an intervention on "+listIntervensCur[0].DateEntry.ToShortDateString(); continue; } //check for medication. If there is one in the list, it is guaranteed to be valid for tobacco cessation and in the date range and ordered by PatNum and DateStart, so first found is most recent List<EhrCqmMedicationPat> listMedPatsCur=new List<EhrCqmMedicationPat>(); if(alldata.DictPatNumListMedPats.ContainsKey(patNumCur)) { listMedPatsCur=alldata.DictPatNumListMedPats[patNumCur]; } if(listMedPatsCur.Count>0) { alldata.ListEhrPats[i].IsNumerator=true; string explain="Patient categorized as User with medication "; string activeOrOrder="active"; if(listMedPatsCur[0].PatNote!="") {//PatNote means Medication Order, otherwise Medication Active activeOrOrder="order"; } alldata.ListEhrPats[i].Explanation=explain+activeOrOrder+" with start date "+listMedPatsCur[0].DateStart.ToShortDateString(); continue; } } #endregion //if we get here, there is either no valid assessment date in the date range or the patient was most recently categorized as User with no intervention or medication //check for valid NotPerformed item, for exception #region Check for not performed //alldata.ListNotPerf is ordered by PatNum, DateEntry DESC so first one found is the most recent for the patient List<EhrCqmNotPerf> listNotPerfsCur=new List<EhrCqmNotPerf>(); if(alldata.DictPatNumListNotPerfs.ContainsKey(patNumCur)) { listNotPerfsCur=alldata.DictPatNumListNotPerfs[patNumCur]; } if(listNotPerfsCur.Count>0) { alldata.ListEhrPats[i].IsException=true; alldata.ListEhrPats[i].Explanation="Assessment not done for valid medical reason on "+listNotPerfsCur[0].DateEntry.ToShortDateString(); continue; } #endregion //last, check for limited life expectancy, for exception #region Check for active diagnosis of limited life expectancy List<EhrCqmProblem> listProbsCur=new List<EhrCqmProblem>(); if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { listProbsCur=alldata.DictPatNumListProblems[patNumCur]; } if(listProbsCur.Count>0) { alldata.ListEhrPats[i].IsException=true; string explain="Assessment not done due to an active limited life expectancy diagnosis"; if(listProbsCur[0].DateStart.Year>1880) { explain+=" with start date "+listProbsCur[0].DateStart.ToShortDateString(); } alldata.ListEhrPats[i].Explanation=explain; continue; } #endregion //still not categorized, put note in explanation, could be due to no assessment in date range or categorized User with no intervention/medication #region Not met explanation if(mostRecentAssessDate==DateTime.MinValue) { alldata.ListEhrPats[i].Explanation="No tobacco use assessment entered"; } else if(mostRecentAssessValueSetOID=="2.16.840.1.113883.3.526.3.1170") {//User alldata.ListEhrPats[i].Explanation="Patient categorized as User on "+mostRecentAssessDate.ToShortDateString()+" without an intervention"; } #endregion } break; #endregion #region Influenza case QualityType2014.Influenza: //Strategy: alldata.ListEhrPats will hold all initial patient population //Denominator: alldata.ListEhrPats where IsDenominator=true //No Exclusions //Numerator: if proc, med, or previous receipt during any eligible encounter or proc in the flu season, then numerator //Exceptions: if not Numerator, check for vaccine declined or not performed item with valid reason during any eligible encounter or proc in the flu season //OR check for allergy or intolerance before or during the eligible encounter or proc for(int i=0;i<alldata.ListEhrPats.Count;i++) { if(!alldata.ListEhrPats[i].IsDenominator) {//if not in denominator, they will not show in grid of FormEhrQualityMeasureEdit2014, skip this patient, only in IPP continue; } long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; bool isCategorized=false; //The list of encounters will contain the one-of and two-of encounters during the measurement period that qualify patient for IPP //PLUS the Encounter, Performed: Encounter-Influenza encs that took place <= 92 days before start of measurement period or <= 91 days after start of measurement period. //Each of these influenza encs will be the "Occurrence A of..." that we will be using to try to match the numerator procs/meds/communications. List<EhrCqmEncounter> listAllEncsCur=new List<EhrCqmEncounter>(); if(alldata.DictPatNumListEncounters.ContainsKey(patNumCur)) { listAllEncsCur=alldata.DictPatNumListEncounters[patNumCur]; } //The list of procs will contain procs that qualify pat for the IPP, plus procs that qualify pat for the denominator, plus any procs that may qualify pat for the numerator List<EhrCqmProc> listAllProcsCur=new List<EhrCqmProc>(); if(alldata.DictPatNumListProcs.ContainsKey(patNumCur)) { listAllProcsCur=alldata.DictPatNumListProcs[patNumCur]; } //The list of medicationpats will contain only meds from the value set 2.16.840.1.113883.3.526.3.1254 - Influenza Vaccine Grouping Value Set //But will be for any date in date range 0001-01-01 through 91 days after measurement period start date //Those with CompletionStatus=Complete, and took place <= 92 days before start through <= 91 days after start date range and during "Occurrence A of.." event will be used for numerator //Those with CompletionStatus=NotAdministered will be considered allergy or intolerance and used in exceptions List<EhrCqmMedicationPat> listAllMedPatsCur=new List<EhrCqmMedicationPat>(); if(alldata.DictPatNumListMedPats.ContainsKey(patNumCur)) { listAllMedPatsCur=alldata.DictPatNumListMedPats[patNumCur]; } //The list of problems will contain the communication of previous receipt items for use in numerator that occurred during "Occurrence A of..." //AND the communication of vaccine declined for use in exceptions that occurred during "Occurrence A of..." //AND the allergy/intolerance to eggs/vaccine diagnoses that occurred any time before or during "Occurrence A of..." List<EhrCqmProblem> listAllProbsCur=new List<EhrCqmProblem>(); if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { listAllProbsCur=alldata.DictPatNumListProblems[patNumCur]; } //create list of "Occurrence A of..." encounter/procedure dates List<DateTime> listOccurrenceADates=new List<DateTime>(); for(int j=0;j<listAllEncsCur.Count;j++) { if(listAllEncsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1252") {//Encounter-Influenza Grouping Value Set continue; } if(listAllEncsCur[j].DateEncounter.Date>=dateStart.AddDays(-92).Date && listAllEncsCur[j].DateEncounter.Date<=dateStart.AddDays(91).Date) { //encounter is in value set and date range, one of the "Occurrence A of..." encounters listOccurrenceADates.Add(listAllEncsCur[j].DateEncounter); } } for(int j=0;j<listAllProcsCur.Count;j++) { if(listAllProcsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1083"//Hemodialysis Grouping Value Set && listAllProcsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1084")//Peritoneal Dialysis Grouping Value Set { continue; } if(listAllProcsCur[j].ProcDate.Date>=dateStart.AddDays(-92).Date && listAllProcsCur[j].ProcDate<=dateStart.AddDays(91).Date) { //procedure is in one of the eligible value sets and in flu season date range, one of the "Occurrence A of..." procedures if(!listOccurrenceADates.Contains(listAllProcsCur[j].ProcDate)) { listOccurrenceADates.Add(listAllProcsCur[j].ProcDate); } } } //apply numerator procs for(int j=0;j<listAllProcsCur.Count;j++) { if(listAllProcsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.402") {//Influenza Vaccination Grouping Value Set continue; } for(int k=0;k<listOccurrenceADates.Count;k++) { if(listAllProcsCur[j].ProcDate.Date==listOccurrenceADates[k].Date) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter on "+listOccurrenceADates[k].ToShortDateString()+" and had an influenza vaccination procedure on that date."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } //apply numerator meds for(int j=0;j<listAllMedPatsCur.Count;j++) {//already only consists of meds from value set 2.16.840.1.113883.3.526.3.1254 - Influenza Vaccine Grouping Value Set if(listAllMedPatsCur[j].CompletionStatus==VaccineCompletionStatus.NotAdministered) {//status other than complete, skip continue; } for(int k=0;k<listOccurrenceADates.Count;k++) { if(listOccurrenceADates[k].Date==listAllMedPatsCur[j].DateStart.Date) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter on "+listOccurrenceADates[k].ToShortDateString()+" and had an influenza vaccine medication administered on that date."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } //apply communication of previous receipt of vaccine 'problems' for(int j=0;j<listAllProbsCur.Count;j++) { if(listAllProbsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1185") {//Previous Receipt of Influenza Vaccine Grouping Value Set continue; } for(int k=0;k<listOccurrenceADates.Count;k++) { if(listOccurrenceADates[k].Date==listAllProbsCur[j].DateStart.Date) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter on "+listOccurrenceADates[k].ToShortDateString()+" and communicated having previous receipt of the influenza vaccine to the provider on that date."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } //Not in numerator, try to apply exceptions for(int j=0;j<listAllProbsCur.Count;j++) { if(listAllProbsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1255") {//Influenza Vaccination Declined Grouping Value Set continue; } for(int k=0;k<listOccurrenceADates.Count;k++) { if(listOccurrenceADates[k].Date==listAllProbsCur[j].DateStart.Date) { alldata.ListEhrPats[i].IsException=true; alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter on "+listOccurrenceADates[k].ToShortDateString()+" and declined the influenza vaccination on that date."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } //The list of not perfs will contain the procs/meds not performed for valid med/pat/system reason in the <= 92 days before start through <= 91 days after start date range List<EhrCqmNotPerf> listNotPerfsCur=new List<EhrCqmNotPerf>(); if(alldata.DictPatNumListNotPerfs.ContainsKey(patNumCur)) { listNotPerfsCur=alldata.DictPatNumListNotPerfs[patNumCur]; } for(int j=0;j<listNotPerfsCur.Count;j++) { for(int k=0;k<listOccurrenceADates.Count;k++) { if(listNotPerfsCur[j].DateEntry.Date==listOccurrenceADates[k].Date) { alldata.ListEhrPats[i].IsException=true; alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter on "+listOccurrenceADates[k].ToShortDateString()+" and the influenza vaccine procedure or medication was not performed for valid reason on that date."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } //check for allergies or intolerances in problem list or medpat list that happened any time before "Occurrence A of..." or during that occurrence //problem list has the problems for these three value sets that occurred from '0001-01-01' through dateStart + 91 days for(int j=0;j<listAllProbsCur.Count;j++) { if(listAllProbsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1253"//Allergy to eggs Grouping Value Set && listAllProbsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1256"//Allergy to Influenza Vaccine Grouping Value Set && listAllProbsCur[j].ValueSetOID!="2.16.840.1.113883.3.526.3.1257")//Intolerance to Influenza Vaccine Grouping Value Set { continue; } for(int k=0;k<listOccurrenceADates.Count;k++) { if(listAllProbsCur[j].DateStart.Date<=listOccurrenceADates[k].Date) { alldata.ListEhrPats[i].IsException=true; alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter on "+listOccurrenceADates[k].ToShortDateString()+" and had a diagnosis of allergy or intolerance to the influenza vaccine or an allergy to eggs prior to or on that date."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } for(int j=0;j<listAllMedPatsCur.Count;j++) { if(listAllMedPatsCur[j].CompletionStatus==VaccineCompletionStatus.Complete) {//Only looking for NotAdministered, if status=Complete, skip continue; } for(int k=0;k<listOccurrenceADates.Count;k++) { if(listAllMedPatsCur[j].DateStart.Date<=listOccurrenceADates[k].Date) { alldata.ListEhrPats[i].IsException=true; alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter on "+listOccurrenceADates[k].ToShortDateString()+" and had an influenza vaccine not given due to an allergy or intolerance prior to or on that date."; isCategorized=true; break; } } if(isCategorized) { break; } } if(isCategorized) { continue; } //if we get here, the patient is in the denominator but does not fit the numerator or exception criteria, Not Met alldata.ListEhrPats[i].Explanation="The patient had an eligible procedure or encounter but did not have an influenza vaccine administered or valid reason documented for not administering the vaccine."; } break; #endregion #region WeightChild_X_1 //All the _1 measures will calculate BMI, height, and weight exams the same, the ListEhrPats will be limited by the age groups already case QualityType2014.WeightChild_1_1: case QualityType2014.WeightChild_2_1: case QualityType2014.WeightChild_3_1: //Strategy: alldata.ListEhrPats will be initial patient population //First check for pregnancy diagnosis, alldata.DictPatNumListProblems will hold all of the pregnancy problems that were active during any of the measurement period. //Exclusion if active pregnancy dx exists //alldata.DictPatNumListVitalsigns holds all vitalsign exams in the date range with a valid height and weight value. //Make sure the vitalsign.BMIExamCode, vitalsign.HeightExamCode, and vitalsign.WeightExamCode are in the allowed value sets //If the codes in BMI, height and weight exam code fields are in the value sets, 'Numerator' //No exceptions for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; bool isCategorized=false; //first apply pregnancy exclusion List<EhrCqmProblem> listProbsCur=new List<EhrCqmProblem>(); if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { listProbsCur=alldata.DictPatNumListProblems[patNumCur]; } for(int j=0;j<listProbsCur.Count;j++) { if(listProbsCur[j].ValueSetOID=="2.16.840.1.113883.3.526.3.378") {//Pregnancy Grouping Value Set alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had a pregnancy diagnosis that started on "+listProbsCur[j].DateStart.ToShortDateString()+" that is either still active or ended after the start of the measurement period."; isCategorized=true; break; } } if(isCategorized) { continue; } //get vital sign exams that took place in the measurement period for the patient. Ordered by DateTaken DESC, so index 0 will hold the most recent exam List<EhrCqmVitalsign> listVitalsignsCur=new List<EhrCqmVitalsign>(); if(alldata.DictPatNumListVitalsigns.ContainsKey(patNumCur)) { listVitalsignsCur=alldata.DictPatNumListVitalsigns[patNumCur]; } if(listVitalsignsCur.Count==0) {//no vitalsign exams within 6 months of start of measurement period, but encounters exist or they would not be in the IPP alldata.ListEhrPats[i].Explanation="There is a valid encounter for this patient, but there are no BMI vital sign exams within 6 months of the measurement period."; continue; } //all three sets of exam codes come from the LOINC table only List<EhrCode> listBMIExamCodes=EhrCodes.GetForValueSetOIDs(new List<string>() { "2.16.840.1.113883.3.464.1003.121.12.1012" },false);//BMI percentile Grouping Value Set List<EhrCode> listHeightExamCodes=EhrCodes.GetForValueSetOIDs(new List<string>() { "2.16.840.1.113883.3.464.1003.121.12.1014" },false);//Height Grouping Value Set List<EhrCode> listWeightExamCodes=EhrCodes.GetForValueSetOIDs(new List<string>() { "2.16.840.1.113883.3.464.1003.121.12.1015" },false);//Weight Grouping Value Set //loop through vitalsign exams looking for valid height, weight, and BMI exam codes (percentile) based on value set OIDs for(int j=0;j<listVitalsignsCur.Count;j++) { bool isBMIExamCodeValid=false; bool isHeightExamCodeValid=false; bool isWeightExamCodeValid=false; for(int k=0;k<listBMIExamCodes.Count;k++) { if(listVitalsignsCur[j].BMIExamCode!=listBMIExamCodes[k].CodeValue) { continue; } if(listVitalsignsCur[j].BMIPercentile==-1) {//-1 if not in age range or if BMI percentile was not calculated correctly continue; } isBMIExamCodeValid=true; break; } for(int k=0;k<listHeightExamCodes.Count;k++) { if(listVitalsignsCur[j].HeightExamCode!=listHeightExamCodes[k].CodeValue) { continue; } isHeightExamCodeValid=true; break; } for(int k=0;k<listWeightExamCodes.Count;k++) { if(listVitalsignsCur[j].WeightExamCode!=listWeightExamCodes[k].CodeValue) { continue; } isWeightExamCodeValid=true; break; } if(isBMIExamCodeValid && isHeightExamCodeValid && isWeightExamCodeValid) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The vitalsign exam on "+listVitalsignsCur[j].DateTaken.ToShortDateString()+" has valid height, weight, and BMI Percentile code."; isCategorized=true; break; } } if(isCategorized) { continue; } alldata.ListEhrPats[i].Explanation="There is a valid encounter for this patient, but no valid vitalsign exam recording height, weight, and BMI in the measurement period."; } break; #endregion #region WeightChild_X_2 and WeightChild_X_3 //All _2 and _3 measures will calculate the Nutrition/Physical Activity counseling interventions the same, already limited by the appropriate age groups case QualityType2014.WeightChild_1_2: case QualityType2014.WeightChild_2_2: case QualityType2014.WeightChild_3_2: case QualityType2014.WeightChild_1_3: case QualityType2014.WeightChild_2_3: case QualityType2014.WeightChild_3_3: //Strategy: alldata.ListEhrPats will be initial patient population //First check for pregnancy diagnosis, alldata.DictPatNumListProblems will hold all of the pregnancy problems that were active during any of the measurement period. //Exclusion if active pregnancy dx exists //alldata.DictPatNumListInterventions will hold all of the nutrition and physical activity counseling interventions that apply //if intervention exists, 'Numerator' string interventionType="physical activity";//used for generating explanation string, 1_3, 2_3, and 3_3 are phys activity string valueSetCur="2.16.840.1.113883.3.464.1003.118.12.1035";//Counseling for Physical Activity Grouping Value Set if(qtype==QualityType2014.WeightChild_1_2 || qtype==QualityType2014.WeightChild_2_2 || qtype==QualityType2014.WeightChild_3_2) { interventionType="nutrition"; valueSetCur="2.16.840.1.113883.3.464.1003.195.12.1003";//Counseling for Nutrition Grouping Value Set } for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; bool isCategorized=false; //first apply pregnancy exclusion List<EhrCqmProblem> listProbsCur=new List<EhrCqmProblem>(); if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { listProbsCur=alldata.DictPatNumListProblems[patNumCur]; } for(int j=0;j<listProbsCur.Count;j++) { if(listProbsCur[j].ValueSetOID=="2.16.840.1.113883.3.526.3.378") {//Pregnancy Grouping Value Set alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had a pregnancy diagnosis that started on "+listProbsCur[j].DateStart.ToShortDateString()+" that is either still active or ended after the start of the measurement period."; isCategorized=true; break; } } if(isCategorized) { continue; } List<EhrCqmIntervention> listIntervenCur=new List<EhrCqmIntervention>(); if(alldata.DictPatNumListInterventions.ContainsKey(patNumCur)) { listIntervenCur=alldata.DictPatNumListInterventions[patNumCur]; } //loop through interventions, if one for the current value set (could be nutrition or physical activity) exists, 'Numerator' for(int j=0;j<listIntervenCur.Count;j++) { if(listIntervenCur[j].ValueSetOID==valueSetCur) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="This patient was counseled for "+interventionType+" on "+listIntervenCur[0].DateEntry.ToShortDateString()+"."; isCategorized=true; break; } } if(isCategorized) { continue; } //eligible encounters exist, but no intervention for nutrition/physical activity counseling, not met alldata.ListEhrPats[i].Explanation="There is a valid encounter for this patient, but no "+interventionType+" counseling intervention in the measurement period."; } break; #endregion #region BloodPressureManage case QualityType2014.BloodPressureManage: //Strategy: alldata.ListEhrPats will be the initial patient population, DictPatNumListEncounters holds all encounters for each patient in ListEhrPats //Denominator: initial patient population //Exclusions: alldata.DictPatNumListProblems holds all diagnoses for the patient that started before the measurement period end date //and either have no stop date or the stop date is after the period start date //DictPatNumListProblems will also hold the hypertension dx's, so only exclude if problem is pregnancy, end stage renal disease, or chronic kidney disease stage 5 //DictPatNumListInterventions holds all interventions that exclude the patient from this measure in the date range, if intervention exists, exclude //DictPatNumListProcs holds all procedures that exclude the patient form this measure in the date range, if proc exists, exclude //DictPatNumListEncounters will have any ESRD Monthly Outpatient Services encounters in the list, if one of these encounters exist, exclude //Numerator: During most recent encounter (that is not an ESRD Monthly... encounter from exclusion ValueSetOID), BPDiastolic<90 mmHg, BPSystolic<140 mmHg for(int i=0;i<alldata.ListEhrPats.Count;i++) { long patNumCur=alldata.ListEhrPats[i].EhrCqmPat.PatNum; bool isCategorized=false; //first apply exclusion diagnoses, problem list will hold hypertension dx's, so have to check for valid exlusion dx List<EhrCqmProblem> listProbsCur=new List<EhrCqmProblem>(); if(alldata.DictPatNumListProblems.ContainsKey(patNumCur)) { listProbsCur=alldata.DictPatNumListProblems[patNumCur]; } for(int j=0;j<listProbsCur.Count;j++) { if(listProbsCur[j].ValueSetOID=="2.16.840.1.113883.3.526.3.378") {//Pregnancy Grouping Value Set alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had a pregnancy diagnosis that started on "+listProbsCur[j].DateStart.ToShortDateString()+" that is either still active or ended after the start of the measurement period."; isCategorized=true; break; } if(listProbsCur[j].ValueSetOID=="2.16.840.1.113883.3.526.3.353") {//End Stage Renal Disease Grouping Value Set alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had an end stage renal disease diagnosis that started on "+listProbsCur[j].DateStart.ToShortDateString()+" that is either still active or ended after the start of the measurement period."; isCategorized=true; break; } if(listProbsCur[j].ValueSetOID=="2.16.840.1.113883.3.526.3.1002") {//Chronic Kidney Disease, Stage 5 Grouping Value Set alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had a chronic kidney disease, stage 5 diagnosis that started on "+listProbsCur[j].DateStart.ToShortDateString()+" that is either still active or ended after the start of the measurement period."; isCategorized=true; break; } } if(isCategorized) { continue; } //next apply exclusion interventions, only valid interventions will be in the list if(alldata.DictPatNumListInterventions.ContainsKey(patNumCur)) { alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had an intervention for dialysis education or other services related to dialysis on "+alldata.DictPatNumListInterventions[patNumCur][0].DateEntry.ToShortDateString()+"."; continue; } //next apply exclusion procedures, only valid procs will be in the list if(alldata.DictPatNumListProcs.ContainsKey(patNumCur)) { alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had a procedure performed for vascular access for dialysis, kidney transplant, or dialysis services on "+alldata.DictPatNumListProcs[patNumCur][0].ProcDate.ToShortDateString()+"."; continue; } //finally apply exclusion encounters, have to loop through encounters and look for any ESRD Monthly Outpatient Services encounters //while looping through encounters, get the most recent encounter that is not an ESRD encounter DateTime dateMostRecentEnc=DateTime.MinValue; List<EhrCqmEncounter> listEncountersCur=alldata.DictPatNumListEncounters[patNumCur]; for(int j=0;j<listEncountersCur.Count;j++) { if(listEncountersCur[j].ValueSetOID=="2.16.840.1.113883.3.464.1003.109.12.1014") {//ESRD Monthly Outpatient Services Grouping Value Set alldata.ListEhrPats[i].IsExclusion=true; alldata.ListEhrPats[i].Explanation="The patient had an end stage renal disease monthly outpatient services encounter on "+alldata.DictPatNumListEncounters[patNumCur][j].DateEncounter.ToShortDateString()+"."; isCategorized=true; continue; } if(listEncountersCur[j].DateEncounter.Date>dateMostRecentEnc.Date) { dateMostRecentEnc=listEncountersCur[j].DateEncounter; } } if(isCategorized) { continue; } //patient not excluded, try to match numerator criteria //using dateMostRecentEnc set above, try to find a vitalsign exam on the same date with recorded Diastolic BP < 90 mmHg and Systolic BP < 140 mmHg List<EhrCqmVitalsign> listVitalsignsCur=new List<EhrCqmVitalsign>(); if(alldata.DictPatNumListVitalsigns.ContainsKey(patNumCur)) { listVitalsignsCur=alldata.DictPatNumListVitalsigns[patNumCur]; } int recentSystolic=0; int recentDiastolic=0; for(int j=0;j<listVitalsignsCur.Count;j++) { if(listVitalsignsCur[j].DateTaken.Date!=dateMostRecentEnc.Date) { continue; } if(j==0) { recentSystolic=listVitalsignsCur[j].BpSystolic; recentDiastolic=listVitalsignsCur[j].BpDiastolic; } if(listVitalsignsCur[j].BpSystolic<recentSystolic) { recentSystolic=listVitalsignsCur[j].BpSystolic; } if(listVitalsignsCur[j].BpDiastolic<recentDiastolic) { recentDiastolic=listVitalsignsCur[j].BpDiastolic; } } if(recentSystolic>0 && recentSystolic<140 && recentDiastolic>0 && recentDiastolic<90) { alldata.ListEhrPats[i].IsNumerator=true; alldata.ListEhrPats[i].Explanation="The patient had a vitalsign exam on "+dateMostRecentEnc.ToShortDateString() +" with systolic blood pressure "+recentSystolic.ToString()+" mmHg and diastolic blood pressure "+recentDiastolic.ToString()+" mmHg."; continue; } //no exceptions, if not in the numerator, patient had a hypertension dx within 6 months of the measurement period start date or any time before the measurement period that did not end before the measurement period start date, was not excluded, and either did not have a vitalsign exam recording BP during their most recent encounter or their most recent encounter with vitalsign exam recorded BP above the allowed range (diastolic<140, systolic<90) alldata.ListEhrPats[i].Explanation="The patient's most recent qualifying encounter on "+dateMostRecentEnc.ToShortDateString(); if(recentSystolic==0 || recentDiastolic==0) {//BP was not recorded during most recent encounter alldata.ListEhrPats[i].Explanation+=" did not have a corresponding vitalsign exam recording systolic and diastolic blood pressure with the same date."; } else { alldata.ListEhrPats[i].Explanation+=" had a corresponding vitalsign exam with systolic blood pressure " +recentSystolic.ToString()+" mmHg and diastolic blood pressure "+recentDiastolic.ToString()+" mmHg."; } } break; #endregion default: throw new ApplicationException("Type not found: "+qtype.ToString()); } }
///<summary>Only called from GetAll2014. Once the EhrCqmData object is created, all of the data relevant to the measure and required by the QRDA category 1 and category 3 reporting is part of the object.</summary> private static QualityMeasure GetEhrCqmData(QualityType2014 qtype,DateTime dateStart,DateTime dateEnd,long provNum) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { return Meth.GetObject<QualityMeasure>(MethodBase.GetCurrentMethod(),qtype,dateStart,dateEnd,provNum); } //these queries only work for mysql string command="SELECT GROUP_CONCAT(provider.ProvNum) FROM provider WHERE provider.EhrKey=" +"(SELECT pv.EhrKey FROM provider pv WHERE pv.ProvNum="+POut.Long(provNum)+")"; string provs=Db.GetScalar(command); QualityMeasure measureCur=new QualityMeasure(); List<string> listOneOfEncOIDs=new List<string>(); List<string> listTwoOfEncOIDs=new List<string>(); List<string> listValueSetOIDs; List<string> listReasonOIDs; List<long> listEhrPatNums; //This adultEncQuery is used by several CQMs //All encounters in the date range by the provider (based on ehrkey, so may be list of providers) for patients over 18 at the start of the measurement period string encounterSelectWhere="SELECT encounter.* FROM encounter " +"INNER JOIN patient ON patient.PatNum=encounter.PatNum " +"WHERE YEAR(patient.Birthdate)>1880 "//valid birthdate +"AND encounter.ProvNum IN("+POut.String(provs)+") " +"AND DATE(encounter.DateEncounter) BETWEEN "+POut.Date(dateStart)+" AND "+POut.Date(dateEnd)+" "; string encounterWhereAdults="AND patient.Birthdate<="+POut.Date(dateStart)+"-INTERVAL 18 YEAR ";//18 or over at start of measurement period string encounterOrder="ORDER BY encounter.PatNum,encounter.DateEncounter DESC"; string adultEncCommand=encounterSelectWhere+encounterWhereAdults+encounterOrder; switch(qtype) { #region MedicationsEntered //this is our only measure that is not patient based, but episode of care based //denominator is all encounters that match the criteria in the date range, not all patients with those encounters case QualityType2014.MedicationsEntered: #region Get Initial Patient Population #region Get Valid Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.600.1.1834");//Medications Encounter Code Set Grouping Value Set //measureCur.ListEncounters will include all encounters that belong to the OneOf and TwoOf lists, so a patient will appear more than once //if they had more than one encounter from those sets in date range measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(adultEncCommand,listOneOfEncOIDs,listTwoOfEncOIDs); //if no patients had valid one of or two or more of the two of encounters, no need to continue calculating measure if(measureCur.DictPatNumListEncounters.Count==0) { break; } #endregion #region Get Patient Data //Denominator is equal to inital patient population for this measure, no exclusions measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats); #endregion #endregion #region Get Current Medications Documented Procedures //Get procedures from the value set that occurred during measurement period listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.462" };//Current Medications Documented SNMD SNOMED-CT Value Set //Only one procedure code in the value set for this measure, SNOMEDCT - 428191000124101 - Documentation of current medications (procedure) measureCur.DictPatNumListMeasureEvents=GetMedDocumentedProcs(listEhrPatNums,listValueSetOIDs,dateStart,dateEnd); #endregion #region Get Medication Procs Not Performed //Get a list of all not performed items from the value set that occurred during the measurement period with valid readson listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.462" };//Current Medications Documented SNMD SNOMED-CT Value Set listReasonOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.1502" };//Medical or Other reason not done SNOMED-CT Value Set measureCur.DictPatNumListNotPerfs=GetNotPerformeds(listEhrPatNums,listValueSetOIDs,listReasonOIDs,dateStart,dateEnd); #endregion break; #endregion #region WeightAdult And WeightOver65 //The two populations are >= 18 and < 64 at the start of the measurement period and >= 65 at the start of the measurement period. //These two populations exclude patients who are 64 at the start of the measurement period apparently on purpose. case QualityType2014.WeightAdult: case QualityType2014.WeightOver65: //Strategy: Get all eligible encounters for patients 65 and over for Over65, >= 18 and < 64 for Adult, at the start of the measurement period //Get Not Performed items for BMI exams with valid reason ("Medical or Other" and "Patient" reasons) //Remove from the encounter list any encounters that have a Not Performed item for a BMI exam on the same day //Get from disease table all palliative care 'procedures' (not likely ever going to be any, but these 'procedure orders' will be stored in the disease table) //Remove from the encounter list any encounters that occurred for patients who have a palliative care order that starts before or during the encounter //Get patient data from the remaining encounters (for reporting), these patients are the initial patient population. //The problem list will contain pregnancies as well as palliative care problems //If the pregnancy starts before or during measurement period and does not end before start of measurement period, the patient is excluded //Numerator - MOST RECENT physical exam that is within 6 months of the specific encounter with: //1.) BMI >= 23 kg/m2 and < 30 kg/m2 for Over65, >= 18.5 and < 25 for Adult, OR //2.) BMI >= 30 kg/m2 for Over65, >= 25 for Adult, with an intervention or medication order for 'Overweight' within 6 months of the specific encounter //3.) BMI < 23 kg/m2 for Over65, < 18.5 for Adult, with an intervention or medication order for 'Underweight' within 6 months of the specific encounter #region Get Initial Patient Population #region Get Raw Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.600.1.1751");//BMI Encounter Code Set Grouping Value Set string encsWhere65="AND patient.Birthdate<"+POut.Date(dateStart)+"-INTERVAL 65 YEAR ";//65 or over at the start of the measurement period string encsWhereLessThan64="AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 64 YEAR ";//< 64 years old at the start of the measurement period string encCommand=""; if(qtype==QualityType2014.WeightOver65) { encCommand=encounterSelectWhere+encsWhere65+encounterOrder; } if(qtype==QualityType2014.WeightAdult) { encCommand=encounterSelectWhere+encounterWhereAdults+encsWhereLessThan64+encounterOrder; } measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(encCommand,listOneOfEncOIDs,listTwoOfEncOIDs); //if no patients had valid one of or two or more of the two of encounters, no need to continue calculating measure if(measureCur.DictPatNumListEncounters.Count==0) { break; } #endregion #region Get Pregnancy And Palliative Care Problems listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.1579" };//Palliative Care Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.600.1.1623");//Pregnancy Dx Grouping Value Set List<long> listRawPatNums=new List<long>(measureCur.DictPatNumListEncounters.Keys); measureCur.DictPatNumListProblems=GetProblems(listRawPatNums,listValueSetOIDs,dateStart,dateEnd); #endregion #region Get Not Performed listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.681" };//BMI LOINC Value LOINC Value Set listReasonOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.1502" };//Medical or Other reason not done SNOMED-CT Value Set listReasonOIDs.Add("2.16.840.1.113883.3.600.1.1503");//Patient Reason Refused SNOMED-CT Value Set measureCur.DictPatNumListNotPerfs=GetNotPerformeds(listRawPatNums,listValueSetOIDs,listReasonOIDs,dateStart,dateEnd); #endregion #region Remove If Palliative Care Order Exists Prior To Encounter Date //if the patient with eligible encounter list has a palliative care order that starts before or during the encounter, remove the encounter //if all encounters end up removed, remove the PatNum key from the dictionary foreach(KeyValuePair<long,List<EhrCqmEncounter>> patNumListEncs in measureCur.DictPatNumListEncounters) {//loop through every patient with an encounter list if(!measureCur.DictPatNumListProblems.ContainsKey(patNumListEncs.Key)) {//if no palliative care problem, move to next patient continue; } List<EhrCqmProblem> listProbsCur=measureCur.DictPatNumListProblems[patNumListEncs.Key]; for(int i=patNumListEncs.Value.Count-1;i>-1;i--) {//loop through encounter list for this patient for(int j=0;j<listProbsCur.Count;j++) {//loop through palliative care problem list for this patient\ if(listProbsCur[j].ValueSetOID!="2.16.840.1.113883.3.600.1.1579") {//if not Palliative Care, move to next problem (problem list for this measure can contain pregnancy dx or palliative care 'procedures') continue; } if(listProbsCur[j].DateStart.Date<=patNumListEncs.Value[i].DateEncounter.Date) {//if palliative care dx starts before or on encounter date patNumListEncs.Value.RemoveAt(i);//remove the encounter break;//break out of problem list loop, move to next encounter } } } } #endregion #region Remove If Not Performed Exists On Encounter Date //if the patient with eligible encounter list also has a not performed on the same day, remove the encounter //this patient will not be in the initial patient population for this encounter but may still be for a different encounter date foreach(KeyValuePair<long,List<EhrCqmEncounter>> patNumListEncs in measureCur.DictPatNumListEncounters) {//loop through every patient with an encounter list if(!measureCur.DictPatNumListNotPerfs.ContainsKey(patNumListEncs.Key)) {//if no not performed items, move to next patient continue; } List<EhrCqmNotPerf> listNotPerfsCur=measureCur.DictPatNumListNotPerfs[patNumListEncs.Key];//the not performed items are guaranteed to have valid reasons for(int i=patNumListEncs.Value.Count-1;i>-1;i--) {//loop through encounters for this patient for(int j=0;j<listNotPerfsCur.Count;j++) {//loop through not performed items for this patient if(listNotPerfsCur[j].DateEntry.Date==patNumListEncs.Value[i].DateEncounter.Date) {//compare encounter date to not perfomed date patNumListEncs.Value.RemoveAt(i);//remove encounter if not performed item on same date break;//break out of not performed loop to move to next encounter } } } } //if all encounters for this patient have been removed, remove the PatNum key so the patient is not in the denominator List<long> allKeys=new List<long>(measureCur.DictPatNumListEncounters.Keys); for(int i=0;i<allKeys.Count;i++) { if(measureCur.DictPatNumListEncounters[allKeys[i]].Count==0) { measureCur.DictPatNumListEncounters.Remove(allKeys[i]); } } //no patients with encounters left, no need to go on if(measureCur.DictPatNumListEncounters.Count==0) { break; } #endregion #region Get Patient Data //encounters are now eligible and only if no palliative care order before or on encounter date and no eligible not perforemed item on same date measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats); #endregion #endregion #region Get Vital Sign Exams //get all vitalsign exams with valid height and weight in the date range, we have to subtract 6 months from dateStart, since encounter must be in measurement period, but exam can be before measurement period as long as it is within 6 months of the encounter //each exam will have a calculated BMI, which is (weight*703)/(height*height) measureCur.DictPatNumListVitalsigns=GetVitalsignsForBMI(listEhrPatNums,dateStart.AddMonths(-6),dateEnd); #endregion #region Get Interventions //Get all interventions for eligible value sets that occurred within 6 months of the start of the measurement period up to the end of the measurement period command="SELECT * FROM intervention " +"WHERE DATE(DateEntry) BETWEEN "+POut.Date(dateStart)+"-INTERVAL 6 MONTH AND "+POut.Date(dateEnd)+" "; if(listEhrPatNums!=null && listEhrPatNums.Count>0) { command+="AND intervention.PatNum IN("+string.Join(",",listEhrPatNums)+") "; } command+="ORDER BY PatNum,DateEntry DESC"; listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.1525" };//Above Normal Follow-up Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.600.1.1528");//Below Normal Follow up Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.600.1.1527");//Referrals where weight assessment may occur Grouping Value Set measureCur.DictPatNumListInterventions=GetInterventions(command,listValueSetOIDs); #endregion #region Get MedicationPats //Get all medicationpats (check for start date and instructions when calculating to make sure they are 'Orders') that started within 6 months of start date listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.600.1.1498" };//Above Normal Medications RxNorm Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.600.1.1499");//Below Normal Medications RxNorm Value Set measureCur.DictPatNumListMedPats=GetMedPats(listEhrPatNums,listValueSetOIDs,dateStart.AddMonths(-6),dateEnd); #endregion break; #endregion #region CariesPrevent age >= 0 and < 20 //These four will be the same encounter/procedure codes, just 4 different age groups: 0-19, 0-5, 6-12, and 13-19 case QualityType2014.CariesPrevent: case QualityType2014.CariesPrevent_1: case QualityType2014.CariesPrevent_2: case QualityType2014.CariesPrevent_3: //Strategy: Get all encounters in date range from eligible value sets for patients in age range //No exclusions, initial patient population is denominator //Get Flouride varnish application procedures that occurred during the measurement period //If encounter and procedure, 'Numerator' //No exceptions #region Get Initial Patient Population #region Get All Eligible Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1001");//Office Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.125.12.1003");//Clinical Oral Evaluation Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1022");//Preventive Care- Initial Office Visit, 0 to 17 Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1023");//Preventive Care Services-Initial Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1024");//Preventive Care - Established Office Visit, 0 to 17 Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1025");//Preventive Care Services - Established Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1048");//Face-to-Face Interaction Grouping Value Set string child0To19Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+" "//age >= 0 at start of measurement period +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 20 YEAR "//age < 20 at start of measurement period +encounterOrder; string child0To5Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+" "//age >= 0 at start of measurement period +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 6 YEAR "//age <= 5 at start of measurement period +encounterOrder; string child6To12Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+"-INTERVAL 6 YEAR "//age >= 6 at start of measurement period +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 13 YEAR "//age <= 12 at start of measurement period +encounterOrder; string child13To19Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+"-INTERVAL 13 YEAR "//age >= 13 at start of measurement period +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 20 YEAR "//age < 20 at start of measurement period +encounterOrder; if(qtype==QualityType2014.CariesPrevent) { measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child0To19Command,listOneOfEncOIDs,listTwoOfEncOIDs); } else if(qtype==QualityType2014.CariesPrevent_1) { measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child0To5Command,listOneOfEncOIDs,listTwoOfEncOIDs); } else if(qtype==QualityType2014.CariesPrevent_2) { measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child6To12Command,listOneOfEncOIDs,listTwoOfEncOIDs); } else if(qtype==QualityType2014.CariesPrevent_3) { measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child13To19Command,listOneOfEncOIDs,listTwoOfEncOIDs); } //if no eligilble encounters, no need to go on if(measureCur.DictPatNumListEncounters.Count==0) { break; } #endregion #region Get Patient Data From Encounters measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats); #endregion #endregion #region Get Flouride Varnish Application Procedures listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.125.12.1002" };//Fluoride Varnish Application for Children Grouping Value Set measureCur.DictPatNumListProcs=GetProcs(listEhrPatNums,listValueSetOIDs,dateStart,dateEnd); #endregion break; #endregion #region ChildCaries case QualityType2014.ChildCaries: //Strategy: Get all encounters in date range from eligible value sets for patients in age range //No exclusions, initial patient population is denominator //Get Dental Caries diagnoses that were active during any of the measurement period (started before or during period and did NOT end before the start of period) //No exceptions #region Get Initial Patient Population #region Get All Eligible Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1001");//Office Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.125.12.1003");//Clinical Oral Evaluation Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1022");//Preventive Care- Initial Office Visit, 0 to 17 Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1023");//Preventive Care Services-Initial Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1024");//Preventive Care - Established Office Visit, 0 to 17 Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1025");//Preventive Care Services - Established Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1048");//Face-to-Face Interaction Grouping Value Set child0To19Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+" "//age >= 0 at start of measurement period (born before or on start date) +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 20 YEAR "//age < 20 at start of measurement period +encounterOrder; measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child0To19Command,listOneOfEncOIDs,listTwoOfEncOIDs); //if no eligible encounters, no need to go on if(measureCur.DictPatNumListEncounters.Count==0) { break; } #endregion #region Get Patient Data From Encounters measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats); #endregion #endregion #region Get Dental Caries Diagnoses listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.125.12.1004" };//Dental Caries Grouping Value Set measureCur.DictPatNumListProblems=GetProblems(listEhrPatNums,listValueSetOIDs,dateStart,dateEnd); #endregion break; #endregion #region Pneumonia case QualityType2014.Pneumonia: //Strategy: Get encounters from eligible value sets for patients >= 65 years old before the start of the measurement period //Those patients will be initial patient population and denominator //No exclusions //Get vaccinepats with eligible code, only one code, CVX - 33 - pneumococcal polysaccharide vaccine, 23 valent //Get procs with eligible code, SNOMEDCT - 12866006 - Pneumococcal vaccination (procedure) and SNOMEDCT - 394678003 - Booster pneumococcal vaccination (procedure) //Get problems with eligible code, only one code, SNOMEDCT - 310578008 - Pneumococcal vaccination given (finding) #region Get Initial Patient Population #region Get Raw Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1240");//Annual Wellness Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1001");//Office Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1016");//Home Healthcare Services Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1023");//Preventive Care Services-Initial Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1025");//Preventive Care Services - Established Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1048");//Face-to-Face Interaction Grouping Value Set encCommand=encounterSelectWhere +"AND patient.Birthdate<"+POut.Date(dateStart)+"-INTERVAL 65 YEAR "//65 or over at start of measurement period +encounterOrder; measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(encCommand,listOneOfEncOIDs,listTwoOfEncOIDs); //if no eligible encounters, no need to go on if(measureCur.DictPatNumListEncounters.Count==0) { break; } #endregion #region Get Patient Data measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats);//for restricting the following list of procs, problems, and vaccinepats #endregion #endregion #region Get Vaccinepats listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.110.12.1027" };//Pneumococcal Vaccine Grouping Value Set measureCur.DictPatNumListMedPats=GetVaccines(listEhrPatNums,listValueSetOIDs,DateTime.MinValue,dateEnd,true); #endregion #region Get Procs //Get procs that are Pneumococcal vaccine administered SNOMEDCT - 12866006 listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.110.12.1034" };//Pneumococcal Vaccine Administered Grouping Value Set measureCur.DictPatNumListProcs=GetProcs(listEhrPatNums,listValueSetOIDs,DateTime.MinValue,dateEnd); #endregion #region Get Problems //Get problems that are history of pheumococcal vaccine recoreded, one code allowed, SNOMEDCT - 310578008 listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.110.12.1028" };//History of Pneumococcal Vaccine Grouping Value Set measureCur.DictPatNumListProblems=GetProblems(listEhrPatNums,listValueSetOIDs,DateTime.MinValue,dateEnd); #endregion break; #endregion #region TobaccoCessation case QualityType2014.TobaccoCessation: #region Get Valid Encounters //add one of encounter OIDs to list listOneOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1240");//Annual Wellness Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1023");//Preventive Care Services-Initial Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1025");//Preventive Care Services - Established Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1026");//Preventive Care Services-Individual Counseling Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1027");//Preventive Care Services - Group Counseling Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1030");//Preventive Care Services - Other Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1048");//Face-to-Face Interaction Grouping Value Set //add two of encounter OIDs to list listTwoOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1001");//Office Visit Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1011");//Occupational Therapy Evaluation Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1020");//Health & Behavioral Assessment - Individual Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1141");//Psychoanalysis Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1245");//Health and Behavioral Assessment - Initial Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1285");//Ophthalmological Services Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1492");//Psych Visit - Diagnostic Evaluation Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1496");//Psych Visit - Psychotherapy Grouping Value Set //measureCur.ListEncounters will include all encounters that belong to the OneOf and TwoOf lists, so a patient will appear more than once //if they had more than one encounter from those sets in date range measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(adultEncCommand,listOneOfEncOIDs,listTwoOfEncOIDs); //if no eligible encounters, no need to go on if(measureCur.DictPatNumListEncounters.Count==0) { break; } #endregion #region Get Initial Patient Population //Denominator is equal to initial patient population for this measure //the Inital Patient Population will be unique patients in ListEncounters, loop through and count unique patients measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats); #endregion #region Get Tobacco Assessments //Get a list of all tobacco assessment events that happened within 24 of end of measurement period measureCur.DictPatNumListMeasureEvents=GetTobaccoAssessmentEvents(listEhrPatNums,dateEnd); #endregion #region Get Tobacco Cessation Interventions //Get all interventions within 24 months of end of measurement period command="SELECT * FROM intervention " +"WHERE DATE(DateEntry) BETWEEN "+POut.Date(dateEnd)+"-INTERVAL 24 MONTH AND "+POut.Date(dateEnd)+" "; if(listEhrPatNums!=null && listEhrPatNums.Count>0) { command+="AND intervention.PatNum IN("+string.Join(",",listEhrPatNums)+") "; } command+="ORDER BY PatNum,DateEntry DESC"; listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.509" };//Tobacco Use Cessation Counseling Grouping Value Set measureCur.DictPatNumListInterventions=GetInterventions(command,listValueSetOIDs); #endregion #region Get Tobacco Cessation Meds //Get a list of all tobacco cessation meds active/ordered within 24 months of end of measurement period listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1190" };////Tobacco Use Cessation Pharmacotherapy Grouping Value Set measureCur.DictPatNumListMedPats=GetMedPats(listEhrPatNums,listValueSetOIDs,dateEnd.AddMonths(-24),dateEnd); #endregion #region Get Tobacco Screenings Not Performed //Get a list of all tobacco assessment not performed items that happened in the measurement period that belong to the value set //that also have a valid medical reason attached from the above value set listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1278" };//Tobacco Use Screening Grouping Value Set listReasonOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1007" };//Medical Reason Grouping Value Set measureCur.DictPatNumListNotPerfs=GetNotPerformeds(listEhrPatNums,listValueSetOIDs,listReasonOIDs,dateStart,dateEnd); #endregion #region Get Limited Life Expectancy Probs listValueSetOIDs=new List<string>() {"2.16.840.1.113883.3.526.3.1259"};//Limited Life Expectancy Grouping Value Set //Get a list of all limited life expectancy diagnoses in the measurement period that belong to the above value set measureCur.DictPatNumListProblems=GetProblems(listEhrPatNums,listValueSetOIDs,dateStart,dateEnd); #endregion break; #endregion #region Influenza case QualityType2014.Influenza: //Strategy: Get encounters from one of and two of lists for patients >= 6 months before start of measurement period //Denominator: Those in the list of encounters who also had an encounter <= 92 days BEFORE the start of the measurement period from three code sets //OR an encounter from the same three code sets <= 91 days AFTER the start of the measurement period //No exclusions //Numerator: Get all flu vaccine procs and flu vaccine medications (vaccinepats, these will include the communication from patient to provider of previous receipt of vaccine) //that happened during the encounter <= 92 days before start of period or <= 91 days after start of period //Exceptions: 1. communication from patient to prov declining vaccine (vaccinepats with CompletionStatus=1 (refused)) //2. procedure or medication NotPerformed for medical, patient, or system reason //Both 1 and 2 have to be during the encounter in the <= 92 before start or <= 91 days after start of period date range //OR active diagnosis of allergy to eggs, allergy to flu vaccine, or intolerance to flu vaccine //OR medication allergy or intolerance to flu vaccine //OR procedure intolerance to vaccine //Those have to start before or during the encounter in the date range. #region Get Initial Patient Population #region Get Raw Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1240");//Annual Wellness Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1012");//Nursing Facility Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1013");//Discharge Services - Nursing Facility Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1022");//Preventive Care- Initial Office Visit, 0 to 17 Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1023");//Preventive Care Services-Initial Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1024");//Preventive Care - Established Office Visit, 0 to 17 Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1025");//Preventive Care Services - Established Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1026");//Preventive Care Services-Individual Counseling Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1027");//Preventive Care Services - Group Counseling Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1030");//Preventive Care Services - Other Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1012");//Patient Provider Interaction Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1001");//Office Visit Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1008");//Outpatient Consultation Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1014");//Care Services in Long-Term Residential Facility Grouping Value Set listTwoOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1016");//Home Healthcare Services Grouping Value Set encCommand=encounterSelectWhere +"AND patient.Birthdate<"+POut.Date(dateStart)+"-INTERVAL 6 MONTH "//>= 6 months at start of measurement period +encounterOrder; measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(encCommand,listOneOfEncOIDs,listTwoOfEncOIDs); #endregion #region Get Patients Who Had Initial Population Proc listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1083" };//Hemodialysis Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.1084");//Peritoneal Dialysis Grouping Value Set measureCur.DictPatNumListProcs=GetProcs(null,listValueSetOIDs,dateStart,dateEnd); #endregion #region Get Patient Data measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters,measureCur.DictPatNumListProcs); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats);//for restricting the following list of procs, problems, and vaccinepats #endregion #endregion #region Apply Additional Denominator Requirements //These are additional requirements for the patient to be in the denominator. //The patient must have one of the eligible encounters/procedures <= 92 days before the start of the period or <= 91 days after the start of the period to be in denominator. Dictionary<long,List<EhrCqmEncounter>> dictPatNumListDenomEncs; if(listEhrPatNums!=null && listEhrPatNums.Count==0) { dictPatNumListDenomEncs=new Dictionary<long,List<EhrCqmEncounter>>(); } else { listOneOfEncOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1252" };//Encounter-Influenza Grouping Value Set listTwoOfEncOIDs=new List<string>(); encCommand="SELECT encounter.* FROM encounter " +"INNER JOIN patient ON patient.PatNum=encounter.PatNum " +"WHERE YEAR(patient.Birthdate)>1880 "//valid birthdate +"AND encounter.ProvNum IN("+POut.String(provs)+") " +"AND DATE(encounter.DateEncounter) BETWEEN "+POut.Date(dateStart.AddDays(-92))+" AND "+POut.Date(dateStart.AddDays(91))+" "; if(listEhrPatNums!=null && listEhrPatNums.Count>0) { command+="AND encounter.PatNum IN("+string.Join(",",listEhrPatNums)+") "; } command+="ORDER BY encounter.PatNum,encounter.DateEncounter DESC"; dictPatNumListDenomEncs=GetEncountersWithOneOfAndTwoOfOIDs(encCommand,listOneOfEncOIDs,listTwoOfEncOIDs); } listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1083" };//Hemodialysis Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.1084");//Peritoneal Dialysis Grouping Value Set Dictionary<long,List<EhrCqmProc>> dictPatNumListDenomProcs=GetProcs(listEhrPatNums,listValueSetOIDs,dateStart.AddDays(-92),dateStart.AddDays(91)); //for each patient in initial pat population ListEhrPats, make sure they have an encounter in dictPatNumListDenomEncs or a procedure in dictPatNumListDenomProcs //those lists will have the eligible encounters or procedures in the <= 92 days starts before start of period and <= 91 days starts after start of period //i.e. the encounter or procedure took place between October 1st of year prior to measurement period and March 31st of year of measurement period //this date range is their definition of the "influenza season" for(int i=0;i<measureCur.ListEhrPats.Count;i++) { long patNumCur=measureCur.ListEhrPats[i].EhrCqmPat.PatNum; bool isDenom=false; if(dictPatNumListDenomEncs.ContainsKey(patNumCur)) { isDenom=true; if(measureCur.DictPatNumListEncounters.ContainsKey(patNumCur)) { measureCur.DictPatNumListEncounters[patNumCur].AddRange(dictPatNumListDenomEncs[patNumCur]); } else {//no encounters from initial patient population, must be in ipp from procedure, add new list to include these encounters measureCur.DictPatNumListEncounters.Add(patNumCur,dictPatNumListDenomEncs[patNumCur]); } } if(dictPatNumListDenomProcs.ContainsKey(patNumCur)) { isDenom=true; if(measureCur.DictPatNumListProcs.ContainsKey(patNumCur)) { measureCur.DictPatNumListProcs[patNumCur].AddRange(dictPatNumListDenomProcs[patNumCur]); } else { measureCur.DictPatNumListProcs.Add(patNumCur,dictPatNumListDenomProcs[patNumCur]); } } if(!isDenom) { //this is the only place the bool IsDenominator is ever set to false measureCur.ListEhrPats[i].IsDenominator=false; } } #endregion #region Get Numerator Data #region Get Influenza Vaccination Procedures //These will actually be in the procedurelog table, the user will have to manually add the correct code to the proccode table and then chart the procedure //Codes are CPT or SNOMEDCT listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.402" };//Influenza Vaccination Grouping Value Set Dictionary<long,List<EhrCqmProc>> dictPatNumListNumeProcs=GetProcs(listEhrPatNums,listValueSetOIDs,dateStart.AddDays(-92),dateStart.AddDays(91)); for(int i=0;i<measureCur.ListEhrPats.Count;i++) { long patNumCur=measureCur.ListEhrPats[i].EhrCqmPat.PatNum; if(dictPatNumListNumeProcs.ContainsKey(patNumCur)) { if(measureCur.DictPatNumListProcs.ContainsKey(patNumCur)) { measureCur.DictPatNumListProcs[patNumCur].AddRange(dictPatNumListNumeProcs[patNumCur]); } else { measureCur.DictPatNumListProcs.Add(patNumCur,dictPatNumListNumeProcs[patNumCur]); } } } #endregion #region Get Influenza Vaccination Medications //These will be the CVX codes that will be in the vaccinepat table listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1254" };//Influenza Vaccine Grouping Value Set measureCur.DictPatNumListMedPats=GetVaccines(listEhrPatNums,listValueSetOIDs,DateTime.MinValue,dateStart.AddDays(91),false);//false means could be vaccines given or not given //Not given vaccines will be used in denominator exceptions and assumed medication intolerance or allergy. //Vaccines given will have to have occurred during "Occurrence A of..." but Not Given means intolerance or allergy and can be any time before or during "Occurrence A of..." #endregion #region Get Problems For Numerator And Exceptions //These will be in the patient's 'Problem' list, like the Pneumonia vaccine communication of previous receipt, 4 possible SNOMEDCT codes listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1185" };//Previous Receipt of Influenza Vaccine Grouping Value Set //this code is only one eligible SNOMEDCT code used for exceptions, but we will add it to the list here listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.1255");//Influenza Vaccination Declined Grouping Value Set measureCur.DictPatNumListProblems=GetProblems(listEhrPatNums,listValueSetOIDs,dateStart.AddDays(-92),dateStart.AddDays(91)); //these value sets are for exception criteria and are all SNOMEDCT codes, we will add to the list here listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1253" };//Diagnosis, Active: Allergy to eggs Grouping Value Set, all SNOMEDCT codes listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.1256");//Diagnosis, Active: Allergy to Influenza Vaccine Grouping Value Set, SNOMEDCT codes listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.1257");//Diagnosis, Active: Intolerance to Influenza Vaccine Grouping Value Set, SNOMEDCT codes Dictionary<long,List<EhrCqmProblem>> dictPatNumListProblems=GetProblems(listEhrPatNums,listValueSetOIDs,DateTime.MinValue,dateStart.AddDays(91)); //The previous receipt of vaccine and declined vaccine exception must occur during "Occurrence A of..." //but the allergy and intolerance diagnoses can be any time before or during "Occurrence A of..." //Add allergy and intolerance problems to the previous receipt and declined vaccine problem list of measureCur List<long> listPatNums=new List<long>(dictPatNumListProblems.Keys); for(int i=0;i<listPatNums.Count;i++) { if(measureCur.DictPatNumListProblems.ContainsKey(listPatNums[i])) { measureCur.DictPatNumListProblems[listPatNums[i]].AddRange(dictPatNumListProblems[listPatNums[i]]); } else { measureCur.DictPatNumListProblems.Add(listPatNums[i],dictPatNumListProblems[listPatNums[i]]); } } #endregion #endregion #region Get Exceptions //All other exception items, besides the not performed items below, have been retrieved in the regions above #region Get Not Performed Items //These will also have to have taken place during the "Occurrence A of" encounter/procedure so limited to Oct 1 of previous year to March 31 of period year listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1254" };//Medication, Administered: Influenza Vaccine Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.402");//Procedure, Performed: Influenza Vaccination Grouping Value Set listReasonOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.1007" };//Medical Reason Grouping Value Set listReasonOIDs.Add("2.16.840.1.113883.3.526.3.1008");//Patient Reason Grouping Value Set listReasonOIDs.Add("2.16.840.1.113883.3.526.3.1009");//System Reason Grouping Value Set measureCur.DictPatNumListNotPerfs=GetNotPerformeds(listEhrPatNums,listValueSetOIDs,listReasonOIDs,dateStart.AddDays(-92),dateStart.AddDays(91)); #endregion #endregion break; #endregion #region WeightChild_X_1 Height, Weight, and BMI Exams case QualityType2014.WeightChild_1_1: case QualityType2014.WeightChild_2_1: case QualityType2014.WeightChild_3_1: //For each group of three measures, the first of the group will get all encounters, patient data, pregnancy diagnoses, vitalsign exams and interventions for that age group. //All three will use the same patient data. Example 1_1 will get all data used by 1_1, 1_2, and 1_3. //Strategy for the weight child measures: Get eligible encounters for patients in age range that occurred during the measurement period //These patients are the initial patient population //Exclusion: Pregnant during any of the measurement period //Numerator 1: There is a vital sign exam with height, weight, and BMI percentile recorded during the measurement period //Numerator 2: There is an intervention for nutrition counseling during the measurement period //Numerator 3: There is an intervention for physical activity during the measurement period #region Get Initial Patient Population #region Get All Eligible Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1048");//Face-to-Face Interaction Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1016");//Home Healthcare Services Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1001");//Office Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1024");//Preventive Care - Established Office Visit, 0 to 17 Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1027");//Preventive Care Services - Group Counseling Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1026");//Preventive Care Services-Individual Counseling Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1022");//Preventive Care- Initial Office Visit, 0 to 17 Grouping Value Set string child3To16Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+"-INTERVAL 3 YEAR "//age >= 3 at start of measurement period +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 17 YEAR "//age < 17 at start of measurement period +encounterOrder; string child3To11Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+"-INTERVAL 3 YEAR "//age >= 3 at start of measurement period +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 12 YEAR "//age <= 11 at start of measurement period +encounterOrder; string child12To16Command=encounterSelectWhere +"AND patient.Birthdate<="+POut.Date(dateStart)+"-INTERVAL 12 YEAR "//age >= 12 at start of measurement period +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 17 YEAR "//age < 17 at start of measurement period +encounterOrder; if(qtype==QualityType2014.WeightChild_1_1) { measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child3To16Command,listOneOfEncOIDs,listTwoOfEncOIDs); } else if(qtype==QualityType2014.WeightChild_2_1) { measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child3To11Command,listOneOfEncOIDs,listTwoOfEncOIDs); } else if(qtype==QualityType2014.WeightChild_3_1) { measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(child12To16Command,listOneOfEncOIDs,listTwoOfEncOIDs); } #endregion #region Get Patient Data From Encounters measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats); #endregion #endregion #region Get Pregnancy Diagnoses listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.526.3.378" };//Pregnancy Grouping Value Set measureCur.DictPatNumListProblems=GetProblems(listEhrPatNums,listValueSetOIDs,dateStart,dateEnd); #endregion #region Get Vitalsign Exams measureCur.DictPatNumListVitalsigns=GetVitalsignsForBMI(listEhrPatNums,dateStart,dateEnd); #endregion #region Get Interventions if(listEhrPatNums!=null && listEhrPatNums.Count==0) { measureCur.DictPatNumListInterventions=new Dictionary<long,List<EhrCqmIntervention>>(); } else { //DictPatNumListInterventions will hold the phys activity and Nutrition counseling interventions command="SELECT * FROM intervention " +"WHERE DATE(DateEntry) BETWEEN "+POut.Date(dateStart)+" AND "+POut.Date(dateEnd)+" "; if(listEhrPatNums!=null && listEhrPatNums.Count>0) { command+="AND intervention.PatNum IN("+string.Join(",",listEhrPatNums)+") "; } command+="ORDER BY PatNum,DateEntry DESC"; listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.195.12.1003" };//Counseling for Nutrition Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.464.1003.118.12.1035");//Counseling for Physical Activity Grouping Value Set measureCur.DictPatNumListInterventions=GetInterventions(command,listValueSetOIDs); } #endregion #region Make Copies Of MeasureCur Data For WeightChild _2 and _3 if(qtype==QualityType2014.WeightChild_1_1) { _measureWeightAssessAll=measureCur.Copy(); } else if(qtype==QualityType2014.WeightChild_2_1) { _measureWeightAssess3To11=measureCur.Copy(); } else if(qtype==QualityType2014.WeightChild_3_1) { _measureWeightAssess12To16=measureCur.Copy(); } #endregion break; #endregion #region WeightChild_X_2 and WeightChild_X_3 Nutrition and Physical Activity Counseling case QualityType2014.WeightChild_1_2: case QualityType2014.WeightChild_2_2: case QualityType2014.WeightChild_3_2: case QualityType2014.WeightChild_1_3: case QualityType2014.WeightChild_2_3: case QualityType2014.WeightChild_3_3: #region Get All Data From Copy if(qtype==QualityType2014.WeightChild_1_2 || qtype==QualityType2014.WeightChild_1_3) { measureCur=_measureWeightAssessAll.Copy(); } else if(qtype==QualityType2014.WeightChild_2_2 || qtype==QualityType2014.WeightChild_2_3) { measureCur=_measureWeightAssess3To11.Copy(); } else if(qtype==QualityType2014.WeightChild_3_2 || qtype==QualityType2014.WeightChild_3_3) { measureCur=_measureWeightAssess12To16.Copy(); } #endregion break; #endregion #region BloodPressureManage case QualityType2014.BloodPressureManage: #region Get Initial Patient Population #region Get Raw Encounters listOneOfEncOIDs.Add("2.16.840.1.113883.3.526.3.1240");//Annual Wellness Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1001");//Office Visit Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1008");//Outpatient Consultation Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1016");//Home Healthcare Services Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1023");//Preventive Care Services-Initial Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1025");//Preventive Care Services - Established Office Visit, 18 and Up Grouping Value Set listOneOfEncOIDs.Add("2.16.840.1.113883.3.464.1003.101.12.1048");//Face-to-Face Interaction Grouping Value Set string encsWhere18To85=encounterSelectWhere +"AND patient.Birthdate>"+POut.Date(dateStart)+"-INTERVAL 85 YEAR "//< 85 years old at the start of the measurement period +encounterOrder; measureCur.DictPatNumListEncounters=GetEncountersWithOneOfAndTwoOfOIDs(encsWhere18To85,listOneOfEncOIDs,listTwoOfEncOIDs); #endregion #region Get Essential Hypertension Problems listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.104.12.1011" };//Essential Hypertension Grouping Value Set //hypertension problem must start within 6 months of start of measurement period //if measurement period end date is less than 6 months after the start date, //problem start date is limited by end date not 6 months after start date as that would start after the end of the measurement period DateTime probDateEnd=dateEnd; if(dateStart.AddMonths(6)<dateEnd) { probDateEnd=dateStart.AddMonths(6); } Dictionary<long,List<EhrCqmProblem>> dictPatNumListHypertension=GetProblems(null,listValueSetOIDs,dateStart,probDateEnd); #endregion #region Remove If No Hypertension Diagnosis //if the patient with eligible encounter list has not been diagnosed with hypertension within 6 months of the start of the measurement period, remove from IPP //(diagnosis <= 6 months starts after dateStart) OR (diagnosis starts before dateStart AND NOT diagnosis ends before dateStart) List<long> allEncKeys=new List<long>(measureCur.DictPatNumListEncounters.Keys); for(int i=0;i<allEncKeys.Count;i++) { if(!dictPatNumListHypertension.ContainsKey(allEncKeys[i])) { measureCur.DictPatNumListEncounters.Remove(allEncKeys[i]); } } #endregion #region Get Patient Data //encounters are now eligible and only if hypertension diagnosis within 6 months of start of measurement period (or before endDate if sooner than 6 months after start date) measureCur.ListEhrPats=GetEhrPatsFromEncsOrProcs(measureCur.DictPatNumListEncounters); listEhrPatNums=GetListPatNums(measureCur.ListEhrPats); #endregion #endregion #region Get Exclusion Items #region Get Exclusion Diagnoses And Hypertension Diagnoses //ListEhrPats is now initial patient population, get hyptertension, pregnancy, end stage renal disease, and chronic kidney disease diagnoses //This time the hypertension diagnoses will be for the entire measurement period, not just within the 6 months after the start date. listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.104.12.1011" };//Essential Hypertension Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.378");//Pregnancy Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.353");//End Stage Renal Disease Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.526.3.1002");//Chronic Kidney Disease, Stage 5 Grouping Value Set measureCur.DictPatNumListProblems=GetProblems(listEhrPatNums,listValueSetOIDs,dateStart,dateEnd); #endregion #region Get Interventions For Exclusion if(listEhrPatNums!=null && listEhrPatNums.Count==0) { measureCur.DictPatNumListInterventions=new Dictionary<long,List<EhrCqmIntervention>>(); } else { listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.109.12.1015" };//Other Services Related to Dialysis Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.464.1003.109.12.1016");//Dialysis Education Grouping Value Set //Get all interventions for eligible value sets that occurred before or during the measurement period command="SELECT * FROM intervention " +"WHERE DATE(DateEntry)<="+POut.Date(dateEnd)+" "; if(listEhrPatNums!=null && listEhrPatNums.Count>0) { command+="AND intervention.PatNum IN("+string.Join(",",listEhrPatNums)+") "; } command+="ORDER BY PatNum,DateEntry DESC"; measureCur.DictPatNumListInterventions=GetInterventions(command,listValueSetOIDs); } #endregion #region Get Procedures For Exclusion listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.109.12.1011" };//Vascular Access for Dialysis Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.464.1003.109.12.1012");//Kidney Transplant Grouping Value Set listValueSetOIDs.Add("2.16.840.1.113883.3.464.1003.109.12.1013");//Dialysis Services Grouping Value Set measureCur.DictPatNumListProcs=GetProcs(listEhrPatNums,listValueSetOIDs,DateTime.MinValue,dateEnd); #endregion #region Get Encounters For Exclusion //Get encounters that occurred before or during the measurement period that belong to the value set and add them to DictPatNumListEncounters //these encounters will be only for those patients already in the IPP, and will simply be added to the list of encounters for that patient //they will be used for exclusion in the Classify function, if one exists the patient is in the IPP and denominator but excluded from the measure listValueSetOIDs=new List<string>() { "2.16.840.1.113883.3.464.1003.109.12.1014" };//ESRD Monthly Outpatient Services Grouping Value Set command="SELECT encounter.* FROM encounter " +"INNER JOIN patient ON patient.PatNum=encounter.PatNum " +"WHERE YEAR(patient.Birthdate)>1880 "//valid birthdate +"AND encounter.ProvNum IN("+POut.String(provs)+") " +"AND DATE(encounter.DateEncounter)<="+POut.Date(dateEnd)+" "; if(listEhrPatNums!=null && listEhrPatNums.Count>0) { command+="AND encounter.PatNum IN("+string.Join(",",listEhrPatNums)+") "; } Dictionary<long,List<EhrCqmEncounter>> dictPatNumListEncs=GetEncountersWithOneOfAndTwoOfOIDs(command,listValueSetOIDs,listTwoOfEncOIDs); //add to the list of encounters for all patients in the IPP any end stage renal disease encounters allKeys=new List<long>(dictPatNumListEncs.Keys); for(int i=0;i<allKeys.Count;i++) { if(measureCur.DictPatNumListEncounters.ContainsKey(allKeys[i])) { measureCur.DictPatNumListEncounters[allKeys[i]].AddRange(dictPatNumListEncs[allKeys[i]]); } } #endregion #endregion #region Get Vitalsign Exams For BP measureCur.DictPatNumListVitalsigns=GetVitalsignsForBP(listEhrPatNums,dateStart,dateEnd); #endregion break; #endregion default: throw new ApplicationException("Type not found: "+qtype.ToString()); } //this will mark the patients in ListEhrPats as Numerator, Exclusion, or Exception, with explanation ClassifyPatients(measureCur,qtype,dateStart,dateEnd); return measureCur; }