use of com.hartwig.hmftools.patientdb.data.BiopsyTreatmentResponseData in project hmftools by hartwigmedical.
the class PatientReader method read.
@NotNull
public Patient read(@NotNull final EcrfPatient ecrfPatient, @NotNull final List<SampleData> sequencedSamples) throws IOException {
LOGGER.info("Reading patient " + ecrfPatient.patientId() + " with samples: " + sequencedSamples);
final BaselineData baselineData = cpctPatientReader.read(ecrfPatient);
final PreTreatmentData preTreatmentData = preTreatmentReader.read(ecrfPatient);
final List<BiopsyData> clinicalBiopsies = BiopsyReader.read(ecrfPatient);
final List<BiopsyTreatmentData> treatments = biopsyTreatmentReader.read(ecrfPatient);
final List<BiopsyTreatmentResponseData> treatmentResponses = BiopsyTreatmentResponseReader.read(ecrfPatient);
final List<TumorMarkerData> tumorMarkers = TumorMarkerReader.read(ecrfPatient);
final MatchResult<BiopsyData> matchedBiopsies = BiopsyMatcher.matchBiopsiesToTumorSamples(ecrfPatient.patientId(), sequencedSamples, clinicalBiopsies);
final MatchResult<BiopsyTreatmentData> matchedTreatments = TreatmentMatcher.matchTreatmentsToBiopsies(ecrfPatient.patientId(), clinicalBiopsies, treatments);
final MatchResult<BiopsyTreatmentResponseData> matchedResponses = TreatmentResponseMatcher.matchTreatmentResponsesToTreatments(ecrfPatient.patientId(), treatments, treatmentResponses);
final List<ValidationFinding> findings = Lists.newArrayList();
findings.addAll(matchedBiopsies.findings());
findings.addAll(matchedTreatments.findings());
findings.addAll(matchedResponses.findings());
return new Patient(ecrfPatient.patientId(), baselineData, preTreatmentData, sequencedSamples, matchedBiopsies.values(), matchedTreatments.values(), matchedResponses.values(), tumorMarkers, findings);
}
use of com.hartwig.hmftools.patientdb.data.BiopsyTreatmentResponseData in project hmftools by hartwigmedical.
the class PatientValidator method validateTreatmentResponses.
@NotNull
@VisibleForTesting
static List<ValidationFinding> validateTreatmentResponses(@NotNull final String patientIdentifier, @NotNull final List<BiopsyTreatmentData> treatments, @NotNull final List<BiopsyTreatmentResponseData> responses) {
final List<ValidationFinding> findings = Lists.newArrayList();
for (int i = 0; i < responses.size(); i++) {
findings.addAll(validateTreatmentResponse(patientIdentifier, responses.get(i), i == 0));
}
Collections.sort(treatments);
Collections.sort(responses);
if (treatments.isEmpty() && !responses.isEmpty()) {
findings.add(ValidationFinding.of(ECRF_LEVEL, patientIdentifier, FORM_TREATMENT, "treatment response filled in, but treatment data missing", FormStatusState.UNKNOWN, false));
}
if (!treatments.isEmpty() && !responses.isEmpty()) {
final LocalDate firstResponseDate = responses.get(0).date();
final LocalDate firstTreatmentStart = treatments.get(0).startDate();
if (firstResponseDate != null && firstTreatmentStart != null && firstResponseDate.isAfter(firstTreatmentStart)) {
findings.add(ValidationFinding.of(ECRF_LEVEL, patientIdentifier, fields(FORM_TREATMENT, FORM_TUMOR_MEASUREMENT), "first (baseline) measurement date is after first treatment start", FormStatusState.best(treatments.get(0).formStatus(), responses.get(0).formStatus()), treatments.get(0).formLocked() || responses.get(0).formLocked(), "first treatment response: " + firstResponseDate + "; first treatment start: " + firstTreatmentStart));
}
}
final List<BiopsyTreatmentData> treatmentsMissingResponse = treatments.stream().filter(treatment -> shouldHaveResponse(treatment) && !hasResponse(treatment.id(), responses)).collect(Collectors.toList());
if (treatmentsMissingResponse.size() > 0) {
findings.add(ValidationFinding.of(ECRF_LEVEL, patientIdentifier, FORM_TUMOR_MEASUREMENT, "no treatment response for at least 1 treatment", FormStatusState.UNKNOWN, false, "treatments " + treatmentsMissingResponse.stream().map(BiopsyTreatmentData::toString).collect(Collectors.toList()) + " should have response since they lasted more than " + Config.IMMEDIATE_TREATMENT_END_THRESHOLD + " days and started more than " + Config.START_DATE_RESPONSE_THRESHOLD + " days ago"));
}
return findings;
}
use of com.hartwig.hmftools.patientdb.data.BiopsyTreatmentResponseData in project hmftools by hartwigmedical.
the class PatientReaderTest method canReadCpctPatientTreatmentResponses.
@Test
public void canReadCpctPatientTreatmentResponses() {
final CpctEcrfModel model = loadTestEcrf();
assertEquals(1, model.patientCount());
final EcrfPatient cpctPatient = model.patients().iterator().next();
final List<BiopsyTreatmentResponseData> treatmentResponses = BiopsyTreatmentResponseReader.read(cpctPatient);
assertEquals(4, treatmentResponses.size());
assertEquals(LocalDate.parse("2012-02-09", DATE_FORMATTER), treatmentResponses.get(0).date());
assertEquals(null, treatmentResponses.get(0).response());
assertEquals(null, treatmentResponses.get(0).measurementDone());
assertEquals(LocalDate.parse("2012-03-05", DATE_FORMATTER), treatmentResponses.get(1).date());
assertEquals("PD", treatmentResponses.get(1).response());
assertEquals(null, treatmentResponses.get(1).measurementDone());
assertEquals(LocalDate.parse("2012-04-23", DATE_FORMATTER), treatmentResponses.get(2).date());
assertEquals("SD", treatmentResponses.get(2).response());
assertEquals(null, treatmentResponses.get(2).measurementDone());
assertEquals(LocalDate.parse("2012-06-08", DATE_FORMATTER), treatmentResponses.get(3).date());
assertEquals("PR", treatmentResponses.get(3).response());
assertEquals("Yes", treatmentResponses.get(3).measurementDone());
}
use of com.hartwig.hmftools.patientdb.data.BiopsyTreatmentResponseData in project hmftools by hartwigmedical.
the class BiopsyTreatmentResponseReader method read.
@NotNull
static List<BiopsyTreatmentResponseData> read(@NotNull final EcrfPatient patient) {
final List<BiopsyTreatmentResponseData> treatmentResponses = Lists.newArrayList();
for (final EcrfStudyEvent studyEvent : patient.studyEventsPerOID(STUDY_TREATMENT)) {
for (final EcrfForm form : studyEvent.nonEmptyFormsPerOID(FORM_TUMOR_MEASUREMENT, false)) {
// KODU: There are generally multiple assessment dates per tumor measurement (one per target lesion)
LocalDate assessmentDate = null;
for (final EcrfItemGroup itemGroup : form.nonEmptyItemGroupsPerOID(ITEMGROUP_MEASUREMENT, false)) {
final LocalDate date = itemGroup.readItemDate(FIELD_ASSESSMENT_DATE, 0, DATE_FORMATTER, false);
if (date != null) {
assessmentDate = date;
break;
}
}
LocalDate responseDate = null;
String measurementDone = null;
String boneOnlyDisease = null;
String response = null;
for (final EcrfItemGroup itemGroup : form.nonEmptyItemGroupsPerOID(ITEMGROUP_TUMOR_MEASUREMENT, false)) {
final LocalDate responseDateValue = itemGroup.readItemDate(FIELD_RESPONSE_DATE, 0, DATE_FORMATTER, false);
if (responseDateValue != null) {
responseDate = responseDateValue;
}
final String measurementDoneValue = itemGroup.readItemString(FIELD_MEASUREMENT_DONE, 0, false);
if (measurementDoneValue != null) {
measurementDone = measurementDoneValue;
}
final String boneOnlyDiseaseValue = itemGroup.readItemString(FIELD_BONE_ONLY_DISEASE, 0, false);
if (boneOnlyDiseaseValue != null) {
boneOnlyDisease = boneOnlyDiseaseValue;
}
final String responseValue = itemGroup.readItemString(FIELD_RESPONSE, 0, false);
if (responseValue != null) {
response = responseValue;
}
}
BiopsyTreatmentResponseData responseData = ImmutableBiopsyTreatmentResponseData.of(assessmentDate, responseDate, response, measurementDone, boneOnlyDisease, form.status(), form.locked());
if (!isEmpty(responseData)) {
treatmentResponses.add(responseData);
}
}
}
return treatmentResponses;
}
use of com.hartwig.hmftools.patientdb.data.BiopsyTreatmentResponseData in project hmftools by hartwigmedical.
the class TreatmentResponseMatcher method matchTreatmentResponsesToTreatments.
@NotNull
public static MatchResult<BiopsyTreatmentResponseData> matchTreatmentResponsesToTreatments(@NotNull String patientId, @NotNull List<BiopsyTreatmentData> treatments, @NotNull List<BiopsyTreatmentResponseData> responses) {
final List<BiopsyTreatmentResponseData> matchedResponses = Lists.newArrayList();
final List<ValidationFinding> findings = Lists.newArrayList();
Collections.sort(responses);
List<BiopsyTreatmentData> sortedTreatments = sortAndFilter(treatments);
if (hasOverlappingTreatments(sortedTreatments)) {
if (!responses.isEmpty()) {
findings.add(responseMatchFinding(patientId, "treatments are overlapping. Cannot match any response.", "treatments: " + sortedTreatments));
}
return new MatchResult<>(responses, findings);
}
Iterator<BiopsyTreatmentData> treatmentIterator = sortedTreatments.iterator();
BiopsyTreatmentData currentTreatment = treatmentIterator.hasNext() ? treatmentIterator.next() : null;
LocalDate firstTreatmentStart = currentTreatment != null ? currentTreatment.startDate() : null;
BiopsyTreatmentData nextTreatment = treatmentIterator.hasNext() ? treatmentIterator.next() : null;
boolean hasNewBaselineResponseFound = false;
for (BiopsyTreatmentResponseData response : responses) {
LocalDate responseDate = response.date();
if (responseMatchable(responseDate, firstTreatmentStart)) {
LocalDate nextTreatmentStart = nextTreatment != null ? nextTreatment.startDate() : null;
while (nextTreatmentStart != null && responseDate.isAfter(nextTreatmentStart)) {
currentTreatment = nextTreatment;
nextTreatment = treatmentIterator.hasNext() ? treatmentIterator.next() : null;
nextTreatmentStart = nextTreatment != null ? nextTreatment.startDate() : null;
hasNewBaselineResponseFound = false;
}
if (hasNewBaselineResponseFound) {
matchedResponses.add(response);
findings.add(responseMatchFinding(patientId, "response after new baseline and before next treatment", "response: " + response));
} else {
String actualResponse = response.response();
if (actualResponse != null && actualResponse.equalsIgnoreCase("ne")) {
matchedResponses.add(response);
hasNewBaselineResponseFound = true;
} else {
matchedResponses.add(ImmutableBiopsyTreatmentResponseData.builder().from(response).treatmentId(currentTreatment.id()).build());
}
}
} else {
matchedResponses.add(response);
}
}
return new MatchResult<>(matchedResponses, findings);
}
Aggregations