use of org.hl7.fhir.r4.model.ListResource.ListEntryComponent in project quality-measure-and-cohort-service by Alvearie.
the class MeasureEvaluation method evaluate.
protected MeasureReport evaluate(Measure measure, Context context, List<Patient> patients, MeasureReport.MeasureReportType type, boolean isSingle, boolean includeEvaluatedResources) {
MeasureReportBuilder reportBuilder = new MeasureReportBuilder();
reportBuilder.buildStatus("complete");
reportBuilder.buildType(type);
reportBuilder.buildMeasureReference(measure.getIdElement().getResourceType() + "/" + measure.getIdElement().getIdPart());
if (type == MeasureReport.MeasureReportType.INDIVIDUAL && CollectionUtils.isNotEmpty(patients)) {
IdType patientId = patients.get(0).getIdElement();
reportBuilder.buildPatientReference(patientId.getResourceType() + "/" + patientId.getIdPart());
}
reportBuilder.buildPeriod(measurementPeriod);
MeasureReport report = reportBuilder.build();
Map<String, Resource> resources = new HashMap<>();
Map<String, Set<String>> codeToResourceMap = new HashMap<>();
MeasureScoring measureScoring = MeasureScoring.fromCode(measure.getScoring().getCodingFirstRep().getCode());
if (measureScoring == null) {
throw new RuntimeException("Measure scoring is required in order to calculate.");
}
List<Measure.MeasureSupplementalDataComponent> sde = measure.getSupplementalData();
Map<String, Map<String, Integer>> sdeAccumulators = new HashMap<>();
for (Measure.MeasureGroupComponent group : measure.getGroup()) {
MeasureReport.MeasureReportGroupComponent reportGroup = new MeasureReport.MeasureReportGroupComponent();
reportGroup.setId(group.getId());
report.getGroup().add(reportGroup);
// Declare variables to avoid a hash lookup on every patient
// TODO: Isn't quite right, there may be multiple initial populations for a
// ratio measure...
Measure.MeasureGroupPopulationComponent initialPopulationCriteria = null;
Measure.MeasureGroupPopulationComponent numeratorCriteria = null;
Measure.MeasureGroupPopulationComponent numeratorExclusionCriteria = null;
Measure.MeasureGroupPopulationComponent denominatorCriteria = null;
Measure.MeasureGroupPopulationComponent denominatorExclusionCriteria = null;
Measure.MeasureGroupPopulationComponent denominatorExceptionCriteria = null;
Map<String, Resource> initialPopulation = null;
Map<String, Resource> numerator = null;
Map<String, Resource> numeratorExclusion = null;
Map<String, Resource> denominator = null;
Map<String, Resource> denominatorExclusion = null;
Map<String, Resource> denominatorException = null;
Map<String, Patient> initialPopulationPatients = null;
Map<String, Patient> numeratorPatients = null;
Map<String, Patient> numeratorExclusionPatients = null;
Map<String, Patient> denominatorPatients = null;
Map<String, Patient> denominatorExclusionPatients = null;
Map<String, Patient> denominatorExceptionPatients = null;
for (Measure.MeasureGroupPopulationComponent pop : group.getPopulation()) {
MeasurePopulationType populationType = MeasurePopulationType.fromCode(pop.getCode().getCodingFirstRep().getCode());
if (populationType != null) {
switch(populationType) {
case INITIALPOPULATION:
initialPopulationCriteria = pop;
initialPopulation = new HashMap<>();
if (type == MeasureReport.MeasureReportType.SUBJECTLIST) {
initialPopulationPatients = new HashMap<>();
}
break;
case NUMERATOR:
numeratorCriteria = pop;
numerator = new HashMap<>();
if (type == MeasureReport.MeasureReportType.SUBJECTLIST) {
numeratorPatients = new HashMap<>();
}
break;
case NUMERATOREXCLUSION:
numeratorExclusionCriteria = pop;
numeratorExclusion = new HashMap<>();
if (type == MeasureReport.MeasureReportType.SUBJECTLIST) {
numeratorExclusionPatients = new HashMap<>();
}
break;
case DENOMINATOR:
denominatorCriteria = pop;
denominator = new HashMap<>();
if (type == MeasureReport.MeasureReportType.SUBJECTLIST) {
denominatorPatients = new HashMap<>();
}
break;
case DENOMINATOREXCLUSION:
denominatorExclusionCriteria = pop;
denominatorExclusion = new HashMap<>();
if (type == MeasureReport.MeasureReportType.SUBJECTLIST) {
denominatorExclusionPatients = new HashMap<>();
}
break;
case DENOMINATOREXCEPTION:
denominatorExceptionCriteria = pop;
denominatorException = new HashMap<>();
if (type == MeasureReport.MeasureReportType.SUBJECTLIST) {
denominatorExceptionPatients = new HashMap<>();
}
break;
default:
throw new UnsupportedOperationException("Measure population, observation and measure population exclusion are used for continuous-variable scoring measures which are not supported");
}
}
}
switch(measureScoring) {
case PROPORTION:
case RATIO:
{
// For each patient in the initial population
for (Patient patient : patients) {
// Are they in the initial population?
boolean inInitialPopulation = evaluatePopulationCriteria(context, patient, initialPopulationCriteria, initialPopulation, initialPopulationPatients, null, null, null);
populateResourceMap(context, MeasurePopulationType.INITIALPOPULATION, resources, codeToResourceMap, includeEvaluatedResources);
if (inInitialPopulation) {
// Are they in the denominator?
boolean inDenominator = evaluatePopulationCriteria(context, patient, denominatorCriteria, denominator, denominatorPatients, denominatorExclusionCriteria, denominatorExclusion, denominatorExclusionPatients);
populateResourceMap(context, MeasurePopulationType.DENOMINATOR, resources, codeToResourceMap, includeEvaluatedResources);
if (inDenominator) {
// Are they in the numerator?
boolean inNumerator = evaluatePopulationCriteria(context, patient, numeratorCriteria, numerator, numeratorPatients, numeratorExclusionCriteria, numeratorExclusion, numeratorExclusionPatients);
populateResourceMap(context, MeasurePopulationType.NUMERATOR, resources, codeToResourceMap, includeEvaluatedResources);
if (!inNumerator && inDenominator && (denominatorExceptionCriteria != null)) {
// Are they in the denominator exception?
boolean inException = false;
for (Resource resource : evaluateCriteria(context, patient, denominatorExceptionCriteria)) {
inException = true;
denominatorException.put(resource.getIdElement().getIdPart(), resource);
denominator.remove(resource.getIdElement().getIdPart());
populateResourceMap(context, MeasurePopulationType.DENOMINATOREXCEPTION, resources, codeToResourceMap, includeEvaluatedResources);
}
if (inException) {
if (denominatorExceptionPatients != null) {
denominatorExceptionPatients.put(patient.getIdElement().getIdPart(), patient);
}
if (denominatorPatients != null) {
denominatorPatients.remove(patient.getIdElement().getIdPart());
}
}
}
}
}
MeasureSupplementalDataEvaluation.populateSDEAccumulators(context, patient, sdeAccumulators, sde);
}
// Calculate actual measure score, Count(numerator) / Count(denominator)
if (numerator != null && MapUtils.isNotEmpty(denominator)) {
reportGroup.setMeasureScore(new Quantity(numerator.size() / (double) denominator.size()));
}
break;
}
case COHORT:
{
// For each patient in the patient list
for (Patient patient : patients) {
evaluatePopulationCriteria(context, patient, initialPopulationCriteria, initialPopulation, initialPopulationPatients, null, null, null);
populateResourceMap(context, MeasurePopulationType.INITIALPOPULATION, resources, codeToResourceMap, includeEvaluatedResources);
MeasureSupplementalDataEvaluation.populateSDEAccumulators(context, patient, sdeAccumulators, sde);
}
break;
}
case CONTINUOUSVARIABLE:
throw new UnsupportedOperationException("Scoring type CONTINUOUSVARIABLE is not supported");
}
// Add population reports for each group
addPopulationCriteriaReport(report, reportGroup, initialPopulationCriteria, initialPopulation != null ? initialPopulation.size() : 0, initialPopulationPatients != null ? initialPopulationPatients.values() : null);
addPopulationCriteriaReport(report, reportGroup, numeratorCriteria, numerator != null ? numerator.size() : 0, numeratorPatients != null ? numeratorPatients.values() : null);
addPopulationCriteriaReport(report, reportGroup, numeratorExclusionCriteria, numeratorExclusion != null ? numeratorExclusion.size() : 0, numeratorExclusionPatients != null ? numeratorExclusionPatients.values() : null);
addPopulationCriteriaReport(report, reportGroup, denominatorCriteria, denominator != null ? denominator.size() : 0, denominatorPatients != null ? denominatorPatients.values() : null);
addPopulationCriteriaReport(report, reportGroup, denominatorExclusionCriteria, denominatorExclusion != null ? denominatorExclusion.size() : 0, denominatorExclusionPatients != null ? denominatorExclusionPatients.values() : null);
addPopulationCriteriaReport(report, reportGroup, denominatorExceptionCriteria, denominatorException != null ? denominatorException.size() : 0, denominatorExceptionPatients != null ? denominatorExceptionPatients.values() : null);
}
for (Entry<String, Set<String>> entry : codeToResourceMap.entrySet()) {
ListResource list = new ListResource();
for (String element : entry.getValue()) {
ListResource.ListEntryComponent comp = new ListEntryComponent();
comp.setItem(new Reference('#' + element));
list.addEntry(comp);
}
if (!list.isEmpty()) {
list.setId(UUID.randomUUID().toString());
list.setTitle(entry.getKey());
resources.put(list.getId(), list);
}
}
if (MapUtils.isNotEmpty(resources)) {
List<Reference> evaluatedResourceIds = new ArrayList<>();
resources.forEach((key, resource) -> {
evaluatedResourceIds.add(new Reference(resource.getId()));
});
report.setEvaluatedResource(evaluatedResourceIds);
}
if (MapUtils.isNotEmpty(sdeAccumulators)) {
report = MeasureSupplementalDataEvaluation.processAccumulators(report, sdeAccumulators, isSingle, patients);
}
return report;
}
use of org.hl7.fhir.r4.model.ListResource.ListEntryComponent in project org.hl7.fhir.core by hapifhir.
the class CCDAConverter method processAllergyProblemAct.
protected void processAllergyProblemAct(ListResource list, Element concern) throws Exception {
cda.checkTemplateId(concern, "2.16.840.1.113883.10.20.22.4.30");
// Allergy Problem Act - this is a concern - we treat the concern as information about it's place in the list
checkNoNegationOrNullFlavor(concern, "Allergy Problem Act");
checkNoSubject(concern, "Allergy Problem Act");
// SHALL contain exactly one [1..1] Allergy - intolerance Observation
for (Element entry : cda.getChildren(concern, "entryRelationship")) {
Element obs = cda.getChild(entry, "observation");
cda.checkTemplateId(obs, "2.16.840.1.113883.10.20.22.4.7");
checkNoNegationOrNullFlavor(obs, "Allergy - intolerance Observation");
checkNoSubject(obs, "Allergy Problem Act");
AllergyIntolerance ai = new AllergyIntolerance();
ListEntryComponent item = addItemToList(list, ai);
// SHALL contain at least one [1..*] id (CONF:7472).
for (Element e : cda.getChildren(concern, "id")) ai.getIdentifier().add(convert.makeIdentifierFromII(e));
// SHALL contain exactly one [1..1] statusCode, which SHALL be selected from ValueSet 2.16.840.1.113883.3.88.12.80.68 HITSPProblemStatus DYNAMIC (CONF:7485)
// the status code is about the concern (e.g. the entry in the list)
// possible values: active, suspended, aborted, completed, with an effective time
String s = cda.getStatus(concern);
item.setFlag(Factory.newCodeableConcept(s, "http://hl7.org/fhir/v3/ActStatus", s));
if (// only on this condition?
s.equals("aborted"))
item.setDeleted(true);
// SHALL contain exactly one [1..1] effectiveTime (CONF:7498)
Period p = convert.makePeriodFromIVL(cda.getChild(concern, "effectiveTime"));
item.getExtension().add(Factory.newExtension("http://www.healthintersections.com.au/fhir/extensions/list-period", p, false));
if (p.getEnd() != null)
item.setDate(p.getEnd());
else
item.setDate(p.getStart());
// SHALL contain at least one [1..*] id (CONF:7382)
for (Element e : cda.getChildren(obs, "id")) ai.getIdentifier().add(convert.makeIdentifierFromII(e));
// SHALL contain exactly one [1..1] effectiveTime (CONF:7387)
ai.getExtension().add(Factory.newExtension("http://www.healthintersections.com.au/fhir/extensions/allergyintolerance-period", convert.makePeriodFromIVL(cda.getChild(obs, "effectiveTime")), false));
// SHALL contain exactly one [1..1] value with @xsi:type="CD" (CONF:7390)
CodeableConcept type = convert.makeCodeableConceptFromCD(cda.getChild(obs, "value"));
// This value SHALL contain @code, which SHALL be selected from ValueSet 2.16.840.1.113883.3.88.12.3221.6.2 Allergy/Adverse Event Type
String ss = type.getCoding().get(0).getCode();
if (ss.equals("416098002") || ss.equals("414285001"))
ai.setType(AllergyIntoleranceType.ALLERGY);
else if (ss.equals("59037007") || ss.equals("235719002"))
ai.setType(AllergyIntoleranceType.INTOLERANCE);
ai.getExtension().add(Factory.newExtension("http://www.healthintersections.com.au/fhir/extensions/allergy-category", type, false));
// SHOULD contain zero or one [0..1] participant (CONF:7402) such that it
// ......This playingEntity SHALL contain exactly one [1..1] code
ai.setCode(convert.makeCodeableConceptFromCD(cda.getDescendent(obs, "participant/participantRole/playingEntity/code")));
// SHOULD contain zero or more [0..*] entryRelationship (CONF:7447) such that it SHALL contain exactly one [1..1] Reaction Observation (templateId:2.16.840.1.113883.10.20.22.4.9) (CONF:7450).
for (Element e : cda.getChildren(obs, "entryRelationship")) {
Element child = cda.getChild(e, "observation");
if (cda.hasTemplateId(child, "2.16.840.1.113883.10.20.22.4.28") && ai.getClinicalStatus() == null) {
// SHALL contain exactly one [1..1] value with @xsi:type="CE", where the @code SHALL be selected from ValueSet Problem Status Value Set 2.16.840.1.113883.3.88.12.80.68 DYNAMIC (CONF:7322).
// 55561003 SNOMED CT Active
// 73425007 SNOMED CT Inactive
// 413322009 SNOMED CT Resolved
String sc = cda.getChild(child, "value").getAttribute("code");
if (sc.equals("55561003")) {
ai.setClinicalStatus(AllergyIntoleranceClinicalStatus.ACTIVE);
ai.setVerificationStatus(AllergyIntoleranceVerificationStatus.CONFIRMED);
} else
ai.setClinicalStatus(AllergyIntoleranceClinicalStatus.RESOLVED);
} else if (cda.hasTemplateId(child, "2.16.840.1.113883.10.20.22.4.9")) {
ai.getReaction().add(processAdverseReactionObservation(child));
}
}
// SHOULD contain zero or one [0..1] entryRelationship (CONF:9961) such that it SHALL contain exactly one [1..1] Severity Observation (templateId:2.16.840.1.113883.10.20.22.4.8) (CONF:9963).
ai.setCriticality(readCriticality(cda.getSeverity(obs)));
}
}
use of org.hl7.fhir.r4.model.ListResource.ListEntryComponent in project nia-patient-switching-standard-adaptor by NHSDigital.
the class EncounterMapper method generateLinkSetTopicLists.
private void generateLinkSetTopicLists(RCMRMT030101UK04EhrComposition ehrComposition, ListResource consultation, List<ListResource> topics) {
var linkSetList = getLinkSets(ehrComposition);
if (!CollectionUtils.isEmpty(linkSetList)) {
var linkSetTopic = consultationListMapper.mapToTopic(consultation, null);
addLinkSetsAsTopicEntries(linkSetList, linkSetTopic);
consultation.addEntry(new ListEntryComponent(new Reference(linkSetTopic)));
topics.add(linkSetTopic);
}
}
use of org.hl7.fhir.r4.model.ListResource.ListEntryComponent in project nia-patient-switching-standard-adaptor by NHSDigital.
the class EncounterMapper method generateCategoryLists.
private void generateCategoryLists(RCMRMT030101UK04CompoundStatement topicCompoundStatement, ListResource topic, List<ListResource> categories) {
var categoryCompoundStatements = getCategoryCompoundStatements(topicCompoundStatement);
categoryCompoundStatements.forEach(categoryCompoundStatement -> {
var category = consultationListMapper.mapToCategory(topic, categoryCompoundStatement);
List<Reference> entryReferences = new ArrayList<>();
resourceReferenceUtil.extractChildReferencesFromCompoundStatement(categoryCompoundStatement, entryReferences);
entryReferences.forEach(reference -> addEntry(category, reference));
topic.addEntry(new ListEntryComponent(new Reference(category)));
categories.add(category);
});
}
use of org.hl7.fhir.r4.model.ListResource.ListEntryComponent in project gpconnect-demonstrator by nhsconnect.
the class StructuredAllergyIntoleranceBuilder method listResourceBuilder.
private void listResourceBuilder(ListResource buildingListResource, AllergyIntolerance allergyIntolerance, boolean isResolved) {
ListEntryComponent comp = new ListEntryComponent();
if (isResolved) {
buildingListResource.addContained(allergyIntolerance);
Reference allergyReference = new Reference("#" + allergyIntolerance.getId());
comp.setItem(allergyReference);
} else {
Reference allergyReference = new Reference("AllergyIntolerance/" + allergyIntolerance.getId());
comp.setItem(allergyReference);
}
buildingListResource.addEntry(comp);
}
Aggregations