All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.ctakes.fhir.cc.FhirDocComposer Maven / Gradle / Ivy

package org.apache.ctakes.fhir.cc;


import org.apache.ctakes.core.util.annotation.EssentialAnnotationUtil;
import org.apache.ctakes.fhir.element.FhirElementFactory;
import org.apache.ctakes.fhir.resource.*;
import org.apache.ctakes.fhir.util.FhirNoteSpecs;
import org.apache.ctakes.typesystem.type.relation.BinaryTextRelation;
import org.apache.ctakes.typesystem.type.relation.RelationArgument;
import org.apache.ctakes.typesystem.type.syntax.BaseToken;
import org.apache.ctakes.typesystem.type.textsem.IdentifiedAnnotation;
import org.apache.ctakes.typesystem.type.textspan.Paragraph;
import org.apache.ctakes.typesystem.type.textspan.Segment;
import org.apache.ctakes.typesystem.type.textspan.Sentence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.tcas.Annotation;
import org.hl7.fhir.dstu3.model.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Creates a complete fhir bundle for a note.
 * @author SPF , chip-nlp
 * @version %I%
 * @since 12/15/2017
 */
final public class FhirDocComposer {

   static private final Logger LOGGER = LoggerFactory.getLogger( "FhirDocComposer" );

   static private final String SIMPLE_SECTION = "SIMPLE_SEGMENT";

   private FhirDocComposer() {
   }

   /**
    * @param jCas         ye olde ...
    * @param practitioner fhir practitioner.  Usually the default "ctakes" practitioner.
    * @param writeNlpFhir write all nlp information (paragraph, sentence, base annotations) to fhir.
    * @return a complete fhir bundle for a note.
    */
   static public Bundle composeDocFhir( final JCas jCas, final FhirPractitioner practitioner,
                                        final boolean writeNlpFhir ) {
      final FhirNoteSpecs noteSpecs = new FhirNoteSpecs( jCas );
      // creators
      final CompositionCreator compositionCreator = new CompositionCreator();
      final FhirResourceCreator sectionCreator = new SectionCreator();
      final FhirResourceCreator iaCreator = new IdentifiedAnnotationCreator();
      final FhirResourceCreator aCreator = new AnnotationCreator();
      // essential types
      final Map> sectionAnnotationMap
            = JCasUtil.indexCovered( jCas, Segment.class, IdentifiedAnnotation.class );
      final Collection sections = new ArrayList<>( sectionAnnotationMap.size() );
      final Map> markableCorefs = EssentialAnnotationUtil.createMarkableCorefs(
            jCas );
      final Collection requiredAnnotations = EssentialAnnotationUtil.getRequiredAnnotations( jCas,
            markableCorefs );
      // Create map of annotations to Fhir Basics.
      final Map annotationBasics = new HashMap<>();
      for ( Map.Entry> sectionAnnotations : sectionAnnotationMap.entrySet() ) {
         final Segment segment = sectionAnnotations.getKey();
         final String segmentId = segment.getId();
         final Basic section = sectionCreator.createResource( jCas, sectionAnnotations.getKey(), practitioner,
               noteSpecs );
         if ( writeNlpFhir || (!segmentId.isEmpty() && !segmentId.equals( SIMPLE_SECTION )) ) {
            sections.add( section );
         }
         final Reference sectionRef = new Reference( section );
         for ( IdentifiedAnnotation annotation : sectionAnnotations.getValue() ) {
            if ( !requiredAnnotations.contains( annotation ) ) {
               continue;
            }
            final Basic basic = iaCreator.createResource( jCas, annotation, practitioner, noteSpecs );
            if ( !segmentId.isEmpty() && !segmentId.equals( SIMPLE_SECTION ) ) {
               basic.addExtension( FhirElementFactory.createSectionExtension( sectionRef ) );
            }
            final Collection corefs = markableCorefs.get( annotation );
            if ( corefs != null ) {
               corefs.stream()
                     .map( FhirElementFactory::createCorefIndex )
                     .forEach( basic::addExtension );
            }
            annotationBasics.put( annotation, basic );
         }
      }
      // Add relations as reference extensions.
      final Map simpleAnnotationBasics = new HashMap<>();

      if ( writeNlpFhir ) {
         final BaseTokenCreator baseTokenCreator = new BaseTokenCreator();
         JCasUtil.select( jCas, BaseToken.class )
                 .forEach( b -> simpleAnnotationBasics.put( b,
                       baseTokenCreator.createResource( jCas, b, practitioner, noteSpecs ) ) );
      }

      addRelations( jCas, practitioner, noteSpecs, aCreator, annotationBasics, simpleAnnotationBasics );
      // Create a Bundle
      final Composition composition = compositionCreator.createResource( jCas, null, practitioner, noteSpecs );
      final Bundle bundle = new BundleCreator().createResource( jCas, null, practitioner, noteSpecs );
      bundle.addEntry( new Bundle.BundleEntryComponent().setResource( composition ) );
      bundle.addEntry( new Bundle.BundleEntryComponent().setResource( practitioner.getPractitioner() ) );
      addBundleResources( bundle, noteSpecs.getSubjects() );
      addBundleResources( bundle, sections );
      addBundleResources( bundle, annotationBasics.values() );
      addBundleResources( bundle, simpleAnnotationBasics.values() );

      if ( writeNlpFhir ) {
         final ParagraphCreator paragraphCreator = new ParagraphCreator();
         final Collection paragraphs
               = JCasUtil.select( jCas, Paragraph.class ).stream()
                         .map( p -> paragraphCreator.createResource( jCas, p, practitioner, noteSpecs ) )
                         .collect( Collectors.toList() );
         addBundleResources( bundle, paragraphs );

         final SentenceCreator sentenceCreator = new SentenceCreator();
         final Collection sentences
               = JCasUtil.select( jCas, Sentence.class ).stream()
                         .map( s -> sentenceCreator.createResource( jCas, s, practitioner, noteSpecs ) )
                         .collect( Collectors.toList() );
         addBundleResources( bundle, sentences );
      }

      return bundle;
   }

   /**
    * Add all of the given resources to the given bundle.
    *
    * @param bundle    -
    * @param resources -
    */
   static private void addBundleResources( final Bundle bundle, final Collection resources ) {
      resources.stream()
            .map( r -> new Bundle.BundleEntryComponent().setResource( r ) )
            .forEach( bundle::addEntry );
   }

   /**
    * Link fhir object ids according to ctakes relations.
    * @param jCas ye olde ...
    * @param practitioner -
    * @param noteSpecs -
    * @param aCreator -
    * @param annotationBasics -
    * @param simpleBasics -
    */
   static private void addRelations( final JCas jCas,
                                     final FhirPractitioner practitioner,
                                     final FhirNoteSpecs noteSpecs,
                                     final FhirResourceCreator aCreator,
                                     final Map annotationBasics,
                                     final Map simpleBasics ) {
      final Collection relations = JCasUtil.select( jCas, BinaryTextRelation.class );
      for ( BinaryTextRelation relation : relations ) {
         final RelationArgument arg1 = relation.getArg1();
         final Annotation source = arg1.getArgument();
         Basic basicSource;
         if ( source instanceof IdentifiedAnnotation ) {
            basicSource = annotationBasics.get( (IdentifiedAnnotation)source );
         } else {
            basicSource = getSimpleBasic( jCas, source, practitioner, noteSpecs, aCreator, simpleBasics );
         }
         final RelationArgument arg2 = relation.getArg2();
         final Annotation target = arg2.getArgument();
         Basic basicTarget;
         if ( target instanceof IdentifiedAnnotation ) {
            basicTarget = annotationBasics.get( (IdentifiedAnnotation)target );
         } else {
            basicTarget = getSimpleBasic( jCas, target, practitioner, noteSpecs, aCreator, simpleBasics );
         }
         final String type = relation.getCategory();
         basicSource.addExtension( FhirElementFactory.createRelation( type, basicTarget ) );
      }
   }

   /**
    *
    * @param jCas ye olde ...
    * @param annotation -
    * @param practitioner -
    * @param noteSpecs -
    * @param aCreator -
    * @param simpleBasics -
    * @return fhir Basic object for the given annotation.
    */
   static private Basic getSimpleBasic( final JCas jCas,
                                        final Annotation annotation,
                                        final FhirPractitioner practitioner,
                                        final FhirNoteSpecs noteSpecs,
                                        final FhirResourceCreator aCreator,
                                        final Map simpleBasics ) {
      final Basic basic = simpleBasics.get( annotation );
      if ( basic != null ) {
         return basic;
      }
      final Basic newBasic = aCreator.createResource( jCas, annotation, practitioner, noteSpecs );
      simpleBasics.put( annotation, newBasic );
      return newBasic;
   }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy