/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.ctakes.padtermspotter.cc;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CASException;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.collection.CasConsumer_ImplBase;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.JFSIndexRepository;
import org.apache.uima.jcas.cas.TOP;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.ResourceProcessException;
import org.apache.uima.util.ProcessTrace;
import org.apache.ctakes.core.cc.NonTerminalConsumer;
import org.apache.ctakes.typesystem.type.structured.DocumentID;
import org.apache.ctakes.padtermspotter.type.PADHit;
import org.apache.ctakes.padtermspotter.type.PADLocation;
import org.apache.ctakes.padtermspotter.type.PADTerm;
import org.apache.ctakes.padtermspotter.type.SubSection;
/**
* @author Mayo Clinic
*
*/
public class PADOffSetsRecord extends CasConsumer_ImplBase implements
NonTerminalConsumer {
public static final String ultrasound = "US_EXAM";
public static final String lower_extremity = "LOWER_EXT";
public static final String ultrasound_lower_extremity = "US_LOWER_EXT";
public static final String ultrasound_lower_extremity_one_side_only = "US_LOWER_SOLO";
public static final String CAT_Scan = "CT_EXAM";
public static final String CAT_Scan_one_side_only = "CT_EXAM_SOLO";
public static Logger iv_logger = Logger.getLogger(PADOffSetsRecord.class);
public static final String PARAM_ALTERNATE_ALGOR = "usingAlternateAlgorithm";
public static final String PARAM_OUTPUTFILE = "outputFileName";
public static final String COLLECTION_SEPARATOR = "|";
public static final String FIELD_SEPARATOR = ":";
public static final String OS_NAME = "os.name";
public static final String OS_WINDOWS = "Windows";
public static final String COUNT_PLACE_HOLDER = "@@COUNT@@";
public Boolean alternateAlgorithm = false;
// --- default constructor ----
public PADOffSetsRecord() {
super();
}
public void initialize() throws ResourceInitializationException {
try {
super.initialize();
casConsumerOffSetData = new StringBuffer();
casConsumerOutData = new StringBuffer();
// if(isWindows())
// {
String outputFileName = (String) getConfigParameterValue(PARAM_OUTPUTFILE);
alternateAlgorithm = (Boolean) getConfigParameterValue(PARAM_ALTERNATE_ALGOR);
iv_outputFile = new File(outputFileName);
fos = new FileOutputStream(iv_outputFile);
// }
} catch (FileNotFoundException fnfe) {
throw new ResourceInitializationException(fnfe);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void processCas(CAS cas) throws ResourceProcessException {
try {
casConsumerOffSetData
.replace(0, casConsumerOffSetData.length(), "");
casConsumerOutData.replace(0, casConsumerOutData.length(), "");
// get a list of PADTerm annotations
processHits(cas);
} catch (CASException ce) {
throw new ResourceProcessException(ce);
}
}
/**
* Used by any end-user program to get the processed data
*
* @return
*/
public String getOutputXml() {
return casConsumerOffSetData.toString();
}
// -- private data members ---------------
private boolean isWindows() {
return System.getProperty(OS_NAME).startsWith(OS_WINDOWS);
}
private void addPatientMetaData(JCas jcas) {
// TODO: Need to upgrade to Common Type System compliant
//
// JFSIndexRepository indexes = jcas.getJFSIndexRepository();
// Iterator<?> annotItr = indexes.getAnnotationIndex(Hash.type)
// .iterator();
// if (annotItr.hasNext()) {
// Properties props = (Properties) annotItr.next();
// FSArray fsArr = props.getPropArr();
// for (int i = 0; i < fsArr.size(); i++) {
// Property prop = (Property) fsArr.get(i);
// if (prop == null)
// continue;
//
// String key = prop.getKey();
// if (key != null && key.equalsIgnoreCase("CLINICAL_NUMBER"))
// casConsumerOffSetData.append(FIELD_SEPARATOR
// + prop.getValue());
//
// if (key != null && key.equalsIgnoreCase("NOTE_DATE"))
// ;
// casConsumerOffSetData.append(FIELD_SEPARATOR + prop.getValue());
//
// }
// }
}
// -- private data members ---------------
private void processHits(CAS cas) throws CASException,
ResourceProcessException {
int count = 0;
try {
JCas jcas = cas.getJCas();
JFSIndexRepository indexes;
Iterator<?> annotItr;
Iterator<?> checkExamItr;
boolean haveUSSoloExamType = false;
boolean haveUSExamType = false;
boolean haveLowerExtExamType = false;
boolean haveCombinedExamType = false;
boolean haveLowerSoloExamType = false;
boolean haveVRADExamType = false;
boolean locTermsOnly = false;
boolean noStenosis = true;
boolean noVein = true;
boolean noStent = true;
boolean CTTypeExam = false;
indexes = jcas.getJFSIndexRepository();
boolean negatedCase = true;
int locOnlyCount = 0;
int termOnlyCount = 0;
int probableCount = 0;
int veinCount = 0;
// Not needed for production use - add documentId that was collected
// in the CAS initializer
// if (isWindows()) {
FSIterator<TOP> documentIDIterator = indexes.getAllIndexedFS(DocumentID.type);
if (documentIDIterator.hasNext()) {
DocumentID did = (DocumentID) documentIDIterator.next();
casConsumerOffSetData.append(did.getDocumentID());
}
// }
// add clinic number, etc for local run
// if (isWindows())
addPatientMetaData(jcas);
annotItr = indexes.getAnnotationIndex(PADHit.type).iterator();
casConsumerOffSetData.append(COLLECTION_SEPARATOR
+ COUNT_PLACE_HOLDER + COLLECTION_SEPARATOR);
// Need subsection for special case where Ultrasound exams are being
// implemented:
// Case : UNK: if no relevant documents OR negation of positive
// evidence in US or V+IRA
checkExamItr = indexes.getAnnotationIndex(SubSection.type)
.iterator();
while (checkExamItr.hasNext()) {
SubSection ssId = (SubSection) checkExamItr.next();
// US_LOWER_SOLO (ultrasound_lower_extremity_one_side_only),
// CT_EXAM_SOLO (CAT_Scan_one_side_only)
if (ssId.getParentSectionId().compareTo(
ultrasound_lower_extremity_one_side_only) == 0
|| ssId.getParentSectionId().compareTo(
"CAT_Scan_one_side_only") == 0)
haveLowerSoloExamType = true;
if (ssId.getParentSectionId().indexOf("V_IRAD") >= 0
|| ssId.getParentSectionId().compareTo("V&IRAD") == 0)
haveVRADExamType = true;
// US_EXAM (ultrasound),
if (ssId.getParentSectionId().compareTo(ultrasound) == 0)
haveUSExamType = true;
// LOWER_EXT (lower_extremity),
if (ssId.getParentSectionId().compareTo(lower_extremity) == 0)
haveLowerExtExamType = true;
// US_LOWER_EXT (ultrasound_lower_extremity),
if (ssId.getParentSectionId().compareTo(
ultrasound_lower_extremity) == 0)
haveCombinedExamType = true;
// US_LOWER_SOLO (ultrasound_lower_extremity_one_side_only),
if (ssId.getParentSectionId().compareTo(
ultrasound_lower_extremity_one_side_only) == 0)
haveUSSoloExamType = true;
// CT_EXAM (CAT_Scan),
if (ssId.getParentSectionId().indexOf(CAT_Scan) > 0
|| ssId.getParentSectionId().compareTo(CAT_Scan) == 0)
CTTypeExam = true;
}
boolean negCount = false;
boolean probableCase = false;
boolean globalProbable = false;
int balanceCount = 0;
while (annotItr.hasNext()) {
count++;
negatedCase = false;
// probableCase = false;
if (count >= 1) {
casConsumerOffSetData.append("(");
casConsumerOutData.append(COLLECTION_SEPARATOR);
}
// add segment from term or location
PADHit uaHit = (PADHit) annotItr.next();
if (uaHit.getUaTerm() != null)
casConsumerOutData.append(((PADTerm) uaHit.getUaTerm())
.getSegmentID());
else if (uaHit.getUaLocation() != null)
casConsumerOutData.append(((PADLocation) uaHit
.getUaLocation()).getSegmentID());
// add location and term data
PADLocation ual = uaHit.getUaLocation();
PADTerm uat = uaHit.getUaTerm();
if (ual != null) {
casConsumerOutData.append(COLLECTION_SEPARATOR
+ ual.getCoveredText());
casConsumerOffSetData.append(ual.getBegin() + "-"
+ ual.getEnd() + ":");
if (ual.getPolarity() == -1
&& uat == null
|| (ual.getPolarity() == -1 && uat != null
&& uat.getTypeID() != disorderStenosis && ual
.getPolarity() == -1)) {
negatedCase = true;
} else if (ual.getIsStandAlone() != 1
&& ual.getPolarity() != -1
&& ual.getUncertainty() == disorderPatent) {
probableCase = true;
probableCount++;
} else
probableCase = false;
} else {
casConsumerOutData.append(COLLECTION_SEPARATOR + " ");
casConsumerOffSetData.append("-1:");
if (uat.getTypeID() == disorderStenosis
&& uat.getPolarity() != -1)
noStenosis = false;
if (uat != null && uat.getPolarity() == -1
&& uat.getTypeID() != disorderStenosis
&& uat.getTypeID() != anatomicalSiteExclusion)
negatedCase = true;
else if (uat != null
&& ((uat.getIsStandAlone() != 1 || uat.getTypeID() == disorderPatent) && uat
.getPolarity() != -1)) {
probableCase = true;
probableCount++;
} else
probableCase = false;
}
if (uat != null) {
casConsumerOutData.append(COLLECTION_SEPARATOR
+ uat.getCoveredText());
casConsumerOffSetData.append(uat.getBegin() + "-"
+ uat.getEnd() + ")");
if (uat.getTypeID() == disorderStenosis
&& uat.getPolarity() != -1)
noStenosis = false;
if (uat.getPolarity() == -1
&& uat.getTypeID() != disorderStenosis
&& uat.getUncertainty() != disorderPatent
&& uat.getTypeID() != anatomicalSiteExclusion
&& uat.getIsStandAlone() != 1)
negatedCase = true;
else if (uat.getUncertainty() == disorderPatent
&& uat.getIsStandAlone() != 1) {
probableCase = true;
probableCount++;
} else if (!negatedCase)
probableCase = false;
} else {
casConsumerOutData.append(COLLECTION_SEPARATOR + " ");
casConsumerOffSetData.append("-1)");
if (ual != null && ual.getPolarity() == -1
&& ual.getUncertainty() != disorderPatent)
negatedCase = true;
else if (ual.getIsStandAlone() != 1
&& ual.getPolarity() != -1
&& ual.getUncertainty() == disorderPatent) {
probableCase = true;
probableCount++;
}
else
probableCase = false;
}
if (probableCase)
globalProbable = true;
if ((negatedCase || probableCase)) {
count--;
negCount = true;
if (uat != null && !probableCase
&& uat.getTypeID() != disorderStenosis
&& uat.getTypeID() != disorderPatent) {
if (ual == null || (ual != null)
&& ual.getTypeID() != disorderPatent
&& ual.getPolarity() == -1)
balanceCount--;
}
} else
balanceCount++;
}
annotItr = indexes.getAnnotationIndex(PADLocation.type).iterator();
while (annotItr.hasNext()) {
PADLocation location = (PADLocation) annotItr.next();
Iterator<?> annotHitItr = indexes.getAnnotationIndex(
PADHit.type).iterator();
boolean skip = false;
if (location.getCoveredText().indexOf("vein") != -1) {
noVein = false;
veinCount++;
}
while (annotHitItr.hasNext() && !skip) {
PADHit uaHit = ((PADHit) annotHitItr.next());
if (uaHit.getUaLocation() != null
&& location.getBegin() == uaHit.getUaLocation()
.getBegin())
skip = true;
}
if (!skip) {
if (location.getPolarity() == -1) {
locTermsOnly = true;
}
if (location.getPolarity() != -1) {
locOnlyCount++;
casConsumerOffSetData.append("(");
casConsumerOffSetData.append("-1:");
casConsumerOffSetData.append(location.getBegin() + "-"
+ location.getEnd() + ")");
casConsumerOutData.append(COLLECTION_SEPARATOR);
casConsumerOutData.append(location.getSegmentID());
casConsumerOutData.append(COLLECTION_SEPARATOR
+ "**NO TERM**");
casConsumerOutData.append(COLLECTION_SEPARATOR
+ location.getCoveredText());
} else if (location.getPolarity() != -1
&& location.getTypeID() != disorderStenosis
&& location.getTypeID() != anatomicalSiteExclusion
&& location.getUncertainty() == disorderPatent)
locOnlyCount--;
}
}
annotItr = indexes.getAnnotationIndex(PADTerm.type).iterator();
while (annotItr.hasNext()) {
PADTerm term = (PADTerm) annotItr.next();
Iterator<?> annotHitItr = indexes.getAnnotationIndex(
PADHit.type).iterator();
boolean skip = false;
while (annotHitItr.hasNext() && !skip) {
PADHit uaHit = ((PADHit) annotHitItr.next());
if (uaHit.getUaTerm() != null
&& term.getBegin() == uaHit.getUaTerm().getBegin())
skip = true;
}
if (!skip) {
locTermsOnly = false;
if (term.getTypeID() == disorderStenosis
&& term.getPolarity() != -1)
noStenosis = false;
if (term.getUncertainty() == disorderPatent
&& (term.getPolarity() != -1 || term.getTypeID() == disorderStenosis
&& term.getTypeID() != anatomicalSiteExclusion)) {
if (term.getUncertainty() == disorderPatent && count == 0) {
globalProbable = true;
if (term.getCoveredText().compareToIgnoreCase(
"stent") == 0
|| term.getCoveredText()
.compareToIgnoreCase("stents") == 0
|| term.getCoveredText()
.compareToIgnoreCase("stented") == 0)
noStent = false;
}
termOnlyCount++;
casConsumerOffSetData.append("(");
casConsumerOffSetData.append(term.getBegin() + "-"
+ term.getEnd() + ":-1)");
casConsumerOutData.append(COLLECTION_SEPARATOR);
casConsumerOutData.append(term.getSegmentID());
casConsumerOutData.append(COLLECTION_SEPARATOR
+ term.getCoveredText());
casConsumerOutData.append(COLLECTION_SEPARATOR
+ "**NO LOC**");
} else if (term.getPolarity() != -1
&& term.getTypeID() != disorderStenosis
&& term.getTypeID() != anatomicalSiteExclusion
&& term.getTypeID() == disorderPatent)
termOnlyCount--;
}
}
int loc = casConsumerOffSetData.indexOf(COUNT_PLACE_HOLDER);
casConsumerOffSetData.append(casConsumerOutData.toString());
boolean noRelatedExam = !haveUSSoloExamType && !haveUSExamType
&& !haveLowerExtExamType && !haveCombinedExamType
&& !haveLowerSoloExamType && !haveVRADExamType;
String classification = null;
if (!alternateAlgorithm) {
// If there is no related exam type and no positive or negative
// evidence, classify as UNKNOWN;
if ((!haveUSSoloExamType && !haveUSExamType
&& !haveLowerExtExamType && !haveCombinedExamType
&& !haveLowerSoloExamType && !CTTypeExam && !negCount
&& !negatedCase && !globalProbable && count < 1)
|| noRelatedExam && !CTTypeExam)
classification = String.valueOf(-1);
// If there is positive evidence in an applicable exam, classify
// as POS;
else if (((balanceCount > 0 || count > 0) && (haveVRADExamType
|| haveUSSoloExamType || haveUSExamType
|| haveLowerExtExamType || haveCombinedExamType
|| haveLowerSoloExamType || CTTypeExam)))
classification = String.valueOf(count);
// If there is explicit evidence of negation of positive
// evidence or lower solo extremity exam with evidence of no
// stenosis and no discussion concerning veins and other
// locations of concern are mentioned nor probable PAD
// discussion, classify as NEG ;
else if ((negatedCase || negCount)
&& ((balanceCount < 0 && locOnlyCount + balanceCount < 1) || (noStenosis
&& noStent && noVein && !globalProbable)
&& haveCombinedExamType
&& (!locTermsOnly || negatedCase))
|| count < 0
|| (haveLowerSoloExamType && haveUSExamType && locOnlyCount > 0))
classification = String.valueOf(0);
// If there are no POS or NEG evidence OR
// o if there is negation of positive evidence in an Ultrosound
// or V+IRAD report and no probable and negated counts or vein
// counts,
// o classify as UNKNOWN;
else if ((haveUSSoloExamType || haveUSExamType
|| haveCombinedExamType || haveLowerExtExamType
|| haveLowerSoloExamType || haveVRADExamType || CTTypeExam)
&& ((!probableCase && probableCount < 1 && (negatedCase || negCount)) || veinCount > 0))
classification = String.valueOf(-1);
// Otherwise, classify as PROB;
else
classification = "prob";
} else {
classification = calculateRecordLevelClassification(count,
termOnlyCount,
locOnlyCount, balanceCount, probableCount, veinCount,
noStent, locTermsOnly, noVein, noStenosis, CTTypeExam,
haveLowerExtExamType, haveCombinedExamType,
haveUSSoloExamType, haveLowerSoloExamType,
haveUSExamType, negCount, negatedCase, globalProbable);
}
casConsumerOffSetData.replace(loc, loc
+ COUNT_PLACE_HOLDER.length(), classification);
// if (isWindows()) {
casConsumerOffSetData.append("\n");
fos.write(casConsumerOffSetData.toString().getBytes());
// }
} catch (IOException ioe) {
throw new ResourceProcessException(ioe);
}
}
// -- private data members ---------------
public void collectionProcessComplete(ProcessTrace arg0)
throws ResourceProcessException, IOException {
// TODO Auto-generated method stub
super.collectionProcessComplete(arg0);
File file = new File(new File(iv_outputFile.getAbsolutePath())
.getParent());
holdResults = new File(file + System.getProperty("file.separator")
+ "Summary_PADRadiology.csv");
if (file.isDirectory()) {
String[] processFiles = file.list();
if (!holdResults.exists())
store(holdResults.getAbsolutePath(), drugHeaders);
for (int i = 0; i < processFiles.length; i++) {
System.out.println("Process Each File in '" + file
+ System.getProperty("file.separator")
+ processFiles[i] + "'");
File nextFile = new File(file
+ System.getProperty("file.separator")
+ processFiles[i]);
boolean hasNext = true;
if (!nextFile.isDirectory()) {
int numPADConfirmed = 0;
int numPADConfirmedWeight = 0;
int numPADNegative = 0;
int numPADProbable = 0;
int countPatientRecords = 0;
String fileName = nextFile.getAbsolutePath();
List<String[][]> findPatientPADClassification = loadFieldContents(fileName);
List<String[][]> nextPatientPADClassification = loadFieldContents(fileName);
Iterator<String[][]> searchNextPatient = nextPatientPADClassification
.iterator();
searchNextPatient.next();
Iterator<String[][]> searchPatientClassification = findPatientPADClassification
.iterator();
String[][] nextPatientClassInstance = null;
String nextPatientID = "";
while (searchPatientClassification.hasNext()) {
countPatientRecords++;
if (hasNext = searchNextPatient.hasNext()) {
nextPatientClassInstance = searchNextPatient.next();
nextPatientID = nextPatientClassInstance[0][0];
}
String[][] patientClassInstance = searchPatientClassification
.next();
String patientID = patientClassInstance[0][0];
String classificationPAD = patientClassInstance[1][0];
if (classificationPAD.indexOf("-1") == -1) {
if (classificationPAD.indexOf("prob") == 0) {
numPADProbable++;
} else if (classificationPAD.indexOf("0") == 0) {
numPADNegative++;
} else {
numPADConfirmed++;
numPADConfirmedWeight = numPADConfirmedWeight
+ new Integer(classificationPAD)
.intValue();
}
}
// set precedence order as PAD-Yes > PAD-prob >
// PAD-no/unknown
if (nextPatientID.compareTo(patientID) != 0 || !hasNext
&& nextPatientID.compareTo(patientID) == 0) {
if ((numPADNegative > numPADProbable)
&& (numPADNegative > numPADConfirmed && numPADNegative > numPADConfirmedWeight)) {
store(holdResults.getAbsolutePath(), patientID
+ ",no");
} else if ((numPADProbable > numPADNegative)
&& (numPADProbable > numPADConfirmed)
|| (numPADConfirmed > 0
&& numPADNegative == numPADConfirmed && numPADConfirmedWeight == numPADNegative)) {
store(holdResults.getAbsolutePath(), patientID
+ ",probable");
} else if ((numPADConfirmed > numPADNegative || numPADConfirmedWeight > numPADNegative)
&& (numPADConfirmed > numPADProbable || numPADConfirmedWeight > numPADProbable)) {
store(holdResults.getAbsolutePath(), patientID
+ ",yes");
} else if ((numPADConfirmed > numPADNegative || numPADConfirmedWeight > numPADNegative)
&& (numPADConfirmed == numPADProbable || numPADConfirmedWeight > numPADProbable)) {
if (numPADConfirmedWeight / numPADProbable > 1)
store(holdResults.getAbsolutePath(),
patientID + ",yes");
else
store(holdResults.getAbsolutePath(),
patientID + ",probable");
} else if ((numPADConfirmed > numPADProbable || numPADConfirmedWeight > numPADProbable)
&& (numPADConfirmed == numPADNegative || numPADConfirmedWeight > numPADNegative)) {
if (numPADConfirmedWeight / numPADNegative > 1)
store(holdResults.getAbsolutePath(),
patientID + ",yes");
else
store(holdResults.getAbsolutePath(),
patientID + ",unknown");
} else if ((numPADNegative > numPADConfirmed)
&& (numPADNegative == numPADProbable)) {
store(holdResults.getAbsolutePath(), patientID
+ ",probable");
} else if ((numPADNegative > numPADProbable)
&& (numPADNegative == numPADConfirmed)) {
if (numPADConfirmed > 0
&& numPADConfirmedWeight
/ numPADNegative > 1)
store(holdResults.getAbsolutePath(),
patientID + ",yes");
else
store(holdResults.getAbsolutePath(),
patientID + ",unknown");
} else if ((numPADProbable > numPADConfirmed)
&& (numPADProbable == numPADNegative)) {
store(holdResults.getAbsolutePath(), patientID
+ ",unknown");
} else if ((numPADProbable > numPADNegative)
&& (numPADProbable == numPADConfirmed)) {
if (numPADConfirmed > 0
&& numPADConfirmedWeight
/ numPADProbable > 1)
store(holdResults.getAbsolutePath(),
patientID + ",yes");
else
store(holdResults.getAbsolutePath(),
patientID + ",probable");
} else {
store(holdResults.getAbsolutePath(), patientID
+ ",unknown");
}
numPADConfirmed = 0;
numPADConfirmedWeight = 0;
numPADNegative = 0;
numPADProbable = 0;
countPatientRecords = 0;
}
}
}
}
}
// if (isWindows())
fos.close();
}
/**
* Private method 'calculateRecordLevelClassification' is responsible for
* providing the PAD classification given the factors; #1 Type of
* examination ("CT_EXAM", "LOWER_EXT", "US_LOWER_EXT", "US_EXAM_SOLO",
* "US_LOWER_SOLO or CT_EXAM_SOLO, and "US_EXAM") #2 Number of hits, and, if
* applicable, the difference if both exist ("numberOfHits" and
* "differentialHitCount") #3 Number of term only mentions, site only
* mentions, probable evidence, mentions of vein related terms, and mention
* of stent related terms ("numberOfTermOnly", "numberOfLocationOnly",
* "numberOfProbable", "numberVeinMentions", and "noMentionOfStents") #4
* Whether there is a mention of veins or stenosis related terms
* ("noMentionOfVeins" and "noMentionOfStenosis") #5 Whether there is
* evidence of probable, location terms only, negation and possible negation
* ("foundEvidenceOfProbable", "locationTermsOnly", "haveNegativeCases",
* "possibleNegativeCases"); #6 "noPadMentionThreshold" is a somewhat
* arbitrary value used to measure a relative weight of evidence against
* other counts.
*
*
* @param numberOfHits
* @param numberOfTermOnly
* @param numberOfLocationOnly
* @param differentialHitCount
* @param numberOfProbable
* @param numberVeinMentions
* @param noMentionOfStents
* @param locationTermsOnly
* @param noMentionOfVeins
* @param noMentionOfStenosis
* @param haveCT_EXAM
* @param haveLOWER_EXT
* @param haveUS_LOWER_EXT
* @param haveUS_EXAM_SOLO
* @param haveUS_LOWER_SOLOorCT_EXAM_SOLO
* @param haveUS_EXAM
* @param haveNegativeCases
* @param possibleNegativeCases
* @param foundEvidenceOfProbable
* @return
*/
private String calculateRecordLevelClassification(int numberOfHits,
int numberOfTermOnly, int numberOfLocationOnly,
int differentialHitCount, int numberOfProbable,
int numberVeinMentions, boolean noMentionOfStents,
boolean locationTermsOnly, boolean noMentionOfVeins,
boolean noMentionOfStenosis, boolean haveCT_EXAM,
boolean haveLOWER_EXT, boolean haveUS_LOWER_EXT,
boolean haveUS_EXAM_SOLO, boolean haveUS_LOWER_SOLOorCT_EXAM_SOLO,
boolean haveUS_EXAM, boolean haveNegativeCases,
boolean possibleNegativeCases, boolean foundEvidenceOfProbable) {
if (numberOfHits == 0 && numberOfTermOnly + numberOfLocationOnly >= 0)
differentialHitCount = 0;
if ((differentialHitCount < 0 || !haveCT_EXAM)
&& numberOfHits == 0
&& !haveNegativeCases
&& !foundEvidenceOfProbable
&& !haveLOWER_EXT
&& !haveUS_LOWER_EXT
|| (!haveUS_EXAM && !haveUS_LOWER_EXT && !haveCT_EXAM
&& !haveUS_LOWER_SOLOorCT_EXAM_SOLO && !haveLOWER_EXT
&& numberOfHits == 0 && !haveNegativeCases && (locationTermsOnly && numberOfLocationOnly > noPadMentionThreshold))
|| ((haveUS_EXAM || haveUS_LOWER_EXT) && numberOfHits == 0
&& !noMentionOfStenosis && !foundEvidenceOfProbable && (!locationTermsOnly
|| !noMentionOfVeins || haveNegativeCases))
|| ((numberOfLocationOnly <= noPadMentionThreshold)
&& numberOfHits == 0
&& (!haveNegativeCases || !noMentionOfVeins)
&& !noMentionOfStenosis && !foundEvidenceOfProbable && (numberOfTermOnly <= 0 || differentialHitCount < 0))
|| noMentionOfStenosis && !haveUS_LOWER_EXT && !haveLOWER_EXT
&& numberOfHits == 0 && !foundEvidenceOfProbable)
return String.valueOf(-1);
else if (numberOfHits > 0
&& ((!noMentionOfStenosis
&& (haveCT_EXAM || haveLOWER_EXT || haveUS_LOWER_EXT) && (!foundEvidenceOfProbable
|| !possibleNegativeCases || numberOfHits >= noPadMentionThreshold))
|| (numberOfHits > 0 && differentialHitCount >= 0
&& !foundEvidenceOfProbable && (!haveUS_LOWER_SOLOorCT_EXAM_SOLO && !haveUS_EXAM_SOLO)) || (numberOfHits
+ numberOfLocationOnly + numberOfTermOnly >= noPadMentionThreshold)))
return String.valueOf(numberOfHits);
else if (((haveNegativeCases || (numberOfLocationOnly >= noPadMentionThreshold
&& numberOfTermOnly <= 0 && (haveLOWER_EXT || haveUS_EXAM || haveUS_LOWER_EXT)))
&& !foundEvidenceOfProbable && !haveUS_LOWER_SOLOorCT_EXAM_SOLO)
|| noMentionOfStenosis
&& (numberOfHits != 0 && numberOfTermOnly != 0
&& differentialHitCount != 0 || haveLOWER_EXT)
&& !foundEvidenceOfProbable
&& noMentionOfVeins
&& (haveCT_EXAM || haveLOWER_EXT))
return String.valueOf(0);
else if (foundEvidenceOfProbable
&& (haveLOWER_EXT || haveUS_EXAM
|| haveUS_LOWER_SOLOorCT_EXAM_SOLO || haveUS_EXAM_SOLO
|| haveUS_LOWER_EXT || ((haveCT_EXAM || numberOfProbable >= noPadMentionThreshold)
&& noMentionOfStents
&& (noMentionOfVeins || (!noMentionOfVeins && numberVeinMentions < numberOfProbable
+ numberOfLocationOnly)) && !haveUS_EXAM_SOLO && !haveUS_LOWER_SOLOorCT_EXAM_SOLO)))
return "prob";
else
return String.valueOf(-1);
}
/**
* Loads text from a file. Specialized to load array idAndDate and return it
* too
*
* @param filename
* @return
* @throws FileNotFoundException
* @throws IOException
*/
private void store(String filename, String lineToStore)
throws FileNotFoundException, IOException {
int howMany = 132;
boolean skipDate = false;
File f = new File(filename);
if (!f.exists())
f.createNewFile();
ByteArrayOutputStream bout = new ByteArrayOutputStream(howMany * 4);
DataOutputStream dout = new DataOutputStream(bout);
FileOutputStream fos = new FileOutputStream(filename, true);
if (!skipDate)
dout.writeBytes(lineToStore + '\n');
try {
if (!skipDate) {
bout.writeTo(fos);
fos.flush();
}
} finally {
fos.close();
bout.close();
dout.close();
}
}
/**
* Loads text from a file. Specialized to load array idAndDate and return it
* too
*
* @param filename
* @return
* @throws FileNotFoundException
* @throws IOException
*/
private static List<String[][]> loadFieldContents(String filename)
throws FileNotFoundException, IOException {
String[][] padClass = null;
List<String[][]> listIdandClassification = new ArrayList<String[][]>();
File f = new File(filename);
BufferedReader br = new BufferedReader(new FileReader(f));
// br.readLine();// dummy line to go beyond columm headers
String line = br.readLine();
int index = 0;
while ((line != null) && (line != "") && (line.length() > 0)) {
String patientID = line.substring(0, line.indexOf('|'));
String temp = line.substring(line.indexOf('|') + 1);
String padClassification = temp.substring(0, temp.indexOf('|'));
padClass = new String[][] { { patientID }, { padClassification } };
listIdandClassification.add(index, padClass);
index++;
line = br.readLine();
}
br.close();
return listIdandClassification;
}
// -- private data members ---------------
private File iv_outputFile;
private StringBuffer casConsumerOffSetData;
private StringBuffer casConsumerOutData;
private FileOutputStream fos;
private File holdResults;
private String drugHeaders = "clinic,case_type";
private int anatomicalSiteExclusion = 9;
private int disorderPatent = 7;
private int disorderStenosis = 8;
private static int noPadMentionThreshold = 2;
}