You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ctakes.apache.org by se...@apache.org on 2017/08/20 23:19:04 UTC

svn commit: r1805587 - in /ctakes/trunk: ctakes-core-res/src/main/resources/org/apache/ctakes/core/sections/ ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/ ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/html/ ctakes-core/src/ma...

Author: seanfinan
Date: Sun Aug 20 23:19:04 2017
New Revision: 1805587

URL: http://svn.apache.org/viewvc?rev=1805587&view=rev
Log:
Add Events, Times
Add DocTimeRel
SemanticGroup refactor
Patient History regex fix

Modified:
    ctakes/trunk/ctakes-core-res/src/main/resources/org/apache/ctakes/core/sections/DefaultSectionRegex.bsv
    ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/SemanticGroup.java
    ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/html/HtmlTextWriter.java
    ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/plaintext/PrettyTextWriter.java

Modified: ctakes/trunk/ctakes-core-res/src/main/resources/org/apache/ctakes/core/sections/DefaultSectionRegex.bsv
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-core-res/src/main/resources/org/apache/ctakes/core/sections/DefaultSectionRegex.bsv?rev=1805587&r1=1805586&r2=1805587&view=diff
==============================================================================
--- ctakes/trunk/ctakes-core-res/src/main/resources/org/apache/ctakes/core/sections/DefaultSectionRegex.bsv (original)
+++ ctakes/trunk/ctakes-core-res/src/main/resources/org/apache/ctakes/core/sections/DefaultSectionRegex.bsv Sun Aug 20 23:19:04 2017
@@ -2,7 +2,7 @@ Physical Examination||^[\t ]*PHYSICAL EX
 History of Present Illness||^[\t ]*(?:HISTORY OF (?:THE )?(?:PRESENT |PHYSICAL )?ILLNESS)(?: \(HPI(?:, PROBLEM BY PROBLEM)?\))?[\t ]*:?[\t ]*$
 Past Medical History||^[\t ]*(?:(?:HISTORY OF (?:THE )?PAST ILLNESS)|(?:PAST MEDICAL HISTORY))[\t ]*:?[\t ]*$
 Chief Complaint||^[\t ]*(?:CHIEF|PRIMARY) COMPLAINTS?[\t ]*:?[\t ]*$
-Personal and Social History||^[\t ]*(?:(?:PERSONAL (?:(?:AND )?SOCIAL )?HISTORY)?|(?:(?:PSYCHO)?SOC(?:IAL)? HISTORY)|(?:HISTORY (?:OF )(?:OTHER )?SOCIAL (?:FUNCTIONs?|FACTORS?))|(?:PSO)|(?:P?SHX))[\t ]*:?[\t ]*$
+Personal and Social History||^[\t ]*(?:(?:PERSONAL (?:(?:AND )?SOCIAL )?HISTORY)|(?:(?:PSYCHO)?SOC(?:IAL)? HISTORY)|(?:HISTORY (?:OF )(?:OTHER )?SOCIAL (?:FUNCTIONs?|FACTORS?))|(?:PSO)|(?:P?SHX))[\t ]*:?[\t ]*$
 Review of Systems||^[\t ]*REVIEW OF SYSTEMS?[\t ]*:?[\t ]*$
 Family Medical History||^[\t ]*(?:FAMILY (?:MEDICAL )?HISTORY)|(?:HISTORY (?:OF )?FAMILY MEMBER DISEASES?)|(?:FAM HX)|FH|FMH|FMHX|FHX[\t ]*:?[\t ]*$
 Medications||^[\t ]*(?:CURRENT )?MEDICATIONS?[\t ]*:?[\t ]*$

Modified: ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/SemanticGroup.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/SemanticGroup.java?rev=1805587&r1=1805586&r2=1805587&view=diff
==============================================================================
--- ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/SemanticGroup.java (original)
+++ ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/SemanticGroup.java Sun Aug 20 23:19:04 2017
@@ -1,7 +1,12 @@
 package org.apache.ctakes.core.cc.pretty;
 
-import java.util.Arrays;
-import java.util.Collection;
+import org.apache.ctakes.core.util.OntologyConceptUtil;
+import org.apache.ctakes.typesystem.type.refsem.UmlsConcept;
+import org.apache.ctakes.typesystem.type.textsem.EventMention;
+import org.apache.ctakes.typesystem.type.textsem.IdentifiedAnnotation;
+import org.apache.ctakes.typesystem.type.textsem.TimeMention;
+
+import java.util.*;
 
 /**
  * enumeration of ctakes semantic types:
@@ -22,6 +27,10 @@ public enum SemanticGroup {
 
    static public final String UNKNOWN_SEMANTIC = "Unknown";
    static public final String UNKNOWN_SEMANTIC_CODE = "UNK";
+   static public final String EVENT_SEMANTIC = "Event";
+   static public final String EVENT_CODE = "EVT";
+   static public final String TIMEX_SEMANTIC = "Time";
+   static public final String TIMEX_CODE = "TMX";
    final private String _name;
    final private String _code;
    final private Collection<String> _tuis;
@@ -54,6 +63,48 @@ public enum SemanticGroup {
    }
 
    /**
+    * @param annotation -
+    * @return all applicable semantic names for the annotation
+    */
+   static public Collection<String> getSemanticNames( final IdentifiedAnnotation annotation ) {
+      final Collection<UmlsConcept> umlsConcepts = OntologyConceptUtil.getUmlsConcepts( annotation );
+      if ( umlsConcepts == null || umlsConcepts.isEmpty() ) {
+         if ( annotation instanceof EventMention ) {
+            return Collections.singletonList( EVENT_SEMANTIC );
+         } else if ( annotation instanceof TimeMention ) {
+            return Collections.singletonList( TIMEX_SEMANTIC );
+         }
+         return Collections.emptyList();
+      }
+      final Collection<String> semanticNames = new HashSet<>();
+      for ( UmlsConcept umlsConcept : umlsConcepts ) {
+         semanticNames.add( getSemanticName( annotation, umlsConcept ) );
+      }
+      final List<String> semanticList = new ArrayList<>( semanticNames );
+      Collections.sort( semanticList );
+      return semanticList;
+   }
+
+   /**
+    * @param annotation -
+    * @param concept    -
+    * @return semantic name
+    */
+   static public String getSemanticName( final IdentifiedAnnotation annotation, final UmlsConcept concept ) {
+      final String tui = concept.getTui();
+      final String semanticName = SemanticGroup.getSemanticName( tui );
+      if ( semanticName != null && !semanticName.equals( UNKNOWN_SEMANTIC ) ) {
+         return semanticName;
+      }
+      if ( annotation instanceof EventMention ) {
+         return EVENT_SEMANTIC;
+      } else if ( annotation instanceof TimeMention ) {
+         return TIMEX_SEMANTIC;
+      }
+      return getSimpleName( annotation );
+   }
+
+   /**
     * @param tui a tui of interest
     * @return the name of a Semantic type associated with the tui
     */
@@ -70,6 +121,15 @@ public enum SemanticGroup {
    }
 
    /**
+    * @param concept    -
+    * @return the code of a Semantic type associated with the concept
+    */
+   static public String getSemanticCode( final UmlsConcept concept ) {
+      final String tui = concept.getTui();
+      return getSemanticCode( tui );
+   }
+
+   /**
     * @param tui a tui of interest
     * @return the code of a Semantic type associated with the tui
     */
@@ -98,5 +158,18 @@ public enum SemanticGroup {
       return UNKNOWN_SEMANTIC;
    }
 
+   /**
+    *
+    * @param annotation annotation whose name could not be derived by tui
+    * @return the simple class name, with any suffix "Mention" removed
+    */
+   static private String getSimpleName( final IdentifiedAnnotation annotation ) {
+      final String simpleName = annotation.getClass().getSimpleName();
+      if ( simpleName.endsWith( "Mention" ) ) {
+         return simpleName.substring( 0, simpleName.length() - 7 );
+      }
+      return simpleName;
+   }
+
 
 }

Modified: ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/html/HtmlTextWriter.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/html/HtmlTextWriter.java?rev=1805587&r1=1805586&r2=1805587&view=diff
==============================================================================
--- ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/html/HtmlTextWriter.java (original)
+++ ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/html/HtmlTextWriter.java Sun Aug 20 23:19:04 2017
@@ -8,6 +8,8 @@ import org.apache.ctakes.core.cc.pretty.
 import org.apache.ctakes.core.pipeline.PipeBitInfo;
 import org.apache.ctakes.core.util.DocumentIDAnnotationUtil;
 import org.apache.ctakes.core.util.OntologyConceptUtil;
+import org.apache.ctakes.typesystem.type.refsem.Event;
+import org.apache.ctakes.typesystem.type.refsem.EventProperties;
 import org.apache.ctakes.typesystem.type.refsem.UmlsConcept;
 import org.apache.ctakes.typesystem.type.syntax.BaseToken;
 import org.apache.ctakes.typesystem.type.textsem.EventMention;
@@ -89,7 +91,6 @@ final public class HtmlTextWriter extend
                = JCasUtil.indexCovered( jCas, Sentence.class, IdentifiedAnnotation.class );
          final Map<Sentence, Collection<BaseToken>> sentenceTokens
                = JCasUtil.indexCovered( jCas, Sentence.class, BaseToken.class );
-//         writeSections( sectionSentences, sentenceAnnotations, sentenceTokens, writer );
          writeSections( sections, lists, listEntries, sectionSentences, sentenceAnnotations, sentenceTokens, writer );
          writeInfoPane( writer );
          writer.write( startJavascript() );
@@ -101,7 +102,6 @@ final public class HtmlTextWriter extend
    }
 
    /**
-    *
     * @param title normally the document title
     * @return html to set the header
     */
@@ -119,8 +119,9 @@ final public class HtmlTextWriter extend
 
    /**
     * Write html for document title
-    * @param title normally document title, such as filename
-    * @param writer    writer to which pretty html for the section should be written
+    *
+    * @param title  normally document title, such as filename
+    * @param writer writer to which pretty html for the section should be written
     * @throws IOException if the writer has issues
     */
    static private void writeTitle( final String title, final BufferedWriter writer ) throws IOException {
@@ -355,10 +356,10 @@ final public class HtmlTextWriter extend
    /**
     * Write html for a sentence from the document text
     *
-    * @param sentence sentence of interest
+    * @param sentence    sentence of interest
     * @param annotations identified annotations in the section
-    * @param baseTokens baseTokens in the section
-    * @param writer    writer to which pretty html for the section should be written
+    * @param baseTokens  baseTokens in the section
+    * @param writer      writer to which pretty html for the section should be written
     * @throws IOException if the writer has issues
     */
    static private void writeSentence( final Sentence sentence,
@@ -421,8 +422,8 @@ final public class HtmlTextWriter extend
          if ( textSpan.getWidth() == 0 ) {
             continue;
          }
-         final Collection<String> semanticNames = getSemanticNames( annotation );
-         if ( !semanticNames.isEmpty() || annotation instanceof TimeMention || annotation instanceof EventMention ) {
+         final Collection<String> semanticNames = SemanticGroup.getSemanticNames( annotation );
+         if ( !semanticNames.isEmpty() ) {
             annotationMap.putIfAbsent( textSpan, new ArrayList<>() );
             annotationMap.get( textSpan ).add( annotation );
          }
@@ -431,30 +432,6 @@ final public class HtmlTextWriter extend
    }
 
    /**
-    *
-    * @param identifiedAnnotation -
-    * @return all applicable semantic names for the annotation
-    */
-   static private Collection<String> getSemanticNames( final IdentifiedAnnotation identifiedAnnotation ) {
-      final Collection<UmlsConcept> umlsConcepts = OntologyConceptUtil.getUmlsConcepts( identifiedAnnotation );
-      if ( umlsConcepts == null || umlsConcepts.isEmpty() ) {
-         return Collections.emptyList();
-      }
-      final Collection<String> semanticNames = new HashSet<>();
-      for ( UmlsConcept umlsConcept : umlsConcepts ) {
-         final String tui = umlsConcept.getTui();
-         String semanticName = SemanticGroup.getSemanticName( tui );
-         if ( semanticName.equals( "Unknown" ) ) {
-            semanticName = identifiedAnnotation.getClass().getSimpleName();
-         }
-         semanticNames.add( semanticName );
-      }
-      final List<String> semanticList = new ArrayList<>( semanticNames );
-      Collections.sort( semanticList );
-      return semanticList;
-   }
-
-   /**
     * sorts by begins, then by ends if begins are equal
     */
    static private class TextSpanComparator implements Comparator<TextSpan> {
@@ -648,62 +625,103 @@ final public class HtmlTextWriter extend
 
    /**
     * @param annotation -
-    * @return map of semantic to pref text
+    * @return map of semantic to text for annotations
     */
    static private Map<String, Collection<String>> createInfoMap( final IdentifiedAnnotation annotation ) {
       final Collection<UmlsConcept> concepts = OntologyConceptUtil.getUmlsConcepts( annotation );
       final Map<String, Collection<String>> semanticMap = new HashMap<>();
+      final String coveredText = getCoveredText( annotation );
       for ( UmlsConcept concept : concepts ) {
-         final String semanticName = getSemanticCode( annotation, concept );
-         semanticMap.putIfAbsent( semanticName, new HashSet<>() );
-         semanticMap.get( semanticName ).add( getPreferredText( annotation, concept ) );
+         final String semanticCode = SemanticGroup.getSemanticCode( concept );
+         semanticMap.putIfAbsent( semanticCode, new HashSet<>() );
+         String text = getCodes( concept ) + coveredText + getPreferredText( coveredText, concept );
+         if ( annotation instanceof EventMention ) {
+            text += getDocTimeRel( (EventMention) annotation );
+         }
+         semanticMap.get( semanticCode ).add( text );
+      }
+      if ( concepts.isEmpty() ) {
+         String semanticCode = "";
+         String postText = "";
+         if ( annotation instanceof EventMention ) {
+            semanticCode = SemanticGroup.EVENT_CODE;
+            postText = getDocTimeRel( (EventMention) annotation );
+         } else if ( annotation instanceof TimeMention ) {
+            semanticCode = SemanticGroup.TIMEX_CODE;
+         }
+         if ( !semanticCode.isEmpty() ) {
+            semanticMap.putIfAbsent( semanticCode, new HashSet<>() );
+            semanticMap.get( semanticCode ).add( coveredText + postText );
+         }
       }
       return semanticMap;
    }
 
    /**
-    * @param annotation -
-    * @param concept    -
-    * @return semantic name
+    * @param concept -
+    * @return cui if it exists and any codes if they exist
     */
-   static private String getSemanticName( final IdentifiedAnnotation annotation, final UmlsConcept concept ) {
-      final String tui = concept.getTui();
-      final String semanticName = SemanticGroup.getSemanticName( tui );
-      if ( semanticName != null && !semanticName.equals( "Unknown" ) ) {
-         return semanticName;
+   static private String getCodes( final UmlsConcept concept ) {
+      String codes = "";
+      final String cui = concept.getCui();
+      if ( cui != null && !cui.isEmpty() ) {
+         codes += cui;
+      }
+      final String code = concept.getCode();
+      if ( code != null && !code.isEmpty() ) {
+         if ( !codes.isEmpty() ) {
+            codes += " ";
+         }
+         codes += code;
+      }
+      if ( !codes.isEmpty() ) {
+         codes += " : ";
       }
-      return annotation.getClass().getSimpleName();
+      return codes;
    }
 
    /**
     * @param annotation -
-    * @param concept    -
-    * @return semantic code
+    * @return the covered text
     */
-   static private String getSemanticCode( final IdentifiedAnnotation annotation, final UmlsConcept concept ) {
-      final String tui = concept.getTui();
-      final String semanticCode = SemanticGroup.getSemanticCode( tui );
-      if ( semanticCode != null && !semanticCode.equals( SemanticGroup.UNKNOWN_SEMANTIC_CODE ) ) {
-         return semanticCode;
-      }
-      return annotation.getClass().getSimpleName();
+   static private String getCoveredText( final IdentifiedAnnotation annotation ) {
+      return annotation.getCoveredText().replace( '\r', ' ' ).replace( '\n', ' ' );
    }
 
    /**
-    * @param annotation -
-    * @param concept    -
-    * @return cui and pref text
+    * @param coveredText -
+    * @param concept     -
+    * @return the covered text plus preferred text if it exists and is not equal to the covered text
     */
-   static private String getPreferredText( final IdentifiedAnnotation annotation, final UmlsConcept concept ) {
-      final String cui = concept.getCui();
-      final String coveredText = annotation.getCoveredText().replace( '\r', ' ' ).replace( '\n', ' ' );
+   static private String getPreferredText( final String coveredText, final UmlsConcept concept ) {
       final String preferredText = concept.getPreferredText();
       if ( preferredText != null && !preferredText.isEmpty()
             && !preferredText.equalsIgnoreCase( coveredText )
             && !coveredText.equalsIgnoreCase( preferredText + 's' ) ) {
-         return cui + " : " + coveredText + " [" + preferredText + "]";
+         return " [" + preferredText + "]";
+      }
+      return "";
+   }
+
+
+   /**
+    * @param eventMention -
+    * @return a line of text with doctimerel if available
+    */
+   static private String getDocTimeRel( final EventMention eventMention ) {
+      final Event event = eventMention.getEvent();
+      if ( event == null ) {
+         return "";
+      }
+      final EventProperties eventProperties = event.getProperties();
+      if ( eventProperties == null ) {
+         return "";
+      }
+      final String dtr = eventProperties.getDocTimeRel();
+      if ( dtr == null || dtr.isEmpty() ) {
+         return "";
       }
-      return cui + " : " + coveredText;
+      return " [" + dtr.toLowerCase() + " doc time]";
    }
 
    /**
@@ -719,7 +737,6 @@ final public class HtmlTextWriter extend
    }
 
    /**
-    *
     * @param annotation -
     * @return polarity for a single annotation
     */
@@ -738,21 +755,11 @@ final public class HtmlTextWriter extend
    }
 
    /**
-    *
     * @param annotations -
-    * @return semantic names for given annotations
+    * @return tooltip text with semantic names for given annotations
     */
    static private String createTipText( final Collection<IdentifiedAnnotation> annotations ) {
-      final Map<String, Integer> semanticCounts = new HashMap<>();
-      for ( IdentifiedAnnotation annotation : annotations ) {
-         final Collection<UmlsConcept> concepts = OntologyConceptUtil.getUmlsConcepts( annotation );
-         for ( UmlsConcept concept : concepts ) {
-            final String semanticName = getSemanticName( annotation, concept );
-            semanticCounts.putIfAbsent( semanticName, 0 );
-            final int count = semanticCounts.get( semanticName );
-            semanticCounts.put( semanticName, count + 1 );
-         }
-      }
+      final Map<String, Integer> semanticCounts = getSemanticCounts( annotations );
       final List<String> semantics = new ArrayList<>( semanticCounts.keySet() );
       Collections.sort( semantics );
       final StringBuilder sb = new StringBuilder();
@@ -767,6 +774,44 @@ final public class HtmlTextWriter extend
       return sb.toString();
    }
 
+
+   /**
+    * @param annotations -
+    * @return counts of semantic types for annotations
+    */
+   static private Map<String, Integer> getSemanticCounts( final Collection<IdentifiedAnnotation> annotations ) {
+      // Check concepts with the same cui can have multiple tuis.  This can make it look like there are extra counts.
+      final Collection<String> usedCuis = new HashSet<>();
+      final Map<String, Integer> semanticCounts = new HashMap<>();
+      for ( IdentifiedAnnotation annotation : annotations ) {
+         final Collection<UmlsConcept> concepts = OntologyConceptUtil.getUmlsConcepts( annotation );
+         for ( UmlsConcept concept : concepts ) {
+            if ( !usedCuis.add( concept.getCui() ) ) {
+               continue;
+            }
+            final String semanticName = SemanticGroup.getSemanticName( annotation, concept );
+            semanticCounts.putIfAbsent( semanticName, 0 );
+            final int count = semanticCounts.get( semanticName );
+            semanticCounts.put( semanticName, count + 1 );
+         }
+         usedCuis.clear();
+         if ( concepts.isEmpty() ) {
+            String semanticName = "";
+            if ( annotation instanceof EventMention ) {
+               semanticName = SemanticGroup.EVENT_SEMANTIC;
+            } else if ( annotation instanceof TimeMention ) {
+               semanticName = SemanticGroup.TIMEX_SEMANTIC;
+            }
+            if ( !semanticName.isEmpty() ) {
+               semanticCounts.putIfAbsent( semanticName, 0 );
+               final int count = semanticCounts.get( semanticName );
+               semanticCounts.put( semanticName, count + 1 );
+            }
+         }
+      }
+      return semanticCounts;
+   }
+
    /**
     * writes html for right-hand annotation information panel
     * @param writer    writer to which pretty html for the section should be written
@@ -791,7 +836,9 @@ final public class HtmlTextWriter extend
             "    var fnd=dis.replace( /" + SemanticGroup.FINDING.getCode() + "/g,\"<b>Sign/ Symptom</b>\" );\n" +
             "    var prc=fnd.replace( /" + SemanticGroup.PROCEDURE.getCode() + "/g,\"<b>Procedure</b>\" );\n" +
             "    var drg=prc.replace( /" + SemanticGroup.MEDICATION.getCode() + "/g,\"<b>Medication</b>\" );\n" +
-            "    var unk=drg.replace( /" + SemanticGroup.UNKNOWN_SEMANTIC_CODE + "/g,\"<b>Unknown</b>\" );\n" +
+            "    var evt=drg.replace( /" + SemanticGroup.EVENT_CODE + "/g,\"<b>Event</b>\" );\n" +
+            "    var tmx=evt.replace( /" + SemanticGroup.TIMEX_CODE + "/g,\"<b>Time</b>\" );\n" +
+            "    var unk=tmx.replace( /" + SemanticGroup.UNKNOWN_SEMANTIC_CODE + "/g,\"<b>Unknown</b>\" );\n" +
             "    var prf1=unk.replace( /\\[/g,\"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>\" );\n" +
             "    var prf2=prf1.replace( /\\]/g,\"</i>\" );\n" +
             "    document.getElementById(\"ia\").innerHTML = prf2;\n" +

Modified: ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/plaintext/PrettyTextWriter.java
URL: http://svn.apache.org/viewvc/ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/plaintext/PrettyTextWriter.java?rev=1805587&r1=1805586&r2=1805587&view=diff
==============================================================================
--- ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/plaintext/PrettyTextWriter.java (original)
+++ ctakes/trunk/ctakes-core/src/main/java/org/apache/ctakes/core/cc/pretty/plaintext/PrettyTextWriter.java Sun Aug 20 23:19:04 2017
@@ -86,15 +86,6 @@ final public class PrettyTextWriter {
          outputFile = new File( _outputDirPath, docId + FILE_EXTENSION );
       }
       writeFile( jcas, outputFile.getPath() );
-//      try ( final BufferedWriter writer = new BufferedWriter( new FileWriter( outputFile ) ) ) {
-//         final Collection<Sentence> sentences = JCasUtil.select( jcas, Sentence.class );
-//         for ( Sentence sentence : sentences ) {
-//            writeSentence( jcas, sentence, writer );
-//         }
-//      } catch ( IOException ioE ) {
-//         LOGGER.error( "Could not not write pretty file " + outputFile.getPath() );
-//         LOGGER.error( ioE.getMessage() );
-//      }
       LOGGER.info( "Finished processing" );
    }
 
@@ -206,24 +197,16 @@ final public class PrettyTextWriter {
       final Map<Integer, Collection<ItemCell>> coveringAnnotationMap = new HashMap<>();
       for ( ItemCell itemCell : requiredCells ) {
          final Collection<ItemCell> coveredBaseItems = getCoveredBaseItems( itemCell.getTextSpan(), baseItemMap );
-         Collection<ItemCell> coveringAnnotations = coveringAnnotationMap.get( coveredBaseItems.size() );
-         if ( coveringAnnotations == null ) {
-            coveringAnnotations = new HashSet<>();
-            coveringAnnotationMap.put( coveredBaseItems.size(), coveringAnnotations );
-         }
-         coveringAnnotations.add( itemCell );
+         coveringAnnotationMap.putIfAbsent( coveredBaseItems.size(), new HashSet<>() );
+         coveringAnnotationMap.get( coveredBaseItems.size() ).add( itemCell );
       }
       for ( ItemCell itemCell : eventCells ) {
          if ( usedTextSpans.contains( itemCell.getTextSpan() ) ) {
             continue;
          }
          final Collection<ItemCell> coveredBaseItems = getCoveredBaseItems( itemCell.getTextSpan(), baseItemMap );
-         Collection<ItemCell> coveringAnnotations = coveringAnnotationMap.get( coveredBaseItems.size() );
-         if ( coveringAnnotations == null ) {
-            coveringAnnotations = new HashSet<>();
-            coveringAnnotationMap.put( coveredBaseItems.size(), coveringAnnotations );
-         }
-         coveringAnnotations.add( itemCell );
+         coveringAnnotationMap.putIfAbsent( coveredBaseItems.size(), new HashSet<>() );
+         coveringAnnotationMap.get( coveredBaseItems.size() ).add( itemCell );
       }
       return coveringAnnotationMap;
    }
@@ -421,17 +404,9 @@ final public class PrettyTextWriter {
       final Map<String, Collection<String>> semanticCuis = new HashMap<>();
       for ( UmlsConcept umlsConcept : umlsConcepts ) {
          final String cui = trimTo8( umlsConcept.getCui() );
-         final String tui = umlsConcept.getTui();
-         String semanticName = SemanticGroup.getSemanticName( tui );
-         if ( semanticName.equals( "Unknown" ) ) {
-            semanticName = trimTo8( identifiedAnnotation.getClass().getSimpleName() );
-         }
-         Collection<String> cuis = semanticCuis.get( semanticName );
-         if ( cuis == null ) {
-            cuis = new HashSet<>();
-            semanticCuis.put( semanticName, cuis );
-         }
-         cuis.add( cui );
+         String semanticName = SemanticGroup.getSemanticName( identifiedAnnotation, umlsConcept );
+         semanticCuis.putIfAbsent( semanticName, new HashSet<>() );
+         semanticCuis.get( semanticName ).add( cui );
       }
       return semanticCuis;
    }