/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.ohd.pophealth.preprocess; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.astm.ccr.Agent; import org.astm.ccr.AlertType; import org.astm.ccr.CodeType; import org.astm.ccr.CodedDescriptionType; import org.astm.ccr.ContinuityOfCareRecord; import org.astm.ccr.ContinuityOfCareRecord.Body.Problems; import org.astm.ccr.EncounterType; import org.astm.ccr.ProblemType; import org.astm.ccr.ResultType; import org.astm.ccr.SocialHistoryType; import org.astm.ccr.StructuredProductType; import org.astm.ccr.StructuredProductType.Product; import org.astm.ccr.TestType; import org.ohd.umls.Code; import org.ohd.umls.CodingSystem; import org.ohd.umls.UMLSConfiguration; import org.ohd.umls.UMLSInterface; /** * * @author ohdohd */ public class PreProcessor implements Closeable { private static UMLSInterface umls; private static List<CodingSystem> availableCS; public PreProcessor(InputStream config, String lvgConfLocation) { umls = new UMLSInterface(new UMLSConfiguration(config), lvgConfLocation); setAvailableCS(); } public PreProcessor(String fileName, String lvgConfLocation) { umls = new UMLSInterface(new UMLSConfiguration(fileName), lvgConfLocation); setAvailableCS(); } private void setAvailableCS() { availableCS = umls.getCodingSystem(); Logger.getLogger(PreProcessor.class.getName()).log(Level.FINEST, "Size of available Coding Systems: " + availableCS.size()); } public ContinuityOfCareRecord preProcess(ContinuityOfCareRecord ccr) { ccr = inferCodes(ccr); ccr = fixTobaccoHx(ccr); ccr = fixEncounters(ccr); return ccr; } public ContinuityOfCareRecord fixTobaccoHx(ContinuityOfCareRecord ccr) { if (ccr.getBody().getSocialHistory() != null) { ProblemType p = fixTobaccoHx(ccr.getBody().getSocialHistory().getSocialHistoryElement()); if (p != null) { // fix the date and set to CCR creation date if (p.getDateTime().isEmpty()) { p.getDateTime().add(ccr.getDateTime()); } //Add to existing list of problems or create a new list of needed if (ccr.getBody().getProblems() != null) { ccr.getBody().getProblems().getProblem().add(p); } else { Problems prblms = new Problems(); prblms.getProblem().add(p); ccr.getBody().setProblems(prblms); } } } return ccr; } private static final String[] cptEncounterList = {"99201", "99202", "99203", "99204", "99205", "99211", "99212", "99213", "99214", "99215", "99217", "99218", "99219", "99220", "99241", "99242", "99243", "99244", "99245", "99341", "99342", "99343", "99344", "99345", "99347", "99348", "99349", "99350", "99384", "99385", "99386", "99387", "99394", "99395", "99396", "99397", "99401", "99402", "99403", "99404", "99411", "99412", "99420", "99429", "99455", "99456"}; private ArrayList<CodeType> encounterCodes = null; private void createEncounterCodes() { encounterCodes = new ArrayList<CodeType>(); for (String c : cptEncounterList) { CodeType ct = new CodeType(); ct.setCodingSystem("CPT"); ct.setValue(c); encounterCodes.add(ct); } } public ContinuityOfCareRecord fixEncounters(ContinuityOfCareRecord ccr) { if (encounterCodes == null) { createEncounterCodes(); } if (ccr.getBody().getEncounters() != null) { for (EncounterType et : ccr.getBody().getEncounters().getEncounter()) { if (et.getDescription() == null) { CodedDescriptionType cdt = new CodedDescriptionType(); cdt.setText("Fixed Encounter"); et.setDescription(cdt); } for (CodeType ct : encounterCodes) { et.getDescription().getCode().add(ct); } } } return ccr; } public ContinuityOfCareRecord inferCodes(ContinuityOfCareRecord ccr) { if (ccr.getBody().getMedications() != null) { codeMeds(ccr.getBody().getMedications().getMedication()); } if (ccr.getBody().getImmunizations() != null) { codeMeds(ccr.getBody().getImmunizations().getImmunization()); } if (ccr.getBody().getProblems() != null) { codeProblems(ccr.getBody().getProblems().getProblem()); } if (ccr.getBody().getAlerts() != null) { codeAlerts(ccr.getBody().getAlerts().getAlert()); } if (ccr.getBody().getResults() != null) { codeResults(ccr.getBody().getResults().getResult()); } if (ccr.getBody().getVitalSigns() != null) { codeResults(ccr.getBody().getVitalSigns().getResult()); } return ccr; } private void codeMeds(List<StructuredProductType> medications) { for (StructuredProductType spt : medications) { for (Product p : spt.getProduct()) { Logger.getLogger(PreProcessor.class.getName()).log(Level.FINE, "Looking up code for {0}", p.getProductName().getText()); addCode(p.getProductName(), "rxnorm"); if (p.getBrandName() != null) { addCode(p.getBrandName(), "rxnorm"); } } } } private void codeAlerts(List<AlertType> alerts) { for (AlertType at : alerts) { if (at.getDescription() != null) { addCode(at.getDescription(), "rxnorm"); } for (Agent ag : at.getAgent()) { if (ag.getProducts() != null) { for (StructuredProductType spt : ag.getProducts().getProduct()) { for (Product p : spt.getProduct()) { addCode(p.getProductName(), "rxnorm"); if (p.getBrandName() != null) { addCode(p.getBrandName(), "rxnorm"); } } } } } } } private void codeProblems(List<ProblemType> problems) { for (ProblemType pt : problems) { if (pt.getDescription() != null) { addCode(pt.getDescription(), "snomedct"); } } } private void codeResults(List<ResultType> results) { for (ResultType rt : results) { if (rt.getDescription() != null) { addCode(rt.getDescription(), "lnc"); addCode(rt.getDescription(), "snomedct"); } for (TestType tt : rt.getTest()) { if (tt.getDescription() != null) { // TODO Hack to fix systolic/diastolic if (tt.getDescription().getText() != null) { if ("systolic".equalsIgnoreCase(tt.getDescription().getText())) { // Setting the text to include "blood pressure" will allow for the correct infered code tt.getDescription().setText("Systolic Blood Pressure"); } else if ("diastolic".equalsIgnoreCase(tt.getDescription().getText())) { // Setting the text to include "blood pressure" does not work with diastolic, need to force it tt.getDescription().setText("Diastolic Blood Pressure"); // Force the add a SNOMEDCT Code CodeType dbp = new CodeType(); dbp.setCodingSystem("SNOMEDCT"); dbp.setVersion("07/2009"); dbp.setValue("163031004"); tt.getDescription().getCode().add(dbp); } } // End Hack addCode(tt.getDescription(), "lnc"); addCode(tt.getDescription(), "snomedct"); } } } } private ProblemType fixTobaccoHx(List<SocialHistoryType> socialHistoryElements) { for (SocialHistoryType sht : socialHistoryElements) { if (sht.getType() != null && sht.getStatus() != null) { if (sht.getType().getText().equalsIgnoreCase("smoking")) { if (sht.getStatus().getText().equalsIgnoreCase("current")) { ProblemType tobacAddic = new ProblemType(); tobacAddic.setCCRDataObjectID(Long.toString(System.currentTimeMillis())); CodedDescriptionType desc = new CodedDescriptionType(); desc.setText("Current Smoker"); CodeType smoker = new CodeType(); smoker.setCodingSystem("SNOMEDCT"); smoker.setValue("160603005"); smoker.setVersion("2009"); desc.getCode().add(smoker); tobacAddic.setDescription(desc); Logger.getLogger(PreProcessor.class.getName()).log(Level.FINE, "Found Current Smoker"); return tobacAddic; } else { ProblemType tobacAddic = new ProblemType(); tobacAddic.setCCRDataObjectID(Long.toString(System.currentTimeMillis())); CodedDescriptionType desc = new CodedDescriptionType(); desc.setText("Non Smoker"); CodeType smoker = new CodeType(); smoker.setCodingSystem("SNOMEDCT"); smoker.setValue("105539002"); smoker.setVersion("2009"); desc.getCode().add(smoker); tobacAddic.setDescription(desc); Logger.getLogger(PreProcessor.class.getName()).log(Level.FINE, "Found Non Smoker"); return tobacAddic; } } } } return null; } private void addCode(CodedDescriptionType cdt, String vocab) { if (cdt.getText() == null || vocab == null) { return; } else { // Could check for known vocab CodingSystem cs = findCodingSystem(vocab); if (cs == null) { Logger.getLogger(PreProcessor.class.getName()).log(Level.WARNING, "Could not find vocab: {0}", vocab); return; } String norm = umls.normalize(cdt.getText()); Logger.getLogger(PreProcessor.class.getName()).log(Level.FINEST, "Normalized to: " + norm); List<String> cuis = umls.getCUIs(norm); Logger.getLogger(PreProcessor.class.getName()).log(Level.FINEST, "Found [{0}] CUI matches", cuis.size()); for (String cui : cuis) { Code code = umls.getCode(cui, cs); if (code != null) { Logger.getLogger(PreProcessor.class.getName()).log(Level.FINEST, "Adding Code: {0} [{1}] for [{2}]", new Object[]{code.getTerm(), code.getValue(), cdt.getText()}); CodeType ct = new CodeType(); ct.setCodingSystem(cs.getId()); ct.setVersion(cs.getVersion()); ct.setValue(code.getValue()); cdt.getCode().add(ct); } else { Logger.getLogger(PreProcessor.class.getName()).log(Level.FINEST, "No Code Found for: {0}", norm); } } } } private CodingSystem findCodingSystem(String name) { for (CodingSystem cs : availableCS) { if (name.equalsIgnoreCase(cs.getId())) { return cs; } } return null; } public void close() throws IOException { this.umls.close(); } }