use of org.hl7.fhir.r5.model.Observation in project BridgeServer2 by Sage-Bionetworks.
the class CRCControllerTest method operationWrongIdentifier.
@Test(expectedExceptions = BadRequestException.class, expectedExceptionsMessageRegExp = "Could not find Bridge user ID.")
public void operationWrongIdentifier() throws Exception {
when(mockRequest.getHeader(AUTHORIZATION)).thenReturn(AUTHORIZATION_HEADER_VALUE);
when(mockAccountService.authenticate(any(), any())).thenReturn(account);
when(mockAccountService.getAccount(ACCOUNT_ID)).thenReturn(Optional.of(account));
Identifier identifier = new Identifier();
identifier.setSystem("wrong-system");
identifier.setValue(TEST_USER_ID);
Observation observation = new Observation();
observation.addIdentifier(identifier);
String json = FHIR_CONTEXT.newJsonParser().encodeResourceToString(observation);
mockRequestBody(mockRequest, json);
controller.postObservation();
}
use of org.hl7.fhir.r5.model.Observation in project quality-measure-and-cohort-service by Alvearie.
the class MeasureSupplementalDataEvaluationTest method testProcessAccumulators_notSDESex.
@Test
public void testProcessAccumulators_notSDESex() {
/*
* Jill - I don't like how this part of the code works. The code grabs everything after (and including) the "-",
* and then looks for that to exist as an extension on the Patient resource. This works for race and ethnicity
* on the US-core patient profile, but since we already calculated this in the populate SDE accumulator method
* the only reason it's "recalculating" is because the system and display aren't on the passed in map.
* Plus, it's coded assuming there is a list of extensions within the extension (which is how US-Core handles race and eth)
* and it magically grabs the first one... so if you have multiple this doesn't match all of them.
*/
Code white = new Code();
white.setCode(WHITE_CODE);
Map<String, Map<String, Integer>> sdeAccumulators = getSDEAccumulators(SDE_RACE, null, white, new HashMap<>());
MeasureReport report = new MeasureReport();
Patient mockPatient = mockPatient();
Extension raceExtension = new Extension();
// This can be anything as long as it includes "-race"
raceExtension.setUrl("something-race");
// This example was stolen from https://www.hl7.org/fhir/us/core/Patient-example.xml.html
Extension valueExtension = new Extension();
valueExtension.setUrl("ombCategory");
valueExtension.setValue(getWhiteCoding());
raceExtension.setExtension(Arrays.asList(valueExtension));
Mockito.when(mockPatient.getExtension()).thenReturn(Arrays.asList(raceExtension));
MeasureSupplementalDataEvaluation.processAccumulators(report, sdeAccumulators, true, Arrays.asList(mockPatient));
assertNotNull(report);
// EvaluatedResource should contain a reference to an observation record created for supplemental data
assertEquals(1, report.getEvaluatedResource().size());
// The observation record mentioned previously should exist within the contained resources of the measure report
assertEquals(1, report.getContained().size());
assertTrue(report.getContained().get(0) instanceof Observation);
Observation obs = (Observation) report.getContained().get(0);
// For a single patient, the code of the observation should be the supplemental data text
assertEquals(SDE_RACE, obs.getCode().getText());
// For a single patient, the value of the observation should be the result of the appropriate define
assertTrue(obs.getValue() instanceof CodeableConcept);
assertEquals(WHITE_CODE, ((CodeableConcept) obs.getValue()).getCoding().get(0).getCode());
}
use of org.hl7.fhir.r5.model.Observation in project quality-measure-and-cohort-service by Alvearie.
the class MeasureSupplementalDataEvaluationTest method testProcessAccumulators.
@Test
public void testProcessAccumulators() {
Map<String, Map<String, Integer>> sdeAccumulators = getSexSDEAccumulators();
MeasureReport report = new MeasureReport();
MeasureSupplementalDataEvaluation.processAccumulators(report, sdeAccumulators, true, new ArrayList<>());
assertNotNull(report);
// EvaluatedResource should contain a reference to an observation record created for supplemental data
assertEquals(1, report.getEvaluatedResource().size());
// The observation record mentioned previously should exist within the contained resources of the measure report
assertEquals(1, report.getContained().size());
assertTrue(report.getContained().get(0) instanceof Observation);
Observation obs = (Observation) report.getContained().get(0);
// For a single patient, the code of the observation should be the supplemental data text
assertEquals(MeasureSupplementalDataEvaluation.SDE_SEX, obs.getCode().getText());
// For a single patient, the value of the observation should be the result of the appropriate define
assertTrue(obs.getValue() instanceof CodeableConcept);
assertEquals(MALE_CODE, ((CodeableConcept) obs.getValue()).getCoding().get(0).getCode());
// Within the observation, there should be 1 extension, with two further nested extensions
Extension obsExt = obs.getExtensionByUrl(MeasureSupplementalDataEvaluation.CQF_MEASUREINFO_URL);
assertNotNull(obsExt);
assertEquals(2, obsExt.getExtension().size());
Extension measureNestedExt = obsExt.getExtensionByUrl(MeasureSupplementalDataEvaluation.MEASURE);
assertTrue(measureNestedExt.getValue() instanceof CanonicalType);
assertEquals(MeasureSupplementalDataEvaluation.CQFMEASURES_URL + report.getMeasure(), ((CanonicalType) measureNestedExt.getValue()).asStringValue());
Extension populationNestedExt = obsExt.getExtensionByUrl(MeasureSupplementalDataEvaluation.POPULATION_ID);
assertEquals(MeasureSupplementalDataEvaluation.SDE_SEX, ((StringType) populationNestedExt.getValue()).asStringValue());
}
use of org.hl7.fhir.r5.model.Observation in project quality-measure-and-cohort-service by Alvearie.
the class MeasureEvaluatorTest method in_populations_supplemental_data.
@Test
public void in_populations_supplemental_data() throws Exception {
CapabilityStatement metadata = getCapabilityStatement();
mockFhirResourceRetrieval("/metadata?_format=json", metadata);
Patient patient = getPatient("123", AdministrativeGender.MALE, "1970-10-10");
mockFhirResourceRetrieval(patient);
Library library = setupDefineReturnLibrary();
expressionsByPopulationType.clear();
expressionsByPopulationType.put(MeasurePopulationType.INITIALPOPULATION, INITIAL_POPULATION);
expressionsByPopulationType.put(MeasurePopulationType.DENOMINATOR, DENOMINATOR);
expressionsByPopulationType.put(MeasurePopulationType.NUMERATOR, NUMERATOR);
Measure measure = getProportionMeasure("ProportionMeasureName", library, expressionsByPopulationType);
measure.setSupplementalData(Arrays.asList(createSupplementalDataComponent("SDE Sex", MeasureSupplementalDataEvaluation.SDE_SEX)));
mockFhirResourceRetrieval(measure);
MeasureReport report = evaluator.evaluatePatientMeasure(measure.getId(), patient.getId(), null, new MeasureEvidenceOptions());
assertNotNull(report);
// EvaluatedResource should contain a reference to an observation record created for supplemental data, despite the evidence options indicating returning no evaluatedResources
assertEquals(1, report.getEvaluatedResource().size());
// See MeasureSupplementalDataEvaluationTest for more details on what is returned here
}
use of org.hl7.fhir.r5.model.Observation 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;
}
Aggregations