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 2026/03/09 16:02:55 UTC

(ctakes) branch main updated: raised private to protected methods in AbstractTableFileWriter Improved add Date/Time methods in CalendarUtil Updated ctakes_types.py PatientMedTableFileWriter appends rows instead of one big write, outputs first mention doc time Added logging.basicConfig to pbj_pipeline.py and updated other pbj logging accordingly Update ZipFileTreeReader to use note type and dates in filenames if present

This is an automated email from the ASF dual-hosted git repository.

seanfinan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ctakes.git


The following commit(s) were added to refs/heads/main by this push:
     new 9f4590b  raised private to protected methods in AbstractTableFileWriter Improved add Date/Time methods in CalendarUtil Updated ctakes_types.py PatientMedTableFileWriter appends rows instead of one big write, outputs first mention doc time Added logging.basicConfig to pbj_pipeline.py and updated other pbj logging accordingly Update ZipFileTreeReader to use note type and dates in filenames if present
9f4590b is described below

commit 9f4590b721eb0727076d80c48a1c9ad232f8a2b6
Author: Sean Finan <se...@childrens.harvard.edu>
AuthorDate: Mon Mar 9 12:02:33 2026 -0400

    raised private to protected methods in AbstractTableFileWriter
    Improved add Date/Time methods in CalendarUtil
    Updated ctakes_types.py
    PatientMedTableFileWriter appends rows instead of one big write, outputs first mention doc time
    Added logging.basicConfig to pbj_pipeline.py and updated other pbj logging accordingly
    Update ZipFileTreeReader to use note type and dates in filenames if present
---
 .../ctakes/core/cc/AbstractTableFileWriter.java    |  22 +-
 .../ctakes/core/cc/PatientMedTableFileWriter.java  | 269 +++++++++++++++++----
 .../apache/ctakes/core/cr/ZipFileTreeReader.java   | 103 +++++---
 .../org/apache/ctakes/core/util/CalendarUtil.java  |  73 ++++--
 .../src/ctakes_pbj/component/pbj_dir_reader.py     |  22 +-
 .../src/ctakes_pbj/component/pbj_sender.py         |  10 +-
 .../src/ctakes_pbj/pbj_tools/stomp_receiver.py     |  15 +-
 .../src/ctakes_pbj/pipeline/pbj_pipeline.py        |  28 ++-
 .../src/ctakes_pbj/type_system/ctakes_types.py     |  25 +-
 .../ctakes_pbj/type_system/type_system_loader.py   |   3 +-
 .../org/apache/ctakes/pbj/types/TypeSystem.xml     | 218 ++++++++++++++---
 ctakes-ytex-uima/pom.xml                           |  40 +--
 12 files changed, 641 insertions(+), 187 deletions(-)

diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java
index f3aa157..f4d80c9 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java
@@ -149,6 +149,25 @@ abstract public class AbstractTableFileWriter
    protected void writeComplete( final List<List<String>> data ) {
    }
 
+   protected TableType getTableType() {
+      return Arrays.stream( TableType.values() )
+                   .filter( s -> s.name().equalsIgnoreCase( _tableType ) )
+                   .findFirst()
+                   .orElse( TableType.BSV );
+   }
+
+   // TODO - refactor up to AbstractFileWriter
+   protected File getOutputFile( final String outputDir,
+                                 final String documentId,
+                                 final String fileName ) {
+      final TableType tableType = Arrays.stream( TableType.values() )
+                                        .filter( s -> s.name()
+                                                       .equalsIgnoreCase( _tableType ) )
+                                        .findFirst()
+                                        .orElse( TableType.BSV );
+      return new File( outputDir, documentId + "_table." + tableType.name() );
+   }
+
    /**
     * {@inheritDoc}
     */
@@ -157,15 +176,14 @@ abstract public class AbstractTableFileWriter
                           final String outputDir,
                           final String documentId,
                           final String fileName ) throws IOException {
+      final File file = getOutputFile( outputDir, documentId, fileName );
       final TableType tableType = Arrays.stream( TableType.values() )
                                         .filter( s -> s.name()
                                                        .equalsIgnoreCase( _tableType ) )
                                         .findFirst()
                                         .orElse( TableType.BSV );
-      final File file = new File( outputDir, documentId + "_table." + tableType.name() );
       LOGGER.info( "Writing {} Table to {} ...", tableType.name(), file.getPath() );
       final String header = createTableHeader( tableType, getHeaderRow() );
-
       final String footer = createTableFooter( tableType, getFooterRow() );
       try ( Writer writer = new BufferedWriter( new FileWriter( file ) ) ) {
          writer.write( header );
diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java
index de85952..a6caca3 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java
@@ -3,16 +3,27 @@ package org.apache.ctakes.core.cc;
 import org.apache.ctakes.core.pipeline.PipeBitInfo;
 import org.apache.ctakes.core.util.annotation.IdentifiedAnnotationUtil;
 import org.apache.ctakes.core.util.doc.DocIdUtil;
+import org.apache.ctakes.core.util.doc.SourceMetadataUtil;
 import org.apache.ctakes.typesystem.type.structured.Patient;
+import org.apache.ctakes.typesystem.type.structured.SourceData;
 import org.apache.ctakes.typesystem.type.textsem.MedicationMention;
+import org.apache.uima.UimaContext;
 import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
+import org.apache.uima.fit.descriptor.ConfigurationParameter;
 import org.apache.uima.fit.util.JCasUtil;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.resource.ResourceInitializationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
+import java.io.*;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static org.apache.ctakes.core.pipeline.PipeBitInfo.TypeProduct.*;
 
@@ -32,9 +43,50 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
    // If you do not need to utilize the entire cas, or need more than the doc cas, consider AbstractFileWriter<T>. 
    static private final Logger LOGGER = LoggerFactory.getLogger( "PatientMedTableFileWriter" );
 
+   static public final String DATE_WRITE_FORMAT_PARAM = "DateWriteFormat";
+   static public final String DATE_WRITE_FORMAT_DESC = "A format to write dates.  e.g. dd-MM-yyyy_HH:mm:ss";
+   @ConfigurationParameter (
+         name = DATE_WRITE_FORMAT_PARAM,
+         description = DATE_WRITE_FORMAT_DESC,
+         defaultValue = "ddMMyyyykkmmss",
+         mandatory = false
+   )
+   private String _dateWriteFormat;
+
+   static public final String CAS_DATE_FORMAT_PARAM = "CasDateFormat";
+   static public final String CAS_DATE_FORMAT_DESC = "Set a value for parameter CasDateFormat.";
+   @ConfigurationParameter (
+         name = CAS_DATE_FORMAT_PARAM,
+         description = CAS_DATE_FORMAT_DESC,
+         defaultValue = "MMddyyyykkmmss",
+         mandatory = false
+   )
+   private String _casDateFormat;
+
+   private DateTimeFormatter _dateWriteFormatter;
+   private DateTimeFormatter _casDateFormatter;
+
    private int _patientDocCount = 0;
-   private final Map<String,PatientMed> _patientMeds = new HashMap<>();
-   private final Map<String,Integer> _patientMedCounts = new HashMap<>();
+//   private final Map<String,PatientMed> _patientMeds = new HashMap<>();
+//   private final Map<String,Integer> _patientMedCounts = new HashMap<>();
+   private boolean _isFirstWrite = true;
+
+   static private final LocalDateTime TODAY_DATE = LocalDateTime.now();
+   private String _runStartTime;
+
+   private MedCell _medCell;
+
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public void initialize( final UimaContext context ) throws ResourceInitializationException {
+      super.initialize( context );
+      _casDateFormatter = DateTimeFormatter.ofPattern( _casDateFormat );
+      _dateWriteFormatter = DateTimeFormatter.ofPattern( _dateWriteFormat );
+      _runStartTime = _casDateFormatter.format( OffsetDateTime.now() );
+   }
 
    /**
     * Add medication data from the cas to table rows.
@@ -42,11 +94,19 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
     */
    @Override
    public void process( final JCas jcas ) throws AnalysisEngineProcessException {
-      final List<List<String>> dataRows = createDataRows( jcas );
-      if ( dataRows.isEmpty() ) {
+      createData( jcas );
+      final List<List<String>> data = getData();
+      if ( data == null || data.isEmpty() ) {
+         // Not done with patient.
          return;
       }
-      dataRows.forEach( this::addDataRow );
+      // Done with patient, append data to file.
+      try {
+         appendFile( data, "", "", "", _isFirstWrite, false );
+      } catch ( IOException ioE ) {
+         throw new AnalysisEngineProcessException( ioE );
+      }
+      _isFirstWrite = false;
    }
 
    /**
@@ -55,11 +115,9 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
     */
    @Override
    public void collectionProcessComplete() throws AnalysisEngineProcessException {
-      setHeaderRow( createHeaderRow( null ) );
-      final List<List<String>> data = getData();
       try {
-         writeFile( data, getOutputDirectory( null, getRootDirectory(), null ), "PatientMedication", "" );
-         writeComplete( data );
+         appendFile( Collections.emptyList(), "", "", "", _isFirstWrite, true );
+         writeComplete( Collections.emptyList() );
       } catch ( IOException ioE ) {
          throw new AnalysisEngineProcessException( ioE );
       }
@@ -75,28 +133,52 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
       return getSimpleSubDirectory();
    }
 
+   // TODO - refactor up to AbstractFileWriter
+   protected File getOutputFile( final String outputDir,
+                                 final String documentId,
+                                 final String fileName ) {
+      final String simpleOutputDir = getOutputDirectory( null, getRootDirectory(), null );
+      return super.getOutputFile( simpleOutputDir, "PatientMedication_"+_runStartTime, "" );
+   }
+
    /**
-    * Patient ID, Medication Names, CUI, RNorm, NCI Cui, Count
     * {@inheritDoc}
     */
-   @Override
-   protected List<String> createHeaderRow( final JCas jCas ) {
-      return Arrays.asList(
-            " Patient ID ",
-            " Medication Names ",
-            " CUI ",
-            " RxNorm ",
-            " NCI Cui ",
-            " Count " );
+   public void appendFile( final List<List<String>> dataRows,
+                          final String outputDir,
+                          final String documentId,
+                          final String fileName,
+                           final boolean writeHeader,
+                           final boolean writeFooter ) throws IOException {
+      final TableType tableType = getTableType();
+      final File file = getOutputFile( outputDir, documentId, fileName );
+      LOGGER.info( "Appending {} Table to {} ...", tableType.name(), file.getPath() );
+      try ( Writer writer = new BufferedWriter( new FileWriter( file, true ) ) ) {
+         if ( writeHeader ) {
+            final String header = createTableHeader( tableType, getHeaderRow() );
+            writer.write( header );
+         }
+         for ( List<String> dataRow : dataRows ) {
+            final String row = createTableRow( tableType, dataRow );
+            writer.write( row );
+         }
+         if ( writeFooter ) {
+            final String footer = createTableFooter( tableType, getFooterRow() );
+            writer.write( footer );
+         }
+      }
    }
 
    /**
-    * Does nothing.
-    * @param jCas the jcas passed to the process( jcas ) method.
+    * Patient ID, Medication Names, CUI, RNorm, NCI Cui, Count
+    * {@inheritDoc}
     */
    @Override
-   protected void createData( final JCas jCas ) {
-      return;
+   protected List<String> createHeaderRow( final JCas jCas ) {
+      return Arrays.asList(
+            " Patient ID ",
+            " Medications (Name, [CUIs], [RxNorms], [NCI Cuis], earliest evidence ddMMyyyy240000, count) ",
+            " document count " );
    }
 
    /**
@@ -112,14 +194,18 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
          LOGGER.error( "No Patient for doc {}", DocIdUtil.getDocumentID( jCas ) );
          System.exit( -1 );
       }
-
+      final LocalDateTime docDate = getDocDate( jCas );
+      if ( _medCell == null ) {
+         _medCell = new MedCell();
+      }
       // Get the medication mentions,
       // turn each medication mention into a PatientMedRecord,
       // add each PatientMedRecord to the map (uniquely), increasing a count of identical meds.
       for ( MedicationMention med : JCasUtil.select( jCas, MedicationMention.class ) ) {
-         final String name = IdentifiedAnnotationUtil.getPreferredText( med );
-         _patientMeds.put( name, new PatientMed( med ) );
-         _patientMedCounts.merge( name, 1, Integer::sum );
+         _medCell.update( new PatientMed( med ), docDate );
+//         final String name = IdentifiedAnnotationUtil.getPreferredText( med );
+//         _patientMeds.put( name, new PatientMed( med ) );
+//         _patientMedCounts.merge( name, 1, Integer::sum );
       }
       // Increase the internal count of documents processed.
       _patientDocCount++;
@@ -133,6 +219,25 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
       return Collections.singletonList( createTableRow( patient.getPatientIdentifier() ) );
    }
 
+   private LocalDateTime getDocDate( final JCas jCas ) {
+      final SourceData sourceData = SourceMetadataUtil.getOrCreateSourceData( jCas );
+      String casDate = sourceData.getSourceRevisionDate();
+      if ( casDate == null || casDate.isEmpty() ) {
+         casDate = sourceData.getSourceOriginalDate();
+      }
+      if ( casDate == null || casDate.isEmpty() ) {
+         return TODAY_DATE;
+      }
+//            LOGGER.info( "Cas Date " + casDate + "  Run Start " + _runStartTime );
+      LocalDateTime dateTime;
+      try {
+         dateTime = LocalDateTime.parse( casDate, _casDateFormatter );
+      } catch ( DateTimeParseException dtpE ) {
+         final LocalDate date = LocalDate.parse( casDate, _casDateFormatter );
+         dateTime = date.atStartOfDay();
+      }
+      return dateTime;
+   }
 
    /**
     * Create single table row with information from all PatientMeds.
@@ -140,30 +245,36 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
     * @return -
     */
    private List<String> createTableRow( final String patientId ) {
-      final List<String> names
-            = _patientMeds.keySet().stream()
-                          .sorted( String.CASE_INSENSITIVE_ORDER )
-                          .toList();
-      final StringBuilder prefTexts = new StringBuilder();
-      final StringBuilder cuis = new StringBuilder();
-      final StringBuilder rxnorms = new StringBuilder();
-      final StringBuilder nciCuis = new StringBuilder();
-      final StringBuilder counts = new StringBuilder();
-      for ( String name : names ) {
-         PatientMed med = _patientMeds.get( name );
-         prefTexts.append( name ).append( ";" );
-         cuis.append( med.cuis ).append( ";" );
-         rxnorms.append( med.rxnorms ).append( ";" );
-         nciCuis.append( med.nciCuis ).append( ";" );
-         counts.append( _patientMedCounts.get( name ) ).append( ";" );
+      if ( _medCell == null ) {
+         return Arrays.asList( patientId, "", ""+_patientDocCount );
       }
-      return Arrays.asList(
-            patientId,
-            prefTexts.toString(),
-            cuis.toString(),
-            rxnorms.toString(),
-            nciCuis.toString(),
-            counts.toString() );
+      final String cell = _medCell.getCell();
+      _medCell = null;
+      return Arrays.asList( patientId, cell, ""+_patientDocCount );
+//      final List<String> names
+//            = _patientMeds.keySet().stream()
+//                          .sorted( String.CASE_INSENSITIVE_ORDER )
+//                          .toList();
+//      final StringBuilder prefTexts = new StringBuilder();
+//      final StringBuilder cuis = new StringBuilder();
+//      final StringBuilder rxnorms = new StringBuilder();
+//      final StringBuilder nciCuis = new StringBuilder();
+//      final StringBuilder counts = new StringBuilder();
+//      for ( String name : names ) {
+//         PatientMed med = _patientMeds.get( name );
+//         prefTexts.append( name ).append( ";" );
+//         cuis.append( med.cuis ).append( ";" );
+//         rxnorms.append( med.rxnorms ).append( ";" );
+//         nciCuis.append( med.nciCuis ).append( ";" );
+//         counts.append( _patientMedCounts.get( name ) ).append( ";" );
+//      }
+//      return Arrays.asList(
+//            patientId,
+//            prefTexts.toString(),
+//            cuis.toString(),
+//            rxnorms.toString(),
+//            nciCuis.toString(),
+//            counts.toString() );
    }
 
 
@@ -181,14 +292,66 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
     * @param rxnorms -
     * @param nciCuis -
     */
-   private record PatientMed( List<String> cuis,
+   private record PatientMed( String name,
+                              List<String> cuis,
                               List<String> rxnorms,
                               List<String> nciCuis ) {
       private PatientMed( final MedicationMention med ) {
-         this( toSortedList( IdentifiedAnnotationUtil.getCuis( med ) ),
+         this( IdentifiedAnnotationUtil.getPreferredText( med ),
+               toSortedList( IdentifiedAnnotationUtil.getCuis( med ) ),
                toSortedList( IdentifiedAnnotationUtil.getCodes( med, "RXNORM" ) ),
                toSortedList( IdentifiedAnnotationUtil.getCodes( med, "NCI" ) ) );
       }
    }
 
+
+   private class MedCell {
+      final private Map<String, LocalDateTime> _nameDateMap = new HashMap<>();
+      final private Map<String, PatientMed> _nameMedMap = new HashMap<>();
+      private final Map<String,Integer> _nameCounts = new HashMap<>();
+
+      private void update( final Collection<PatientMed> patientMeds, final LocalDateTime docDate ) {
+         patientMeds.forEach( m -> update( m, docDate ) );
+      }
+
+      private void update( final PatientMed patientMed , final LocalDateTime docDate ) {
+         final String name = patientMed.name();
+         final LocalDateTime statusDate = _nameDateMap.get( name );
+         if ( statusDate == null ) {
+            _nameDateMap.put( name, docDate );
+            _nameMedMap.put( name, patientMed );
+         } else if ( docDate.isBefore( statusDate ) ) {
+            _nameDateMap.put( name, docDate );
+         }
+         _nameCounts.merge( name, 1, Integer::sum );
+      }
+
+      private boolean hasInfo() {
+         return !_nameDateMap.isEmpty();
+      }
+
+      private String getCell() {
+         return _nameMedMap.keySet()
+                        .stream()
+                        .sorted()
+                        .map( this::getValueCell )
+                        .collect( Collectors.joining( ";" ) );
+      }
+
+      private String getValueCell( final String name ) {
+         final LocalDateTime date = _nameDateMap.get( name );
+         if ( date == null ) {
+            return "";
+         }
+         PatientMed med = _nameMedMap.get( name );
+         return name + ',' +
+               med.cuis() + ',' +
+               med.rxnorms() + ',' +
+               med.nciCuis() + ',' +
+               date.format( _dateWriteFormatter ) + ',' +
+               _nameCounts.get( name );
+      }
+   }
+
+
 }
\ No newline at end of file
diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java b/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java
index 2a8656b..e82ea3e 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java
@@ -3,9 +3,7 @@ package org.apache.ctakes.core.cr;
 import org.apache.ctakes.core.patient.PatientNoteStore;
 import org.apache.ctakes.core.pipeline.PipeBitInfo;
 import org.apache.ctakes.core.pipeline.ProgressManager;
-import org.apache.ctakes.core.util.AeParamUtil;
-import org.apache.ctakes.core.util.BannerWriter;
-import org.apache.ctakes.core.util.NumberedSuffixComparator;
+import org.apache.ctakes.core.util.*;
 import org.apache.ctakes.core.util.doc.DocIdUtil;
 import org.apache.ctakes.core.util.doc.JCasBuilder;
 import org.apache.ctakes.core.util.doc.SourceMetadataUtil;
@@ -23,11 +21,11 @@ import org.slf4j.LoggerFactory;
 import java.io.*;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
 import java.util.*;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -62,17 +60,15 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
    )
    private String _patientListPath;
 
-//   static public final String DATE_FORMAT_PARAM = "DateFormat";
-//   static public final String DATE_FORMAT_DESC = "A format to parse dates.  e.g. dd-MM-yyyy_HH:mm:ss";
-//   @ConfigurationParameter (
-//         name = DATE_FORMAT_PARAM,
-//         description = DATE_FORMAT_DESC,
-//         defaultValue = "yyyyMMdd",
-//         mandatory = false
-//   )
-//   private String _dateFormat;
-//
-//   private DateTimeFormatter _dateFormatter;
+   static public final String FILE_DATE_FORMAT_PARAM = "FileDateFormat";
+   static public final String FILE_DATE_FORMAT_DESC = "A format to parse date from a filename.  e.g. dd-MM-yyyy_HH:mm:ss";
+   @ConfigurationParameter (
+         name = FILE_DATE_FORMAT_PARAM,
+         description = FILE_DATE_FORMAT_DESC,
+         defaultValue = "yyyyMMdd",
+         mandatory = false
+   )
+   private String _fileDateFormat;
 
    static public final String CAS_DATE_FORMAT_PARAM = "CasDateFormat";
    static public final String CAS_DATE_FORMAT_DESC = "Set a value for parameter CasDateFormat.";
@@ -84,7 +80,11 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
    )
    private String _casDateFormat;
 
+   private DateTimeFormatter _fileDateFormatter;
    private DateTimeFormatter _casDateFormatter;
+   private final String SHORT_DATE_FORMAT = "yyMMdd";
+   private final DateTimeFormatter SHORT_DATE_FORMATTER = DateTimeFormatter.ofPattern( SHORT_DATE_FORMAT );
+   private final LocalDateTime RUN_START_DT = LocalDateTime.now();
 
 
    private boolean _writeBanner_ = false;
@@ -114,7 +114,7 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
    @Override
    public void initialize( final UimaContext context ) throws ResourceInitializationException {
       super.initialize( context );
-//      _dateFormatter = DateTimeFormatter.ofPattern( _dateFormat );
+      _fileDateFormatter = DateTimeFormatter.ofPattern( _fileDateFormat );
       _casDateFormatter = DateTimeFormatter.ofPattern( _casDateFormat );
       // TODO - for zipPatientLevel in the zip getPatient just get the dir at that level.
       final Object zipPatientLevel = context.getConfigParameterValue( PATIENT_LEVEL );
@@ -139,6 +139,13 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
       // Get rid of patients named after source subdirectories.
       final Collection<String> subDirPatients = PatientNoteStore.getInstance().getStoredPatientIds();
       subDirPatients.forEach( PatientNoteStore.getInstance()::removePatient );
+      if ( !SHORT_DATE_FORMAT.equals( _fileDateFormat ) ) {
+         CalendarUtil.addDateFormat( _fileDateFormat );
+      }
+      if ( !SHORT_DATE_FORMAT.equals( _casDateFormat ) ) {
+      CalendarUtil.addDateTimeFormat( _casDateFormat );
+      }
+      CalendarUtil.addDateFormat( SHORT_DATE_FORMAT );
    }
 
    // TODO move to super class
@@ -455,6 +462,7 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
          final String idPrefix = createDocumentIdPrefix( entryFile, getRootDir() );
          final String docType = createDocumentType( id );
          final String docTime = createDocumentTime( entry );
+         final Calendar creationDate = CalendarUtil.getCalendar( docTime );
          final String patientId = getPatientId( entry );
          return new JCasBuilder()
                .setCorpusName( getCorpusName() )
@@ -466,6 +474,7 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
                .setDocIdPrefix( idPrefix )
                .setDocType( docType )
                .setDocTime( docTime )
+               .setDocCreationDate( creationDate )
                .setDocPath( entryPath )
                .nullDocText();
       } catch ( IOException ioE ) {
@@ -542,15 +551,16 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
       return file.getParent();
    }
 
-
-   /**
-    * @param entry -
-    * @return the file's last modification date as a string : {@link #getDateFormat()}
-    */
-   protected String createDocumentTime( final ZipEntry entry ) {
-      return createDocumentTime( entry.getTime() );
+   protected String createDocumentType( final String documentId ) {
+      final String[] splits = StringUtil.fastSplit( documentId, '-' );
+      if  ( splits.length == 4 ) {
+         return splits[ 2 ];
+      }
+      return super.createDocumentType( documentId );
    }
 
+
+
    // TODO move to abstract reader
 
    /**
@@ -558,31 +568,54 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
     */
    @Override
    public DateFormat getDateFormat() {
-//      return new SimpleDateFormat( _dateFormat );
       return new SimpleDateFormat( _casDateFormat );
    }
 
 
-   protected String createDocumentTime( final LocalDate date ) {
-      return _casDateFormatter.format( date );
-   }
-
    protected String createDocumentTime( final LocalDateTime dateTime ) {
       return _casDateFormatter.format( dateTime );
    }
 
    /**
-    * @param millis -
+    * @param entry -
     * @return the file's last modification date as a string : {@link #getDateFormat()}
     */
-   // TODO move to super class
-   protected String createDocumentTime( final long millis ) {
-//      _dateFormatter = DateTimeFormatter.ofPattern( _dateFormat );
-//      return _dateFormatter.format(
-      return _casDateFormatter.format(
-            LocalDateTime.ofInstant( Instant.ofEpochMilli( millis ), ZONE_ID ) );
+   protected String createDocumentTime( final ZipEntry entry ) {
+      final File entryFile = new File( entry.getName() );
+      final String entryName = entryFile.getName();
+      final String[] extSplits = StringUtil.fastSplit( entryName, '.' );
+      final String[] splits = StringUtil.fastSplit( extSplits[ 0 ], '-' );
+      if ( splits.length == 4 ) {
+         final LocalDateTime ldt = getLocalDateTime( splits[ 3 ] );
+         return createDocumentTime( ldt );
+      }
+      return createDocumentTime( RUN_START_DT );
    }
 
+   // TODO move to abstract reader
+
+   private LocalDateTime getLocalDateTime( final String dateText ) {
+      LocalDate date = null;
+      if ( dateText.length() == 8 ) {
+         try {
+            date = LocalDate.parse( dateText, _fileDateFormatter );
+         } catch ( DateTimeParseException dtpE ) {
+            LOGGER.warn( "Bad File date {} {}", _fileDateFormat, dateText );
+         }
+      } else if ( dateText.length() == 6 ) {
+         try {
+            date = LocalDate.parse( dateText, SHORT_DATE_FORMATTER );
+         } catch ( DateTimeParseException dtpE ) {
+            LOGGER.warn( "Bad File short date {} {}", SHORT_DATE_FORMAT, dateText );
+         }
+      } else {
+         LOGGER.warn( "Bad File date length {}", dateText );
+      }
+      if ( date != null ) {
+         return date.atStartOfDay();
+      }
+      return RUN_START_DT;
+   }
 
 
 }
\ No newline at end of file
diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java b/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java
index 544e5e4..109b0c9 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java
@@ -69,26 +69,71 @@ final public class CalendarUtil {
          = new IdentifiedAnnotationBuilder().creator( TimeMention::new )
                                             .type( SemanticTui.T079 );
 
-   static {
+   static  {
       for ( String date : DATE_FORMAT_CODES ) {
-         DATE_FORMATS.add( new SimpleDateFormat( date ) );
-         DATE_FORMATS.add( new SimpleDateFormat( "EEE " + date ) );
-         DATE_FORMATS.add( new SimpleDateFormat( "EEE, " + date ) );
+         addDateFormats( date );
          for ( String time : TIME_FORMAT_CODES ) {
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " " + time ) );
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " 'at' " + time ) );
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE " + date + " " + time ) );
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE, " + date + " 'at' " + time ) );
-
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " " + date ) );
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' " + date ) );
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( time + ", EEE " + date ) );
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE " + date ) );
-            DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE, " + date ) );
+            addDateTimeFormats( date, time );
          }
       }
    }
 
+   static private void addDateFormats( final String date ) {
+      DATE_FORMATS.add( new SimpleDateFormat( date ) );
+      DATE_FORMATS.add( new SimpleDateFormat( "EEE " + date ) );
+      DATE_FORMATS.add( new SimpleDateFormat( "EEE, " + date ) );
+   }
+
+   static private void addTimeFormats( final String time ) {
+      for ( String date : DATE_FORMAT_CODES ) {
+         addDateTimeFormats( date, time );
+      }
+   }
+
+
+   static private void addDateTimeFormats( final String date, final String time ) {
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " " + time ) );
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " 'at' " + time ) );
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE " + date + " " + time ) );
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE, " + date + " 'at' " + time ) );
+
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " " + date ) );
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' " + date ) );
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( time + ", EEE " + date ) );
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE " + date ) );
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE, " + date ) );
+   }
+
+
+   /**
+    * To normalize date and time expressions, a number of date and time formats are tested.
+    * This will add a date format to the known list of date and time expressions.
+    * @param dateFormat for SimpleDateFormat to apply for normalization.
+    */
+   static public void addDateFormat( final String dateFormat ) {
+      addDateFormats( dateFormat );
+      for ( String time : TIME_FORMAT_CODES ) {
+         addDateTimeFormats( dateFormat, time );
+      }
+   }
+
+   /**
+    * To normalize date and time expressions, a number of date and time formats are tested.
+    * This will add a time format to the known list of date and time expressions.
+    * @param timeFormat for SimpleDateFormat to apply for normalization.
+    */
+   static public void addTimeFormat( final String timeFormat ) {
+      addTimeFormats( timeFormat );
+   }
+
+   /**
+    * To normalize date and time expressions, a number of date and time formats are tested.
+    * This will add a date and time format to the known list of date and time expressions.
+    * @param dateTimeFormat for SimpleDateFormat to apply for normalization.
+    */
+   static public void addDateTimeFormat( final String dateTimeFormat ) {
+      DATE_TIME_FORMATS.add( new SimpleDateFormat( dateTimeFormat ) );
+   }
 
    /**
     * @param jCas  ye olde ...
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py
index 14b75ce..d3d65c8 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py
@@ -1,7 +1,7 @@
-import sys
 import os
 from ctakes_pbj.component.collection_reader import CollectionReader
 from ctakes_pbj.type_system.type_system_loader import *
+from cassis import Cas
 
 import logging
 
@@ -13,6 +13,7 @@ class PBJDirReader(CollectionReader):
 
     def __init__(self):
         self.input_dir = None
+        self.typesystem = None
         self.pipeline = None
 
     # Set the pipeline.  The collection reader controls the pipeline flow.
@@ -36,6 +37,7 @@ def init_params(self, args):
 
     # Called start reading cas objects and pass them to the pipeline.
     def start(self):
+        logger.info(f"Starting Directory Reader on {self.input_dir}...")
         for filename in os.listdir(self.input_dir):
             filepath = os.path.join(self.input_dir, filename)
             if os.path.isfile(filepath):
@@ -46,3 +48,21 @@ def start(self):
                         document_language="en",
                         typesystem=self.get_typesystem())
                     self.pipeline.process(cas)
+        logger.info(f"Finished reading {self.input_dir}.")
+        self.stop()
+
+    # Called to stop reading.
+    def stop(self):
+        # logger.info("%s PBJ Dir Reader: Stopping Pipeline ...", time.ctime())
+        self.pipeline.collection_process_complete()
+
+    def set_typesystem(self, typesystem):
+        self.typesystem = typesystem
+
+    def get_typesystem(self):
+        if self.typesystem is None:
+            # Load the typesystem
+            type_system_accessor = TypeSystemLoader()
+            type_system_accessor.load_type_system()
+            self.set_typesystem(type_system_accessor.get_type_system())
+        return self.typesystem
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py
index 3547d98..ca715a9 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py
@@ -1,5 +1,4 @@
 import sys
-import time
 import stomp
 import logging
 
@@ -43,7 +42,7 @@ def init_params(self, args):
 
     # Called once at the beginning of a pipeline.
     def initialize(self):
-        logger.info(f"{time.ctime()} Starting PBJ Sender on {self.host} {self.queue} ...")
+        logger.info(f"Starting PBJ Sender on {self.host} {self.queue} ...")
         # Use a heartbeat of 10 minutes  (in milliseconds)
         self.conn = stomp.Connection12([(self.host, self.port)],
                                        keepalive=True, heartbeats=(600000, 600000))
@@ -51,8 +50,7 @@ def initialize(self):
 
     # Called for every cas passed through the pipeline.
     def process(self, cas):
-        logger.info(time.ctime(), "Sending processed information to",
-              self.host, self.queue, "...")
+        logger.info(f"Sending processed information to {self.host} {self.queue}...")
         xmi = cas.to_xmi()
         self.conn.send(self.queue, xmi)
 
@@ -68,10 +66,10 @@ def send_text(self, text):
         self.conn.send(self.queue, text)
 
     def send_stop(self):
-        logger.info(f"{time.ctime()} Sending Stop code to {self.host} {self.queue} ...")
+        logger.info(f"Sending Stop code to {self.host} {self.queue} ...")
         self.conn.send(self.queue, STOP_MESSAGE)
         self.conn.disconnect()
-        logger.info(f"{time.ctime()} Disconnected PBJ Sender on self.host self.queue")
+        logger.info(f"Disconnected PBJ Sender on {self.host} {self.queue}.")
 
     def set_host(self, host_name):
         self.host = host_name
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py
index 99bf635..271b2ee 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py
@@ -1,4 +1,3 @@
-import time
 import threading
 from threading import Event
 import logging
@@ -65,7 +64,7 @@ def __init__(self, pipeline, queue_name, host_name, port_name, password, usernam
         # self.__connect_and_subscribe()
 
     def start_receiver(self):
-        logger.info(f"{time.ctime()} Starting Stomp Receiver on f{self.source_host} f{self.source_queue} ...")
+        logger.info(f"Starting Stomp Receiver on {self.source_host} {self.source_queue} ...")
         # Use a heartbeat of 10 minutes  (in milliseconds)
         self.conn = stomp.Connection12([(self.source_host, self.source_port)],
                                        keepalive=True, heartbeats=(600000, 600000))
@@ -98,11 +97,11 @@ def set_stop(self, stop):
 
     def stop_receiver(self):
         self.stop = True
-        logger.info(f"{time.ctime()} Disconnecting Stomp Receiver on f{self.source_host} f{self.source_queue} ...")
+        logger.info(f"Disconnecting Stomp Receiver on {self.source_host} {self.source_queue} ...")
         self.conn.disconnect()
-        logger.info(f"{time.ctime()} Stomp Receiver disconnected.")
+        logger.info(" Stomp Receiver disconnected.")
         self.conn.unsubscribe(destination=self.source_queue, id=self.r_id)
-        logger.info(f"{time.ctime()} Stomp Receiver unsubscribed.")
+        logger.info("Stomp Receiver unsubscribed.")
         # self.conn.disconnect()
         # print(time.ctime((time.time())), "Stomp Receiver disconnected.")
         if self.completed:
@@ -110,7 +109,7 @@ def stop_receiver(self):
 
     def on_message(self, frame):
         if frame.body == STOP_MESSAGE:
-            logger.info(f"{time.ctime()} Received Stop code.")
+            logger.info("Received Stop code.")
             # self.stop = True
             # time.sleep(3)
             self.completed = True
@@ -120,14 +119,14 @@ def on_message(self, frame):
                 cas = cassis.load_cas_from_xmi(frame.body, self.get_typesystem())
                 self.pipeline.process(cas)
             else:
-                logger.error(f"{time.ctime()} Malformed Message: f{frame.body}")
+                logger.error(f"Malformed Message: {frame.body}")
 
     def on_disconnected(self):
         if not self.stop:
             self.__connect_and_subscribe()
 
     def on_error(self, frame):
-        logger.error(f"{time.ctime()} Receiver Error: f{frame.body}")
+        logger.error(f"Receiver Error: {frame.body}")
 
     # Called when an exception is thrown.
     def handle_exception(self):
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py
index 6b9dd06..1d5f3dc 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py
@@ -1,5 +1,4 @@
 import sys
-import time
 import traceback
 from traceback import TracebackException
 from threading import Event
@@ -10,6 +9,13 @@
 
 exit_event = Event()
 
+# Configure logging here...
+logging.basicConfig(
+    level=logging.INFO,
+    format="%(asctime)s %(name)s - %(levelname)s: %(message)s",
+    datefmt='%m/%d/%Y %I:%M:%S %p'
+)
+
 logger = logging.getLogger(__name__)
 
 class PBJPipeline:
@@ -55,7 +61,7 @@ def initialize(self):
             if exit_event.is_set():
                 break
             try:
-                logger.info(f"{time.ctime()} Initializing f{type(annotator).__name__}... ")
+                logger.info(f"Initializing {type(annotator).__name__}... ")
                 annotator.initialize()
             except Exception as exceptable:
                 self.handle_exception(annotator, exceptable, True)
@@ -66,7 +72,7 @@ def run(self):
         if not self.initialized:
             self.initialize()
         try:
-            logger.info(f"{time.ctime()} Starting f{type(self.c_reader).__name__}...")
+            logger.info(f"Starting {type(self.c_reader).__name__}...")
             self.c_reader.start()
         except Exception as exceptable:
             self.handle_exception(self.c_reader, exceptable)
@@ -81,42 +87,42 @@ def process(self, cas):
             if exit_event.is_set():
                 break
             try:
-                logger.info(f"{time.ctime()} Running  f{type(annotator).__name__}...")
+                logger.info(f"Running  {type(annotator).__name__}...")
                 annotator.process(cas)
             except Exception as exceptable:
                 self.handle_exception(annotator, exceptable)
 
     # At the end of the corpus, call each annotator for cleanup, etc.
     def collection_process_complete(self):
-        logger.info(f"{time.ctime()} Collection processing complete.")
+        logger.info("Collection processing complete.")
         for annotator in self.annotators:
             if exit_event.is_set():
                 break
             try:
-                logger.info(f"{time.ctime()} Notifying f{type(annotator).__name__} of completion ...")
+                logger.info(f"Notifying {type(annotator).__name__} of completion ...")
                 annotator.collection_process_complete()
             except Exception as exceptable:
                 self.handle_exception(annotator, exceptable)
-        logger.info(f"{time.ctime()} Done.")
+        logger.info("Done.")
         exit_event.set()
 
     def handle_exception(self, thrower, exceptable, initializing=False):
-        logger.info(f"{time.ctime()} Exception thrown in f{type(thrower).__name__} : f{type(exceptable).__name__} exceptable")
+        logger.info(f"Exception thrown in {type(thrower).__name__} : {type(exceptable).__name__} exceptable")
         # print(TracebackException.from_exception(exceptable, limit=-3, capture_locals=True))
         traceback.print_exc(limit=3, chain=False)
         # Print nice output regarding the exception.
         try:
-            logger.info(f"{time.ctime()} Notifying f{type(self.c_reader).__name__} of exception ...")
+            logger.info(f"Notifying {type(self.c_reader).__name__} of exception ...")
             self.c_reader.handle_exception(thrower, exceptable)
         except Exception as exceptable_2:
             traceback.print_exc(limit=3, chain=False)
         # Distribute handling of exceptions.
         for annotator in self.annotators:
             try:
-                logger.info(f"{time.ctime()} Notifying f{type(annotator).__name__} of exception ...")
+                logger.info(f"Notifying {type(annotator).__name__} of exception ...")
                 annotator.handle_exception(thrower, exceptable, initializing)
             except Exception as exceptable_2:
                 traceback.print_exc(limit=3, chain=False)
-        logger.info(f"{time.ctime()} Done.")
+        logger.info("Done.")
         # sys.exit(1)
         exit_event.set()
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py
index 1ffd6e7..a30206e 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py
@@ -160,9 +160,22 @@
 LabMention = 'org.apache.ctakes.typesystem.type.textsem.LabMention'
 Markable = 'org.apache.ctakes.typesystem.type.textsem.Markable'
 CollectionTextRelationIdentifiedAnnotationRelation = 'org.apache.ctakes.typesystem.type.relation.CollectionTextRelationIdentifiedAnnotationRelation'
-# for RT
-DoseModifier = "org.apache.ctakes.typesystem.type.textsem.DoseModifier"
-DosageCountModifier = "org.apache.ctakes.typesystem.type.textsem.DosageCountModifier"
-TotalDosageModifier = "org.apache.ctakes.typesystem.type.textsem.TotalDoseModifier"
-FrequencyModifier = "org.apache.ctakes.typesystem.type.textsem.FrequencyModifier"
-StatusChangeModifier = "org.apache.ctakes.typesystem.type.textsem.StatusChangeModifier"
\ No newline at end of file
+# 03/09/2026
+Patient='org.apache.ctakes.typesystem.type.structured.Patient'
+Corpus='org.apache.ctakes.typesystem.type.structured.Corpus'
+Dose='org.apache.ctakes.typesystem.type.refsem.Dose'
+TotalDose='org.apache.ctakes.typesystem.type.refsem.TotalDose'
+Form='org.apache.ctakes.typesystem.type.refsem.Form'
+Route='org.apache.ctakes.typesystem.type.refsem.Route'
+Frequency='org.apache.ctakes.typesystem.type.refsem.Frequency'
+Duration='org.apache.ctakes.typesystem.type.refsem.Duration'
+StatusChange='org.apache.ctakes.typesystem.type.refsem.StatusChange'
+DoseModifier='org.apache.ctakes.typesystem.type.textsem.DoseModifier'
+TotalDoseModifier='org.apache.ctakes.typesystem.type.textsem.TotalDoseModifier'
+DosageCountModifier='org.apache.ctakes.typesystem.type.textsem.DosageCountModifier'
+FormModifier='org.apache.ctakes.typesystem.type.textsem.FormModifier'
+RouteModifier='org.apache.ctakes.typesystem.type.textsem.RouteModifier'
+FrequencyModifier='org.apache.ctakes.typesystem.type.textsem.FrequencyModifier'
+DurationModifier='org.apache.ctakes.typesystem.type.textsem.DurationModifier'
+StatusChangeModifier='org.apache.ctakes.typesystem.type.textsem.StatusChangeModifier'
+Episode='org.apache.ctakes.typesystem.type.textspan.Episode'
\ No newline at end of file
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py
index 6c38893..b04117b 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py
@@ -1,6 +1,7 @@
 import cassis
 XMI_INDICATOR = "xmlns:xmi"
-CTAKES_TYPE_SYSTEM = "resources/org/apache/ctakes/pbj/types/TypeSystem.xml"
+# CTAKES_TYPE_SYSTEM = "resources/org/apache/ctakes/pbj/types/TypeSystem.xml"
+CTAKES_TYPE_SYSTEM = "resources/org/apache/ctakes/typesystem/types/TypeSystem.xml"
 
 
 class TypeSystemLoader:
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml
index b3fc587..56eabf7 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml
@@ -271,6 +271,7 @@ Equivalent to cTAKES: edu.mayo.bmi.uima.core.type.SymbolToken</description>
       <supertypeName>org.apache.ctakes.typesystem.type.syntax.BaseToken</supertypeName>
     </typeDescription>
     <typeDescription>
+    <!-- Deprecate. Same as parent type OntologyConcept.  CUI = code.  TUI = code.  Not good anyway, concepts can have >1 TUI.  -->
       <name>org.apache.ctakes.typesystem.type.refsem.UmlsConcept</name>
       <description>Concepts in the Unified Medical Language System (UMLS) Metathesaurus have a concept unique identifier (CUI) and a type unique identifier (TUI, i.e., semantic type) which are curated, normalized codes. For example, "pain" would have a cui=C0030193 and tui=T184.
 Equivalent to cTAKES: edu.mayo.bmi.uima.core.type.UmlsConcept</description>
@@ -1040,6 +1041,11 @@ More qualifying information on how the procedure was done.</description>
           <rangeTypeName>uima.cas.FSArray</rangeTypeName>
           <elementType>org.apache.ctakes.typesystem.type.textsem.IdentifiedAnnotation</elementType>
         </featureDescription>
+        <featureDescription>
+          <name>textRepresentation</name>
+          <description>Plain text representation of the Element. Useful when no mentions are associated and normalization cannot be performed.</description>
+          <rangeTypeName>uima.cas.String</rangeTypeName>
+        </featureDescription>
         <featureDescription>
           <name>discoveryTechnique</name>
           <description/>
@@ -1087,6 +1093,36 @@ More qualifying information on how the procedure was done.</description>
       <description>A normalized form for Time annotations.  Inherits from Element, but some fields may be unused.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.refsem.Element</supertypeName>
       <features>
+          <featureDescription>
+              <name>hour</name>
+              <description/>
+              <rangeTypeName>uima.cas.String</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>minute</name>
+              <description/>
+              <rangeTypeName>uima.cas.String</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>second</name>
+              <description/>
+              <rangeTypeName>uima.cas.String</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>hourValue</name>
+              <description/>
+              <rangeTypeName>uima.cas.Integer</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>minuteValue</name>
+              <description/>
+              <rangeTypeName>uima.cas.Integer</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>secondValue</name>
+              <description/>
+              <rangeTypeName>uima.cas.Integer</rangeTypeName>
+          </featureDescription>
         <featureDescription>
           <name>normalizedForm</name>
           <description/>
@@ -1114,6 +1150,21 @@ More qualifying information on how the procedure was done.</description>
           <description/>
           <rangeTypeName>uima.cas.String</rangeTypeName>
         </featureDescription>
+          <featureDescription>
+              <name>dayValue</name>
+              <description/>
+              <rangeTypeName>uima.cas.Integer</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>monthValue</name>
+              <description/>
+              <rangeTypeName>uima.cas.Integer</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>yearValue</name>
+              <description/>
+              <rangeTypeName>uima.cas.Integer</rangeTypeName>
+          </featureDescription>
       </features>
     </typeDescription>
     <typeDescription>
@@ -1275,7 +1326,7 @@ This instantiates a manages/treats relation which should be marked as conditiona
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.CollectionTextRelation</name>
-      <description/>
+      <description>Generic relation between two spans in text.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.Relation</supertypeName>
       <features>
         <featureDescription>
@@ -1362,107 +1413,107 @@ This instantiates a manages/treats relation which should be marked as conditiona
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.AffectsTextRelation</name>
-      <description/>
+      <description>Affects type relation between two spans of text.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.CausesBringsAbout</name>
-      <description/>
+      <description>Causes or Brings about relation between two Elements.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.CausesBringsAboutTextRelation</name>
-      <description/>
+      <description>Causes or Brings about relation between two spans of text.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.ComplicatesDisrupts</name>
-      <description/>
+      <description>Complicates or Disrupts relation between two Elements.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.ComplicatesDisruptsTextRelation</name>
-      <description/>
+      <description>Complicates or Disrupts relation between two spans of text.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.Contraindicates</name>
-      <description/>
+      <description>Contraindicates relation between two Elements</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.ContraindicatesTextRelation</name>
-      <description/>
+      <description>Contraindicates relation between two spans of text.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.Diagnoses</name>
-      <description/>
+      <description>Diagnoses relation between two Elements.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.DiagnosesTextRelation</name>
-      <description/>
+      <description>Contraindicates relation between two spans of text.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.Indicates</name>
-      <description/>
+      <description>Indicates relation between two Elements</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.IndicatesTextRelation</name>
-      <description/>
+      <description>Indicates relation between two spans of text.</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.IsIndicatedFor</name>
-      <description/>
+      <description>Is Indicated For relation between two Elements</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.IsIndicatedForTextRelation</name>
-      <description/>
+      <description>Is Indicated For relation between two spans of text</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.ManagesTreats</name>
-      <description/>
+      <description>Manages or Treats relation between two Elements</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.Prevents</name>
-      <description/>
+      <description>Prevents relation between two Elements</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.PreventsTextRelation</name>
-      <description/>
+      <description>Prevents relation between two spans of text</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.DegreeOfTextRelation</name>
-      <description/>
+      <description>Degree relation between two spans of text</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.LocationOfTextRelation</name>
-      <description/>
+      <description>Location relation between two spans of text</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.ManagesTreatsTextRelation</name>
-      <description/>
+      <description>Manages or Treats relation between two spans of text</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.ManifestationOfTextRelation</name>
-      <description/>
+      <description>Manifestation relation between two spans of text</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.relation.ResultOfTextRelation</name>
-      <description/>
+      <description>Result relation between two spans of text</description>
       <supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
     </typeDescription>
     <typeDescription>
@@ -1485,11 +1536,20 @@ This instantiates a manages/treats relation which should be marked as conditiona
           <description/>
           <rangeTypeName>uima.cas.String</rangeTypeName>
         </featureDescription>
-        <featureDescription>
+          <featureDescription>
+              <name>birthDateValue</name>
+              <description/>
+              <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Date</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
           <name>deathDate</name>
           <description/>
           <rangeTypeName>uima.cas.String</rangeTypeName>
         </featureDescription>
+          <featureDescription>
+              <name>deathDateValue</name>
+              <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Date</rangeTypeName>
+          </featureDescription>
         <featureDescription>
           <name>gender</name>
           <description/>
@@ -1529,12 +1589,12 @@ This instantiates a manages/treats relation which should be marked as conditiona
       <features>
         <featureDescription>
           <name>noteTypeCode</name>
-          <description/>
+          <description>Pathology: PATH,  Imaging: IMG,  Progress: PROG,  (generic) Clinical: NOTE</description>
           <rangeTypeName>uima.cas.String</rangeTypeName>
         </featureDescription>
         <featureDescription>
           <name>noteSubTypeCode</name>
-          <description/>
+          <description>AUTOPSY vs. BIOPSY,  MRI vs. XRAY,  PREOP vs. POSTOP,  OBGYN vs. ENT,  etc.</description>
           <rangeTypeName>uima.cas.String</rangeTypeName>
         </featureDescription>
         <featureDescription>
@@ -1567,6 +1627,15 @@ This instantiates a manages/treats relation which should be marked as conditiona
           <description/>
           <rangeTypeName>uima.cas.String</rangeTypeName>
         </featureDescription>
+          <!-- Normalized Date and Time -->
+          <featureDescription>
+              <name>sourceCreationDate</name>
+              <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Date</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>sourceCreationTime</name>
+              <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Time</rangeTypeName>
+          </featureDescription>
         <featureDescription>
           <name>sourceInstitution</name>
           <description/>
@@ -1584,6 +1653,60 @@ This instantiates a manages/treats relation which should be marked as conditiona
         </featureDescription>
       </features>
     </typeDescription>
+      <typeDescription>
+          <name>org.apache.ctakes.typesystem.type.structured.Patient</name>
+          <description>Patient information. Patient information intermixed with general metadata is deprecated.</description>
+          <supertypeName>uima.cas.TOP</supertypeName>
+          <features>
+              <featureDescription>
+                  <name>patientIdentifier</name>
+                  <description>Represents a text identifier for the patient.</description>
+                  <rangeTypeName>uima.cas.String</rangeTypeName>
+              </featureDescription>
+              <featureDescription>
+                  <name>patientNum</name>
+                  <description>patientNum is a simple long. Could be an index in an array or table.</description>
+                  <rangeTypeName>uima.cas.Long</rangeTypeName>
+              </featureDescription>
+              <featureDescription>
+                  <name>demographics</name>
+                  <description/>
+                  <rangeTypeName>org.apache.ctakes.typesystem.type.structured.Demographics</rangeTypeName>
+              </featureDescription>
+              <featureDescription>
+                  <name>documentCount</name>
+                  <description>The number of documents for the patient in the corpus.</description>
+                  <rangeTypeName>uima.cas.Integer</rangeTypeName>
+              </featureDescription>
+          </features>
+      </typeDescription>
+      <typeDescription>
+          <name>org.apache.ctakes.typesystem.type.structured.Corpus</name>
+          <description>Information about a corpus containing documents.</description>
+          <supertypeName>uima.cas.TOP</supertypeName>
+          <features>
+              <featureDescription>
+                  <name>corpusId</name>
+                  <description>Some unique identifier.</description>
+                  <rangeTypeName>uima.cas.String</rangeTypeName>
+              </featureDescription>
+              <featureDescription>
+                  <name>corpusName</name>
+                  <description>A name of the corpus, for instance UPMC Melanoma Pathology Notes.</description>
+                  <rangeTypeName>uima.cas.String</rangeTypeName>
+              </featureDescription>
+              <featureDescription>
+                  <name>patientCount</name>
+                  <description>The number of patients in the corpus.</description>
+                  <rangeTypeName>uima.cas.Integer</rangeTypeName>
+              </featureDescription>
+              <featureDescription>
+                  <name>documentCount</name>
+                  <description>The number of documents in the corpus.</description>
+                  <rangeTypeName>uima.cas.Integer</rangeTypeName>
+              </featureDescription>
+          </features>
+      </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.structured.Metadata</name>
       <description>Structured data that captures information about the document, patient, or context of the clinical text.</description>
@@ -1964,6 +2087,16 @@ This instantiates a manages/treats relation which should be marked as conditiona
           <description/>
           <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Time</rangeTypeName>
         </featureDescription>
+          <featureDescription>
+              <name>frequency</name>
+              <description/>
+              <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Frequency</rangeTypeName>
+          </featureDescription>
+          <featureDescription>
+              <name>duration</name>
+              <description/>
+              <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Duration</rangeTypeName>
+          </featureDescription>
         <featureDescription>
           <name>timeClass</name>
           <description>DATE, DURATION, QUANTIFIER, PREPOSTEXP, etc.</description>
@@ -2108,7 +2241,7 @@ Equivalent to cTAKES: edu.mayo.bmi.uima.core.type.Properties</description>
     </typeDescription>
     <typeDescription>
       <name>org.apache.ctakes.typesystem.type.structured.DocumentClassification</name>
-      <description/>
+      <description>Type of Document containing full text.</description>
       <supertypeName>uima.cas.TOP</supertypeName>
       <features>
         <featureDescription>
@@ -2746,6 +2879,11 @@ More qualifying information on how the procedure was done.</description>
               <description/>
               <rangeTypeName>uima.cas.String</rangeTypeName>
            </featureDescription>
+            <featureDescription>
+                <name>countValue</name>
+                <description/>
+                <rangeTypeName>uima.cas.Integer</rangeTypeName>
+            </featureDescription>
         </features>
      </typeDescription>
      <typeDescription>
@@ -2759,7 +2897,12 @@ More qualifying information on how the procedure was done.</description>
               <description/>
               <rangeTypeName>uima.cas.String</rangeTypeName>
            </featureDescription>
-           <featureDescription>
+            <featureDescription>
+                <name>numberValue</name>
+                <description/>
+                <rangeTypeName>uima.cas.Integer</rangeTypeName>
+            </featureDescription>
+            <featureDescription>
               <name>unit</name>
               <description>the unit of dose measurement</description>
               <rangeTypeName>uima.cas.String</rangeTypeName>
@@ -2777,7 +2920,12 @@ More qualifying information on how the procedure was done.</description>
               <description/>
               <rangeTypeName>uima.cas.String</rangeTypeName>
            </featureDescription>
-           <featureDescription>
+            <featureDescription>
+                <name>numberValue</name>
+                <description/>
+                <rangeTypeName>uima.cas.Integer</rangeTypeName>
+            </featureDescription>
+            <featureDescription>
               <name>unit</name>
               <description>the unit of dose measurement</description>
               <rangeTypeName>uima.cas.String</rangeTypeName>
@@ -2818,7 +2966,12 @@ More qualifying information on how the procedure was done.</description>
               <description/>
               <rangeTypeName>uima.cas.String</rangeTypeName>
            </featureDescription>
-           <featureDescription>
+            <featureDescription>
+                <name>numberValue</name>
+                <description/>
+                <rangeTypeName>uima.cas.Integer</rangeTypeName>
+            </featureDescription>
+            <featureDescription>
               <name>unit</name>
               <description>The periodic unit used, e.g day, month, hour, etc.</description>
               <rangeTypeName>uima.cas.String</rangeTypeName>
@@ -2835,7 +2988,12 @@ More qualifying information on how the procedure was done.</description>
               <description/>
               <rangeTypeName>uima.cas.String</rangeTypeName>
            </featureDescription>
-           <featureDescription>
+            <featureDescription>
+                <name>numberValue</name>
+                <description/>
+                <rangeTypeName>uima.cas.Integer</rangeTypeName>
+            </featureDescription>
+            <featureDescription>
               <name>unit</name>
               <description>the unit of time measurement. e.g day, month, hour, etc.</description>
               <rangeTypeName>uima.cas.String</rangeTypeName>
diff --git a/ctakes-ytex-uima/pom.xml b/ctakes-ytex-uima/pom.xml
index 2500205..f08cba9 100644
--- a/ctakes-ytex-uima/pom.xml
+++ b/ctakes-ytex-uima/pom.xml
@@ -166,26 +166,26 @@
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-antrun-plugin</artifactId>
 				<executions>
-					<execution>
-						<id>generate-test-config</id>
-						<phase>pre-integration-test</phase>
-						<goals>
-							<goal>run</goal>
-						</goals>
-						<configuration>
-							<target>
-								<!-- default to hsql, override via -D -->
-								<property name="db.type" value="hsql" />
-								<ant antfile="build-setup.xml" dir="${project.basedir}/../ctakes-ytex/scripts" target="test.setup">
-									<property name="config.local" value="${project.build.testOutputDirectory}" />
-<!--									<property name="db.type" value="${db.type}" />-->
-									<property name="db.type" value="hsql" />
-									<property name="ytex.test" value="true" />
-									<property name="ctakes.home" value="${project.basedir}/.." />
-								</ant>
-							</target>
-						</configuration>
-					</execution>			
+<!--					<execution>-->
+<!--						<id>generate-test-config</id>-->
+<!--						<phase>pre-integration-test</phase>-->
+<!--						<goals>-->
+<!--							<goal>run</goal>-->
+<!--						</goals>-->
+<!--						<configuration>-->
+<!--							<target>-->
+<!--								&lt;!&ndash; default to hsql, override via -D &ndash;&gt;-->
+<!--								<property name="db.type" value="hsql" />-->
+<!--								<ant antfile="build-setup.xml" dir="${project.basedir}/../ctakes-ytex/scripts" target="test.setup">-->
+<!--									<property name="config.local" value="${project.build.testOutputDirectory}" />-->
+<!--&lt;!&ndash;									<property name="db.type" value="${db.type}" />&ndash;&gt;-->
+<!--									<property name="db.type" value="hsql" />-->
+<!--									<property name="ytex.test" value="true" />-->
+<!--									<property name="ctakes.home" value="${project.basedir}/.." />-->
+<!--								</ant>-->
+<!--							</target>-->
+<!--						</configuration>-->
+<!--					</execution>			-->
 				</executions>
 			</plugin>
 			<!-- run all tests in the integration test phase -->