Index: trunk/src/events/events.nw
===================================================================
--- trunk/src/events/events.nw	(revision 8783)
+++ trunk/src/events/events.nw	(revision 8784)
@@ -1,17405 +1,19881 @@
 %% -*- ess-noweb-default-code-mode: f90-mode; noweb-default-code-mode: f90-mode; -*-
 % WHIZARD code as NOWEB source: event handling objects
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Generic Event Handling}
 \includemodulegraph{events}
 
 Event records allow the MC to communicate with the outside world.  The
 event record should exhibit the observable contents of a physical
 event.  We should be able to read and write events.  The actual
 implementation of the event need not be defined yet, for that purpose.
 
 We have the following basic modules:
 \begin{description}
 \item[event\_base]
   Abstract base type for event records.  The base type contains a
   reference to a [[particle_set_t]] object as the event core, and it
   holds some data that we should always expect, such as the squared
   matrix element and event weight.
 \item[eio\_data]
   Transparent container for the metadata of an event sample.
 \item[eio\_base]
   Abstract base type for event-record input and output.  The
   implementations of this base type represent specific event I/O
   formats.
 \end{description}
 
 These are the implementation modules:
 \begin{description}
 \item[eio\_checkpoints]
   Auxiliary output format.  The only purpose is to provide screen
   diagnostics during event output.
 \item[eio\_callback]
   Auxiliary output format.  The only purpose is to execute a callback
   procedure, so we have a hook for external access during event output.
 \item[eio\_weights]
   Print some event summary data, no details.  The main use is for
   testing purposes.
 \item[eio\_dump]
   Dump the contents of WHIZARD's [[particle_set]] internal record,
   using the [[write]] method of that record as-is.  The main use if for
   testing purposes.
 \item[hep\_common]
   Implements traditional HEP common blocks that are (still) used by
   some of the event I/O formats below.
 \item[hepmc\_interface]
   Access particle objects of the HepMC package.  Functional only if this
   package is linked. The interface is working both for HepMC2 and HepMC3.
 \item[lcio\_interface]
   Access objects of the LCIO package.  Functional only if this
   package is linked.
 \item[hep\_events]
   Interface between the event record and the common blocks.
 \item[eio\_ascii]
   Collection of event output formats that write ASCII files.
 \item[eio\_lhef]
   LHEF for input and output.
 \item[eio\_stdhep]
   Support for the StdHEP format (binary, machine-independent).
 \item[eio\_hepmc]
   Support for the HepMC format (C++).
 \item[eio\_lcio]
   Support for the LCIO format (C++).
 \end{description}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Generic Event Handling}
 We introduce events first in form of an abstract type, together with
 some utilities.  Abstract events can be used by other modules, in
 particular event I/O, without introducing an explicit dependency on
 the event implementation.
 <<[[event_base.f90]]>>=
 <<File header>>
 
 module event_base
 
 <<Use kinds>>
   use kinds, only: i64
 <<Use strings>>
-  use io_units
-  use string_utils, only: lower_case
-  use diagnostics
   use model_data
   use particles
 
 <<Standard module head>>
 
 <<Event base: public>>
 
 <<Event base: parameters>>
 
 <<Event base: types>>
 
 <<Event base: interfaces>>
 
+  interface
+<<Event base: sub interfaces>>
+  end interface
+
+end module event_base
+@ %def event_base
+@
+<<[[event_base_sub.f90]]>>=
+<<File header>>
+
+submodule (event_base) event_base_s
+
+  use io_units
+  use string_utils, only: lower_case
+  use diagnostics
+
+  implicit none
+
 contains
 
 <<Event base: procedures>>
 
-end module event_base
-@ %def event_base
+end submodule event_base_s
+
+@ %def event_base_s
 @
 \subsection{generic event type}
 <<Event base: public>>=
   public :: generic_event_t
 <<Event base: types>>=
   type, abstract :: generic_event_t
      !private
      logical :: particle_set_is_valid = .false.
      type(particle_set_t), pointer :: particle_set => null ()
      logical :: sqme_ref_known = .false.
      real(default) :: sqme_ref = 0
      logical :: sqme_prc_known = .false.
      real(default) :: sqme_prc = 0
      logical :: weight_ref_known = .false.
      real(default) :: weight_ref = 0
      logical :: weight_prc_known = .false.
      real(default) :: weight_prc = 0
      logical :: excess_prc_known = .false.
      real(default) :: excess_prc = 0
      logical :: n_dropped_known = .false.
      integer :: n_dropped = 0
      integer :: n_alt = 0
      logical :: sqme_alt_known = .false.
      real(default), dimension(:), allocatable :: sqme_alt
      logical :: weight_alt_known = .false.
      real(default), dimension(:), allocatable :: weight_alt
    contains
    <<Event base: generic event: TBP>>
   end type generic_event_t
 
 @ %def generic_event_t
 @
 \subsection{Initialization}
 This determines the number of alternate weights and sqme values.
 <<Event base: generic event: TBP>>=
   procedure :: base_init => generic_event_init
+<<Event base: sub interfaces>>=
+    module subroutine generic_event_init (event, n_alt)
+      class(generic_event_t), intent(out) :: event
+      integer, intent(in) :: n_alt
+    end subroutine generic_event_init
 <<Event base: procedures>>=
-  subroutine generic_event_init (event, n_alt)
+  module subroutine generic_event_init (event, n_alt)
     class(generic_event_t), intent(out) :: event
     integer, intent(in) :: n_alt
     event%n_alt = n_alt
     allocate (event%sqme_alt (n_alt))
     allocate (event%weight_alt (n_alt))
   end subroutine generic_event_init
 
 @ %def generic_event_init
 @
 \subsection{Access particle set}
 The particle set is the core of the event.  We allow access to it via
 a pointer, and we maintain the information whether the particle set
 is valid, i.e., has been filled with meaningful data.
 <<Event base: generic event: TBP>>=
   procedure :: has_valid_particle_set => generic_event_has_valid_particle_set
   procedure :: accept_particle_set => generic_event_accept_particle_set
   procedure :: discard_particle_set => generic_event_discard_particle_set
+<<Event base: sub interfaces>>=
+    module function generic_event_has_valid_particle_set (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_has_valid_particle_set
+    
+    module subroutine generic_event_accept_particle_set (event)
+      class(generic_event_t), intent(inout) :: event
+    end subroutine generic_event_accept_particle_set
+    
+    module subroutine generic_event_discard_particle_set (event)
+      class(generic_event_t), intent(inout) :: event
+    end subroutine generic_event_discard_particle_set
 <<Event base: procedures>>=
-  function generic_event_has_valid_particle_set (event) result (flag)
+  module function generic_event_has_valid_particle_set (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%particle_set_is_valid
   end function generic_event_has_valid_particle_set
 
-  subroutine generic_event_accept_particle_set (event)
+  module subroutine generic_event_accept_particle_set (event)
     class(generic_event_t), intent(inout) :: event
     event%particle_set_is_valid = .true.
   end subroutine generic_event_accept_particle_set
 
-  subroutine generic_event_discard_particle_set (event)
+  module subroutine generic_event_discard_particle_set (event)
     class(generic_event_t), intent(inout) :: event
     event%particle_set_is_valid = .false.
   end subroutine generic_event_discard_particle_set
 
 @ %def generic_event_has_valid_particle_set
 @ %def generic_event_accept_particle_set
 @ %def generic_event_discard_particle_set
 @
 These procedures deal with the particle set directly.  Return the pointer:
 <<Event base: generic event: TBP>>=
   procedure :: get_particle_set_ptr => generic_event_get_particle_set_ptr
+<<Event base: sub interfaces>>=
+    module function generic_event_get_particle_set_ptr (event) result (ptr)
+      class(generic_event_t), intent(in) :: event
+      type(particle_set_t), pointer :: ptr
+    end function generic_event_get_particle_set_ptr
 <<Event base: procedures>>=
-  function generic_event_get_particle_set_ptr (event) result (ptr)
+  module function generic_event_get_particle_set_ptr (event) result (ptr)
     class(generic_event_t), intent(in) :: event
     type(particle_set_t), pointer :: ptr
     ptr => event%particle_set
   end function generic_event_get_particle_set_ptr
 
 @ %def generic_event_get_particle_set_ptr
 @
 Let it point to some existing particle set:
 <<Event base: generic event: TBP>>=
   procedure :: link_particle_set => generic_event_link_particle_set
+<<Event base: sub interfaces>>=
+    module subroutine generic_event_link_particle_set (event, particle_set)
+      class(generic_event_t), intent(inout) :: event
+      type(particle_set_t), intent(in), target :: particle_set
+    end subroutine generic_event_link_particle_set
 <<Event base: procedures>>=
-  subroutine generic_event_link_particle_set (event, particle_set)
+  module subroutine generic_event_link_particle_set (event, particle_set)
     class(generic_event_t), intent(inout) :: event
     type(particle_set_t), intent(in), target :: particle_set
     event%particle_set => particle_set
     call event%accept_particle_set ()
   end subroutine generic_event_link_particle_set
 
 @ %def generic_event_link_particle_set
 @
 \subsection{Access sqme and weight}
 There are several incarnations: the current value, a reference value,
 alternate values.
 <<Event base: generic event: TBP>>=
   procedure :: sqme_prc_is_known => generic_event_sqme_prc_is_known
   procedure :: sqme_ref_is_known => generic_event_sqme_ref_is_known
   procedure :: sqme_alt_is_known => generic_event_sqme_alt_is_known
   procedure :: weight_prc_is_known => generic_event_weight_prc_is_known
   procedure :: weight_ref_is_known => generic_event_weight_ref_is_known
   procedure :: weight_alt_is_known => generic_event_weight_alt_is_known
   procedure :: excess_prc_is_known => generic_event_excess_prc_is_known
+<<Event base: sub interfaces>>=
+    module function generic_event_sqme_prc_is_known (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_sqme_prc_is_known
+    module function generic_event_sqme_ref_is_known (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_sqme_ref_is_known
+    module function generic_event_sqme_alt_is_known (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_sqme_alt_is_known
+    module function generic_event_weight_prc_is_known (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_weight_prc_is_known
+    module function generic_event_weight_ref_is_known (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_weight_ref_is_known
+    module function generic_event_weight_alt_is_known (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_weight_alt_is_known
+    module function generic_event_excess_prc_is_known (event) result (flag)
+      class(generic_event_t), intent(in) :: event
+      logical :: flag
+    end function generic_event_excess_prc_is_known
 <<Event base: procedures>>=
-  function generic_event_sqme_prc_is_known (event) result (flag)
+  module function generic_event_sqme_prc_is_known (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%sqme_prc_known
   end function generic_event_sqme_prc_is_known
 
-  function generic_event_sqme_ref_is_known (event) result (flag)
+  module function generic_event_sqme_ref_is_known (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%sqme_ref_known
   end function generic_event_sqme_ref_is_known
 
-  function generic_event_sqme_alt_is_known (event) result (flag)
+  module function generic_event_sqme_alt_is_known (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%sqme_alt_known
   end function generic_event_sqme_alt_is_known
 
-  function generic_event_weight_prc_is_known (event) result (flag)
+  module function generic_event_weight_prc_is_known (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%weight_prc_known
   end function generic_event_weight_prc_is_known
 
-  function generic_event_weight_ref_is_known (event) result (flag)
+  module function generic_event_weight_ref_is_known (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%weight_ref_known
   end function generic_event_weight_ref_is_known
 
-  function generic_event_weight_alt_is_known (event) result (flag)
+  module function generic_event_weight_alt_is_known (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%weight_alt_known
   end function generic_event_weight_alt_is_known
 
-  function generic_event_excess_prc_is_known (event) result (flag)
+  module function generic_event_excess_prc_is_known (event) result (flag)
     class(generic_event_t), intent(in) :: event
     logical :: flag
     flag = event%excess_prc_known
   end function generic_event_excess_prc_is_known
 
 @ %def generic_event_sqme_prc_is_known
 @ %def generic_event_sqme_ref_is_known
 @ %def generic_event_sqme_alt_is_known
 @ %def generic_event_weight_prc_is_known
 @ %def generic_event_weight_ref_is_known
 @ %def generic_event_weight_alt_is_known
 @ %def generic_event_excess_prc_is_known
 @
 <<Event base: generic event: TBP>>=
   procedure :: get_n_alt => generic_event_get_n_alt
+<<Event base: sub interfaces>>=
+    module function generic_event_get_n_alt (event) result (n)
+      class(generic_event_t), intent(in) :: event
+      integer :: n
+    end function generic_event_get_n_alt
 <<Event base: procedures>>=
-  function generic_event_get_n_alt (event) result (n)
+  module function generic_event_get_n_alt (event) result (n)
     class(generic_event_t), intent(in) :: event
     integer :: n
     n = event%n_alt
   end function generic_event_get_n_alt
 
 @ %def generic_event_get_n_alt
 @
 <<Event base: generic event: TBP>>=
   procedure :: get_sqme_prc => generic_event_get_sqme_prc
   procedure :: get_sqme_ref => generic_event_get_sqme_ref
   generic :: get_sqme_alt => &
        generic_event_get_sqme_alt_0, generic_event_get_sqme_alt_1
   procedure :: generic_event_get_sqme_alt_0
   procedure :: generic_event_get_sqme_alt_1
   procedure :: get_weight_prc => generic_event_get_weight_prc
   procedure :: get_weight_ref => generic_event_get_weight_ref
   generic :: get_weight_alt => &
        generic_event_get_weight_alt_0, generic_event_get_weight_alt_1
   procedure :: generic_event_get_weight_alt_0
   procedure :: generic_event_get_weight_alt_1
   procedure :: get_n_dropped => generic_event_get_n_dropped
   procedure :: get_excess_prc => generic_event_get_excess_prc
+<<Event base: sub interfaces>>=
+    module function generic_event_get_sqme_prc (event) result (sqme)
+      class(generic_event_t), intent(in) :: event
+      real(default) :: sqme
+    end function generic_event_get_sqme_prc
+    module function generic_event_get_sqme_ref (event) result (sqme)
+      class(generic_event_t), intent(in) :: event
+      real(default) :: sqme
+    end function generic_event_get_sqme_ref
+    module function generic_event_get_sqme_alt_0 (event, i) result (sqme)
+      class(generic_event_t), intent(in) :: event
+      integer, intent(in) :: i
+      real(default) :: sqme
+    end function generic_event_get_sqme_alt_0
+    module function generic_event_get_sqme_alt_1 (event) result (sqme)
+      class(generic_event_t), intent(in) :: event
+      real(default), dimension(event%n_alt) :: sqme
+    end function generic_event_get_sqme_alt_1
+    module function generic_event_get_weight_prc (event) result (weight)
+      class(generic_event_t), intent(in) :: event
+      real(default) :: weight
+    end function generic_event_get_weight_prc
+    module function generic_event_get_weight_ref (event) result (weight)
+      class(generic_event_t), intent(in) :: event
+      real(default) :: weight
+    end function generic_event_get_weight_ref
+    module function generic_event_get_weight_alt_0 (event, i) result (weight)
+      class(generic_event_t), intent(in) :: event
+      integer, intent(in) :: i
+      real(default) :: weight
+    end function generic_event_get_weight_alt_0
+    module function generic_event_get_weight_alt_1 (event) result (weight)
+      class(generic_event_t), intent(in) :: event
+      real(default), dimension(event%n_alt) :: weight
+    end function generic_event_get_weight_alt_1
+    module function generic_event_get_excess_prc (event) result (excess)
+      class(generic_event_t), intent(in) :: event
+      real(default) :: excess
+    end function generic_event_get_excess_prc
+    module function generic_event_get_n_dropped (event) result (n_dropped)
+      class(generic_event_t), intent(in) :: event
+      integer :: n_dropped
+    end function generic_event_get_n_dropped
 <<Event base: procedures>>=
-  function generic_event_get_sqme_prc (event) result (sqme)
+  module function generic_event_get_sqme_prc (event) result (sqme)
     class(generic_event_t), intent(in) :: event
     real(default) :: sqme
     if (event%sqme_prc_known) then
        sqme = event%sqme_prc
     else
        sqme = 0
     end if
   end function generic_event_get_sqme_prc
 
-  function generic_event_get_sqme_ref (event) result (sqme)
+  module function generic_event_get_sqme_ref (event) result (sqme)
     class(generic_event_t), intent(in) :: event
     real(default) :: sqme
     if (event%sqme_ref_known) then
        sqme = event%sqme_ref
     else
        sqme = 0
     end if
   end function generic_event_get_sqme_ref
 
-  function generic_event_get_sqme_alt_0 (event, i) result (sqme)
+  module function generic_event_get_sqme_alt_0 (event, i) result (sqme)
     class(generic_event_t), intent(in) :: event
     integer, intent(in) :: i
     real(default) :: sqme
     if (event%sqme_alt_known) then
        sqme = event%sqme_alt(i)
     else
        sqme = 0
     end if
   end function generic_event_get_sqme_alt_0
 
-  function generic_event_get_sqme_alt_1 (event) result (sqme)
+  module function generic_event_get_sqme_alt_1 (event) result (sqme)
     class(generic_event_t), intent(in) :: event
     real(default), dimension(event%n_alt) :: sqme
     sqme = event%sqme_alt
   end function generic_event_get_sqme_alt_1
 
-  function generic_event_get_weight_prc (event) result (weight)
+  module function generic_event_get_weight_prc (event) result (weight)
     class(generic_event_t), intent(in) :: event
     real(default) :: weight
     if (event%weight_prc_known) then
        weight = event%weight_prc
     else
        weight = 0
     end if
   end function generic_event_get_weight_prc
 
-  function generic_event_get_weight_ref (event) result (weight)
+  module function generic_event_get_weight_ref (event) result (weight)
     class(generic_event_t), intent(in) :: event
     real(default) :: weight
     if (event%weight_ref_known) then
        weight = event%weight_ref
     else
        weight = 0
     end if
   end function generic_event_get_weight_ref
 
-  function generic_event_get_weight_alt_0 (event, i) result (weight)
+  module function generic_event_get_weight_alt_0 (event, i) result (weight)
     class(generic_event_t), intent(in) :: event
     integer, intent(in) :: i
     real(default) :: weight
     if (event%weight_alt_known) then
        weight = event%weight_alt(i)
     else
        weight = 0
     end if
   end function generic_event_get_weight_alt_0
 
-  function generic_event_get_weight_alt_1 (event) result (weight)
+  module function generic_event_get_weight_alt_1 (event) result (weight)
     class(generic_event_t), intent(in) :: event
     real(default), dimension(event%n_alt) :: weight
     weight = event%weight_alt
   end function generic_event_get_weight_alt_1
 
-  function generic_event_get_excess_prc (event) result (excess)
+  module function generic_event_get_excess_prc (event) result (excess)
     class(generic_event_t), intent(in) :: event
     real(default) :: excess
     if (event%excess_prc_known) then
        excess = event%excess_prc
     else
        excess = 0
     end if
   end function generic_event_get_excess_prc
 
-  function generic_event_get_n_dropped (event) result (n_dropped)
+  module function generic_event_get_n_dropped (event) result (n_dropped)
     class(generic_event_t), intent(in) :: event
     integer :: n_dropped
     if (event%n_dropped_known) then
        n_dropped = event%n_dropped
     else
        n_dropped = 0
     end if
   end function generic_event_get_n_dropped
 
 @ %def generic_event_get_sqme_prc
 @ %def generic_event_get_sqme_ref
 @ %def generic_event_get_sqme_alt
 @ %def generic_event_get_weight_prc
 @ %def generic_event_get_weight_ref
 @ %def generic_event_get_weight_alt
 @ %def generic_event_get_n_dropped
 @ %def generic_event_get_excess_prc
 @
 <<Event base: generic event: TBP>>=
   procedure :: set_sqme_prc => generic_event_set_sqme_prc
   procedure :: set_sqme_ref => generic_event_set_sqme_ref
   procedure :: set_sqme_alt => generic_event_set_sqme_alt
   procedure :: set_weight_prc => generic_event_set_weight_prc
   procedure :: set_weight_ref => generic_event_set_weight_ref
   procedure :: set_weight_alt => generic_event_set_weight_alt
   procedure :: set_excess_prc => generic_event_set_excess_prc
   procedure :: set_n_dropped => generic_event_set_n_dropped
+<<Event base: sub interfaces>>=
+    module subroutine generic_event_set_sqme_prc (event, sqme)
+      class(generic_event_t), intent(inout) :: event
+      real(default), intent(in) :: sqme
+    end subroutine generic_event_set_sqme_prc
+    module subroutine generic_event_set_sqme_ref (event, sqme)
+      class(generic_event_t), intent(inout) :: event
+      real(default), intent(in) :: sqme
+    end subroutine generic_event_set_sqme_ref
+    module subroutine generic_event_set_sqme_alt (event, sqme)
+      class(generic_event_t), intent(inout) :: event
+      real(default), dimension(:), intent(in) :: sqme
+    end subroutine generic_event_set_sqme_alt
+    module subroutine generic_event_set_weight_prc (event, weight)
+      class(generic_event_t), intent(inout) :: event
+      real(default), intent(in) :: weight
+    end subroutine generic_event_set_weight_prc
+    module subroutine generic_event_set_weight_ref (event, weight)
+      class(generic_event_t), intent(inout) :: event
+      real(default), intent(in) :: weight
+    end subroutine generic_event_set_weight_ref
+    module subroutine generic_event_set_weight_alt (event, weight)
+      class(generic_event_t), intent(inout) :: event
+      real(default), dimension(:), intent(in) :: weight
+    end subroutine generic_event_set_weight_alt
+    module subroutine generic_event_set_excess_prc (event, excess)
+      class(generic_event_t), intent(inout) :: event
+      real(default), intent(in) :: excess
+    end subroutine generic_event_set_excess_prc
+    module subroutine generic_event_set_n_dropped (event, n_dropped)
+      class(generic_event_t), intent(inout) :: event
+      integer, intent(in) :: n_dropped
+    end subroutine generic_event_set_n_dropped
 <<Event base: procedures>>=
-  subroutine generic_event_set_sqme_prc (event, sqme)
+  module subroutine generic_event_set_sqme_prc (event, sqme)
     class(generic_event_t), intent(inout) :: event
     real(default), intent(in) :: sqme
     event%sqme_prc = sqme
     event%sqme_prc_known = .true.
   end subroutine generic_event_set_sqme_prc
 
-  subroutine generic_event_set_sqme_ref (event, sqme)
+  module subroutine generic_event_set_sqme_ref (event, sqme)
     class(generic_event_t), intent(inout) :: event
     real(default), intent(in) :: sqme
     event%sqme_ref = sqme
     event%sqme_ref_known = .true.
   end subroutine generic_event_set_sqme_ref
 
-  subroutine generic_event_set_sqme_alt (event, sqme)
+  module subroutine generic_event_set_sqme_alt (event, sqme)
     class(generic_event_t), intent(inout) :: event
     real(default), dimension(:), intent(in) :: sqme
     event%sqme_alt = sqme
     event%sqme_alt_known = .true.
   end subroutine generic_event_set_sqme_alt
 
-  subroutine generic_event_set_weight_prc (event, weight)
+  module subroutine generic_event_set_weight_prc (event, weight)
     class(generic_event_t), intent(inout) :: event
     real(default), intent(in) :: weight
     event%weight_prc = weight
     event%weight_prc_known = .true.
   end subroutine generic_event_set_weight_prc
 
-  subroutine generic_event_set_weight_ref (event, weight)
+  module subroutine generic_event_set_weight_ref (event, weight)
     class(generic_event_t), intent(inout) :: event
     real(default), intent(in) :: weight
     event%weight_ref = weight
     event%weight_ref_known = .true.
   end subroutine generic_event_set_weight_ref
 
-  subroutine generic_event_set_weight_alt (event, weight)
+  module subroutine generic_event_set_weight_alt (event, weight)
     class(generic_event_t), intent(inout) :: event
     real(default), dimension(:), intent(in) :: weight
     event%weight_alt = weight
     event%weight_alt_known = .true.
   end subroutine generic_event_set_weight_alt
 
-  subroutine generic_event_set_excess_prc (event, excess)
+  module subroutine generic_event_set_excess_prc (event, excess)
     class(generic_event_t), intent(inout) :: event
     real(default), intent(in) :: excess
     event%excess_prc = excess
     event%excess_prc_known = .true.
   end subroutine generic_event_set_excess_prc
 
-  subroutine generic_event_set_n_dropped (event, n_dropped)
+  module subroutine generic_event_set_n_dropped (event, n_dropped)
     class(generic_event_t), intent(inout) :: event
     integer, intent(in) :: n_dropped
     event%n_dropped = n_dropped
     event%n_dropped_known = .true.
   end subroutine generic_event_set_n_dropped
 
 @ %def generic_event_set_sqme_prc
 @ %def generic_event_set_sqme_ref
 @ %def generic_event_set_sqme_alt
 @ %def generic_event_set_weight_prc
 @ %def generic_event_set_weight_ref
 @ %def generic_event_set_weight_alt
 @ %def generic_event_set_n_dropped
 @
 Set the appropriate entry directly.
 <<Event base: generic event: TBP>>=
   procedure :: set => generic_event_set
+<<Event base: sub interfaces>>=
+    module subroutine generic_event_set (event, &
+         weight_ref, weight_prc, weight_alt, &
+         excess_prc, n_dropped, &
+         sqme_ref, sqme_prc, sqme_alt)
+      class(generic_event_t), intent(inout) :: event
+      real(default), intent(in), optional :: weight_ref, weight_prc
+      real(default), intent(in), optional :: sqme_ref, sqme_prc
+      real(default), dimension(:), intent(in), optional :: sqme_alt, weight_alt
+      real(default), intent(in), optional :: excess_prc
+      integer, intent(in), optional :: n_dropped
+    end subroutine generic_event_set
 <<Event base: procedures>>=
-  subroutine generic_event_set (event, &
+  module subroutine generic_event_set (event, &
        weight_ref, weight_prc, weight_alt, &
        excess_prc, n_dropped, &
        sqme_ref, sqme_prc, sqme_alt)
     class(generic_event_t), intent(inout) :: event
     real(default), intent(in), optional :: weight_ref, weight_prc
     real(default), intent(in), optional :: sqme_ref, sqme_prc
     real(default), dimension(:), intent(in), optional :: sqme_alt, weight_alt
     real(default), intent(in), optional :: excess_prc
     integer, intent(in), optional :: n_dropped
     if (present (sqme_prc)) then
        call event%set_sqme_prc (sqme_prc)
     end if
     if (present (sqme_ref)) then
        call event%set_sqme_ref (sqme_ref)
     end if
     if (present (sqme_alt)) then
        call event%set_sqme_alt (sqme_alt)
     end if
     if (present (weight_prc)) then
        call event%set_weight_prc (weight_prc)
     end if
     if (present (weight_ref)) then
        call event%set_weight_ref (weight_ref)
     end if
     if (present (weight_alt)) then
        call event%set_weight_alt (weight_alt)
     end if
     if (present (excess_prc)) then
        call event%set_excess_prc (excess_prc)
     end if
     if (present (n_dropped)) then
        call event%set_n_dropped (n_dropped)
     end if
   end subroutine generic_event_set
 
 @ %def generic_event_set
 @
 \subsection{Pure Virtual Methods}
 These procedures can only implemented in the concrete implementation.
 
 Output (verbose, depending on parameters).
 <<Event base: generic event: TBP>>=
   procedure (generic_event_write), deferred :: write
 <<Event base: interfaces>>=
   abstract interface
      subroutine generic_event_write (object, unit, &
           show_process, show_transforms, &
           show_decay, verbose, testflag)
        import
        class(generic_event_t), intent(in) :: object
        integer, intent(in), optional :: unit
        logical, intent(in), optional :: show_process
        logical, intent(in), optional :: show_transforms
        logical, intent(in), optional :: show_decay
        logical, intent(in), optional :: verbose
        logical, intent(in), optional :: testflag
      end subroutine generic_event_write
   end interface
 
 @ %def generic_event_write
 @
 Generate an event, based on a selector index [[i_mci]], and optionally on an
 extra set of random numbers [[r]].  For the main bunch of random numbers that
 the generator needs, the event object should contain its own generator.
 <<Event base: generic event: TBP>>=
   procedure (generic_event_generate), deferred :: generate
 <<Event base: interfaces>>=
   abstract interface
      subroutine generic_event_generate (event, i_mci, r, i_nlo)
        import
        class(generic_event_t), intent(inout) :: event
        integer, intent(in) :: i_mci
        real(default), dimension(:), intent(in), optional :: r
        integer, intent(in), optional :: i_nlo
      end subroutine generic_event_generate
   end interface
 
 @ %def event_generate
 @
 Alternative : inject a particle set that is supposed to represent the hard
 process.
 How this determines the event, is dependent on the event structure,
 therefore this is a deferred method.
 <<Event base: generic event: TBP>>=
   procedure (generic_event_set_hard_particle_set), deferred :: &
        set_hard_particle_set
 <<Event base: interfaces>>=
   abstract interface
      subroutine generic_event_set_hard_particle_set (event, particle_set)
        import
        class(generic_event_t), intent(inout) :: event
        type(particle_set_t), intent(in) :: particle_set
      end subroutine generic_event_set_hard_particle_set
   end interface
 
 @ %def generic_event_set_hard_particle_set
 @ Event index handlers.
 <<Event base: generic event: TBP>>=
   procedure (generic_event_set_index), deferred :: set_index
   procedure (generic_event_handler), deferred :: reset_index
   procedure (generic_event_increment_index), deferred :: increment_index
 @
 <<Event base: interfaces>>=
   abstract interface
      subroutine generic_event_set_index (event, index)
        import
        class(generic_event_t), intent(inout) :: event
        integer, intent(in) :: index
      end subroutine generic_event_set_index
   end interface
 
   abstract interface
      subroutine generic_event_handler (event)
        import
        class(generic_event_t), intent(inout) :: event
      end subroutine generic_event_handler
   end interface
 
   abstract interface
      subroutine generic_event_increment_index (event, offset)
        import
        class(generic_event_t), intent(inout) :: event
        integer, intent(in), optional :: offset
      end subroutine generic_event_increment_index
   end interface
 
 @ %def generic_event_set_index
 @ %def generic_event_increment_index
 @ %def generic_event_handler
 @ Evaluate any expressions associated with the event.  No argument needed.
 <<Event base: generic event: TBP>>=
   procedure (generic_event_handler), deferred :: evaluate_expressions
 @
 Select internal parameters
 <<Event base: generic event: TBP>>=
   procedure (generic_event_select), deferred :: select
 <<Event base: interfaces>>=
   abstract interface
      subroutine generic_event_select (event,  i_mci, i_term, channel)
        import
        class(generic_event_t), intent(inout) :: event
        integer, intent(in) :: i_mci, i_term, channel
      end subroutine generic_event_select
   end interface
 
 @ %def generic_event_select
 @ Return a pointer to the model for the currently active process.
 <<Event base: generic event: TBP>>=
   procedure (generic_event_get_model_ptr), deferred :: get_model_ptr
 <<Event base: interfaces>>=
   abstract interface
      function generic_event_get_model_ptr (event) result (model)
        import
        class(generic_event_t), intent(in) :: event
        class(model_data_t), pointer :: model
      end function generic_event_get_model_ptr
   end interface
 
 @ %def generic_event_get_model_ptr
 @ Return data used by external event formats.
 <<Event base: generic event: TBP>>=
   procedure (generic_event_has_index), deferred :: has_index
   procedure (generic_event_get_index), deferred :: get_index
   procedure (generic_event_get_fac_scale), deferred :: get_fac_scale
   procedure (generic_event_get_alpha_s), deferred :: get_alpha_s
   procedure (generic_event_get_sqrts), deferred :: get_sqrts
   procedure (generic_event_get_polarization), deferred :: get_polarization
   procedure (generic_event_get_beam_file), deferred :: get_beam_file
   procedure (generic_event_get_process_name), deferred :: &
        get_process_name
 <<Event base: interfaces>>=
   abstract interface
      function generic_event_has_index (event) result (flag)
        import
        class(generic_event_t), intent(in) :: event
        logical :: flag
      end function generic_event_has_index
   end interface
 
   abstract interface
      function generic_event_get_index (event) result (index)
        import
        class(generic_event_t), intent(in) :: event
        integer :: index
      end function generic_event_get_index
   end interface
 
   abstract interface
      function generic_event_get_fac_scale (event) result (fac_scale)
        import
        class(generic_event_t), intent(in) :: event
        real(default) :: fac_scale
      end function generic_event_get_fac_scale
   end interface
 
   abstract interface
      function generic_event_get_alpha_s (event) result (alpha_s)
        import
        class(generic_event_t), intent(in) :: event
        real(default) :: alpha_s
      end function generic_event_get_alpha_s
   end interface
 
   abstract interface
      function generic_event_get_sqrts (event) result (sqrts)
        import
        class(generic_event_t), intent(in) :: event
        real(default) :: sqrts
      end function generic_event_get_sqrts
   end interface
 
   abstract interface
      function generic_event_get_polarization (event) result (pol)
        import
        class(generic_event_t), intent(in) :: event
        real(default), dimension(:), allocatable :: pol
      end function generic_event_get_polarization
   end interface
 
   abstract interface
      function generic_event_get_beam_file (event) result (file)
        import
        class(generic_event_t), intent(in) :: event
        type(string_t) :: file
      end function generic_event_get_beam_file
   end interface
 
   abstract interface
      function generic_event_get_process_name (event) result (name)
        import
        class(generic_event_t), intent(in) :: event
        type(string_t) :: name
      end function generic_event_get_process_name
   end interface
 
 @ %def generic_event_get_index
 @ %def generic_event_get_fac_scale
 @ %def generic_event_get_alpha_s
 @ %def generic_event_get_sqrts
 @ %def generic_event_get_polarization
 @ %def generic_event_get_beam_file
 @ %def generic_event_get_process_name
 @ Set data used by external event formats.
 <<Event base: generic event: TBP>>=
   procedure (generic_event_set_alpha_qcd_forced), deferred :: &
        set_alpha_qcd_forced
   procedure (generic_event_set_scale_forced), deferred :: &
        set_scale_forced
 <<Event base: interfaces>>=
   abstract interface
      subroutine generic_event_set_alpha_qcd_forced (event, alpha_qcd)
        import
        class(generic_event_t), intent(inout) :: event
        real(default), intent(in) :: alpha_qcd
      end subroutine generic_event_set_alpha_qcd_forced
   end interface
 
   abstract interface
      subroutine generic_event_set_scale_forced (event, scale)
        import
        class(generic_event_t), intent(inout) :: event
        real(default), intent(in) :: scale
      end subroutine generic_event_set_scale_forced
   end interface
 
 @ %def generic_event_set_alpha_qcd_forced
 @ %def generic_event_set_scale_forced
 @
 \subsection{Utilities}
 Applying this, current event contents are marked as incomplete but
 are not deleted.  In particular, the initialization is kept.
 <<Event base: generic event: TBP>>=
   procedure :: reset_contents => generic_event_reset_contents
   procedure :: base_reset_contents => generic_event_reset_contents
+<<Event base: sub interfaces>>=
+    module subroutine generic_event_reset_contents (event)
+      class(generic_event_t), intent(inout) :: event
+    end subroutine generic_event_reset_contents
 <<Event base: procedures>>=
-  subroutine generic_event_reset_contents (event)
+  module subroutine generic_event_reset_contents (event)
     class(generic_event_t), intent(inout) :: event
     call event%discard_particle_set ()
     event%sqme_ref_known = .false.
     event%sqme_prc_known = .false.
     event%sqme_alt_known = .false.
     event%weight_ref_known = .false.
     event%weight_prc_known = .false.
     event%weight_alt_known = .false.
     event%excess_prc_known = .false.
   end subroutine generic_event_reset_contents
 
 @ %def generic_event_reset_contents
 @ Pacify particle set.
 <<Event base: generic event: TBP>>=
   procedure :: pacify_particle_set => generic_event_pacify_particle_set
+<<Event base: sub interfaces>>=
+    module subroutine generic_event_pacify_particle_set (event)
+      class(generic_event_t), intent(inout) :: event
+    end subroutine generic_event_pacify_particle_set
 <<Event base: procedures>>=
-  subroutine generic_event_pacify_particle_set (event)
+  module subroutine generic_event_pacify_particle_set (event)
     class(generic_event_t), intent(inout) :: event
     if (event%has_valid_particle_set ())  call pacify (event%particle_set)
   end subroutine generic_event_pacify_particle_set
 
 @ %def generic_event_pacify_particle_set
 @
 \subsection{Event normalization}
 The parameters for event normalization.  For unweighted events,
 [[NORM_UNIT]] is intended as default, while for weighted events, it is
 [[NORM_SIGMA]].
 
 Note: the unit test for this is in [[eio_data_2]] below.
 <<Event base: parameters>>=
   integer, parameter, public :: NORM_UNDEFINED = 0
   integer, parameter, public :: NORM_UNIT = 1
   integer, parameter, public :: NORM_N_EVT = 2
   integer, parameter, public :: NORM_SIGMA = 3
   integer, parameter, public :: NORM_S_N = 4
 
 @ %def NORM_UNDEFINED NORM_UNIT NORM_N_EVT NORM_SIGMA NORM_S_N
 @ These functions translate between the user representation and the
 internal one.
 <<Event base: public>>=
   public :: event_normalization_mode
   public :: event_normalization_string
+<<Event base: sub interfaces>>=
+    module function event_normalization_mode (string, unweighted) result (mode)
+      integer :: mode
+      type(string_t), intent(in) :: string
+      logical, intent(in) :: unweighted
+    end function event_normalization_mode
+    module function event_normalization_string (norm_mode) result (string)
+      integer, intent(in) :: norm_mode
+      type(string_t) :: string
+    end function event_normalization_string
 <<Event base: procedures>>=
-  function event_normalization_mode (string, unweighted) result (mode)
+  module function event_normalization_mode (string, unweighted) result (mode)
     integer :: mode
     type(string_t), intent(in) :: string
     logical, intent(in) :: unweighted
     select case (lower_case (char (string)))
     case ("auto")
        if (unweighted) then
           mode = NORM_UNIT
        else
           mode = NORM_SIGMA
        end if
     case ("1")
        mode = NORM_UNIT
     case ("1/n")
        mode = NORM_N_EVT
     case ("sigma")
        mode = NORM_SIGMA
     case ("sigma/n")
        mode = NORM_S_N
     case default
        call msg_fatal ("Event normalization: unknown value '" &
             // char (string) // "'")
     end select
   end function event_normalization_mode
 
-  function event_normalization_string (norm_mode) result (string)
+  module function event_normalization_string (norm_mode) result (string)
     integer, intent(in) :: norm_mode
     type(string_t) :: string
     select case (norm_mode)
     case (NORM_UNDEFINED); string = "[undefined]"
     case (NORM_UNIT);      string = "'1'"
     case (NORM_N_EVT);     string = "'1/n'"
     case (NORM_SIGMA);     string = "'sigma'"
     case (NORM_S_N);       string = "'sigma/n'"
     case default;          string = "???"
     end select
   end function event_normalization_string
 
 @ %def event_normalization_mode
 @ %def event_normalization_string
 @ We place this here as a generic helper, so we can update event
 weights whenever we need, not just in connection with an event sample
 data object.
 <<Event base: public>>=
   public :: event_normalization_update
+<<Event base: sub interfaces>>=
+    module subroutine event_normalization_update &
+         (weight, sigma, n, mode_new, mode_old)
+      real(default), intent(inout) :: weight
+      real(default), intent(in) :: sigma
+      integer, intent(in) :: n
+      integer, intent(in) :: mode_new, mode_old
+    end subroutine event_normalization_update
 <<Event base: procedures>>=
-  subroutine event_normalization_update (weight, sigma, n, mode_new, mode_old)
+  module subroutine event_normalization_update &
+       (weight, sigma, n, mode_new, mode_old)
     real(default), intent(inout) :: weight
     real(default), intent(in) :: sigma
     integer, intent(in) :: n
     integer, intent(in) :: mode_new, mode_old
     if (mode_new /= mode_old) then
        if (sigma > 0 .and. n > 0) then
           weight = weight / factor (mode_old) * factor (mode_new)
        else
           call msg_fatal ("Event normalization update: null sample")
        end if
     end if
   contains
     function factor (mode)
       real(default) :: factor
       integer, intent(in) :: mode
       select case (mode)
       case (NORM_UNIT);   factor = 1._default
       case (NORM_N_EVT);  factor = 1._default / n
       case (NORM_SIGMA);  factor = sigma
       case (NORM_S_N);    factor = sigma / n
       case default
          call msg_fatal ("Event normalization update: undefined mode")
       end select
     end function factor
   end subroutine event_normalization_update
 
 @ %def event_normalization_update
 @
 \subsection{Callback container}
 This derived type contains a callback procedure that can
 be executed during event I/O.  The callback procedure is given the
 event object (with class [[generic_event]]) and an event index.
 
 This is a simple wrapper.  The object is abstract, so the the actual
 procedure is introduced by overriding the deferred one.  We use the
 PASS attribute, so we may supplement runtime data in the callback object
 if desired.
 <<Event base: public>>=
   public :: event_callback_t
 <<Event base: types>>=
   type, abstract :: event_callback_t
      private
    contains
      procedure(event_callback_write), deferred :: write
      procedure(event_callback_proc), deferred :: proc
   end type event_callback_t
 
 @ %def event_callback_t
 @ Identify the callback procedure in output
 <<Event base: interfaces>>=
   abstract interface
      subroutine event_callback_write (event_callback, unit)
        import
        class(event_callback_t), intent(in) :: event_callback
        integer, intent(in), optional :: unit
      end subroutine event_callback_write
   end interface
 
 @ %def event_callback_write
 @ This is the procedure interface.
 <<Event base: interfaces>>=
   abstract interface
      subroutine event_callback_proc (event_callback, i, event)
        import
        class(event_callback_t), intent(in) :: event_callback
        integer(i64), intent(in) :: i
        class(generic_event_t), intent(in) :: event
      end subroutine event_callback_proc
   end interface
 
 @ %def event_callback_proc
 @ A dummy implementation for testing and fallback.
 <<Event base: public>>=
   public :: event_callback_nop_t
 <<Event base: types>>=
   type, extends (event_callback_t) :: event_callback_nop_t
      private
    contains
      procedure :: write => event_callback_nop_write
      procedure :: proc => event_callback_nop
   end type event_callback_nop_t
 
 @ %def event_callback_t
+<<Event base: sub interfaces>>=
+    module subroutine event_callback_nop_write (event_callback, unit)
+      class(event_callback_nop_t), intent(in) :: event_callback
+      integer, intent(in), optional :: unit
+    end subroutine event_callback_nop_write
+    module subroutine event_callback_nop (event_callback, i, event)
+      class(event_callback_nop_t), intent(in) :: event_callback
+      integer(i64), intent(in) :: i
+      class(generic_event_t), intent(in) :: event
+    end subroutine event_callback_nop
 <<Event base: procedures>>=
-  subroutine event_callback_nop_write (event_callback, unit)
+  module subroutine event_callback_nop_write (event_callback, unit)
     class(event_callback_nop_t), intent(in) :: event_callback
     integer, intent(in), optional :: unit
     integer :: u
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "NOP"
   end subroutine event_callback_nop_write
 
-  subroutine event_callback_nop (event_callback, i, event)
+  module subroutine event_callback_nop (event_callback, i, event)
     class(event_callback_nop_t), intent(in) :: event_callback
     integer(i64), intent(in) :: i
     class(generic_event_t), intent(in) :: event
   end subroutine event_callback_nop
 
 @ %def event_callback_nop_write
 @ %def event_callback_nop
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Event Handle}
 This module defines an abstract base type that allows us to communicate any
 type of event record within the program.  The concrete extensions are expected
 to consist of pointers, such as the C pointers for HepMC or LCIO events, so
 the communication object is a very light-weight one.
 <<[[event_handles.f90]]>>=
 <<File header>>
 
 module event_handles
   
 <<Standard module head>>
 
 <<Event handle: public>>
 
 <<Event handle: types>>
 
 end module event_handles
 @ %def event_handles
 @
 There is only one abstract type.
 <<Event handle: public>>=
   public :: event_handle_t
 <<Event handle: types>>=
   type, abstract :: event_handle_t
   end type event_handle_t
   
 @ %def event_handle_t
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Event Sample Data}
 We define a simple and transparent container for (meta)data that are
 associated with an event sample.
 <<[[eio_data.f90]]>>=
 <<File header>>
 
 module eio_data
 
 <<Use kinds>>
 <<Use strings>>
-  use io_units
-  use numeric_utils
-  use diagnostics
 
   use event_base
 
 <<Standard module head>>
 
 <<EIO data: public>>
 
 <<EIO data: types>>
 
+  interface
+<<EIO data: sub interfaces>>
+  end interface
+
+end module eio_data
+@ %def eio_data
+@
+<<[[eio_data_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_data) eio_data_s
+
+  use io_units
+  use numeric_utils
+  use diagnostics
+
+  implicit none
+
 contains
 
 <<EIO data: procedures>>
 
-end module eio_data
-@ %def eio_data
+end submodule eio_data_s
+
+@ %def eio_data_s
 @
 \subsection{Event Sample Data}
 These are data that apply to an event sample as a whole.  They are
 given in an easily portable form (no fancy structure) and are used for
 initializing event formats.
 
 There are two MD5 sums here.  [[md5sum_proc]] depends only on the
 definition of the contributing processes.  A sample with matching
 checksum can be rescanned with modified model parameters, beam
 structure etc, to recalculate observables.  [[md5sum_config]] includes
 all relevant data.  Rescanning a sample with matching checksum will
 produce identical observables.  (A third checksum might be added which
 depends on the event sample itself.  This is not needed, so far.)
 
 If alternate weights are part of the event sample ([[n_alt]] nonzero),
 there is a configuration MD5 sum for each of them.
 <<EIO data: public>>=
   public :: event_sample_data_t
 <<EIO data: types>>=
   type :: event_sample_data_t
      character(32) :: md5sum_prc = ""
      character(32) :: md5sum_cfg = ""
      logical :: unweighted = .true.
      logical :: negative_weights = .false.
      integer :: norm_mode = NORM_UNDEFINED
      integer :: n_beam = 0
      integer, dimension(2) :: pdg_beam = 0
      real(default), dimension(2) :: energy_beam = 0
      integer :: n_proc = 0
      integer :: n_evt = 0
      integer :: nlo_multiplier = 1
      integer :: split_n_evt = 0
      integer :: split_n_kbytes = 0
      integer :: split_index = 0
      real(default) :: total_cross_section = 0
      integer, dimension(:), allocatable :: proc_num_id
      integer :: n_alt = 0
      character(32), dimension(:), allocatable :: md5sum_alt
      real(default), dimension(:), allocatable :: cross_section
      real(default), dimension(:), allocatable :: error
    contains
    <<EIO data: event sample data: TBP>>
   end type event_sample_data_t
 
 @ %def event_sample_data_t
 @ Initialize: allocate for the number of processes
 <<EIO data: event sample data: TBP>>=
   procedure :: init => event_sample_data_init
+<<EIO data: sub interfaces>>=
+    module subroutine event_sample_data_init (data, n_proc, n_alt)
+      class(event_sample_data_t), intent(out) :: data
+      integer, intent(in) :: n_proc
+      integer, intent(in), optional :: n_alt
+    end subroutine event_sample_data_init  
 <<EIO data: procedures>>=
-  subroutine event_sample_data_init (data, n_proc, n_alt)
+  module subroutine event_sample_data_init (data, n_proc, n_alt)
     class(event_sample_data_t), intent(out) :: data
     integer, intent(in) :: n_proc
     integer, intent(in), optional :: n_alt
     data%n_proc = n_proc
     allocate (data%proc_num_id (n_proc), source = 0)
     allocate (data%cross_section (n_proc), source = 0._default)
     allocate (data%error (n_proc), source = 0._default)
     if (present (n_alt)) then
        data%n_alt = n_alt
        allocate (data%md5sum_alt (n_alt))
        data%md5sum_alt = ""
     end if
   end subroutine event_sample_data_init
 
 @ %def event_sample_data_init
 @ Output.
 <<EIO data: event sample data: TBP>>=
   procedure :: write => event_sample_data_write
+<<EIO data: sub interfaces>>=
+    module subroutine event_sample_data_write (data, unit)
+      class(event_sample_data_t), intent(in) :: data
+      integer, intent(in), optional :: unit
+    end subroutine event_sample_data_write
 <<EIO data: procedures>>=
-  subroutine event_sample_data_write (data, unit)
+  module subroutine event_sample_data_write (data, unit)
     class(event_sample_data_t), intent(in) :: data
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "Event sample properties:"
     write (u, "(3x,A,A,A)")  "MD5 sum (proc)   = '", data%md5sum_prc, "'"
     write (u, "(3x,A,A,A)")  "MD5 sum (config) = '", data%md5sum_cfg, "'"
     write (u, "(3x,A,L1)")  "unweighted       = ", data%unweighted
     write (u, "(3x,A,L1)")  "negative weights = ", data%negative_weights
     write (u, "(3x,A,A)")   "normalization    = ", &
          char (event_normalization_string (data%norm_mode))
     write (u, "(3x,A,I0)")  "number of beams  = ", data%n_beam
     write (u, "(5x,A,2(1x,I19))")  "PDG    = ", &
          data%pdg_beam(:data%n_beam)
     write (u, "(5x,A,2(1x,ES19.12))")  "Energy = ", &
          data%energy_beam(:data%n_beam)
     if (data%n_evt > 0) then
        write (u, "(3x,A,I0)")  "number of events = ", data%n_evt
     end if
     if (.not. vanishes (data%total_cross_section)) then
        write (u, "(3x,A,ES19.12)")  "total cross sec. = ", &
             data%total_cross_section
     end if
     write (u, "(3x,A,I0)")  "num of processes = ", data%n_proc
     do i = 1, data%n_proc
        write (u, "(3x,A,I0)")  "Process #", data%proc_num_id (i)
        select case (data%n_beam)
        case (1)
           write (u, "(5x,A,ES19.12)")  "Width = ", data%cross_section(i)
        case (2)
           write (u, "(5x,A,ES19.12)")  "CSec  = ", data%cross_section(i)
        end select
        write (u, "(5x,A,ES19.12)")  "Error = ", data%error(i)
     end do
     if (data%n_alt > 0) then
        write (u, "(3x,A,I0)")  "num of alt wgt   = ", data%n_alt
        do i = 1, data%n_alt
           write (u, "(5x,A,A,A,1x,I0)")  "MD5 sum (cfg)  = '", &
                data%md5sum_alt(i), "'", i
        end do
     end if
   end subroutine event_sample_data_write
 
 @ %def event_sample_data_write
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_data_ut.f90]]>>=
 <<File header>>
 
 module eio_data_ut
   use unit_tests
   use eio_data_uti
 
 <<Standard module head>>
 
 <<EIO data: public test>>
 
 contains
 
 <<EIO data: test driver>>
 
 end module eio_data_ut
 @ %def eio_data_ut
 @
 <<[[eio_data_uti.f90]]>>=
 <<File header>>
 
 module eio_data_uti
 
 <<Use kinds>>
 <<Use strings>>
   use event_base
 
   use eio_data
 
 <<Standard module head>>
 
 <<EIO data: test declarations>>
 
 contains
 
 <<EIO data: tests>>
 
 end module eio_data_uti
 @ %def eio_data_ut
 @ API: driver for the unit tests below.
 <<EIO data: public test>>=
   public :: eio_data_test
 <<EIO data: test driver>>=
   subroutine eio_data_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO data: execute tests>>
   end subroutine eio_data_test
 
 @ %def eio_data_test
 @
 \subsubsection{Event Sample Data}
 Print the contents of a sample data block.
 <<EIO data: execute tests>>=
   call test (eio_data_1, "eio_data_1", &
        "event sample data", &
        u, results)
 <<EIO data: test declarations>>=
   public :: eio_data_1
 <<EIO data: tests>>=
   subroutine eio_data_1 (u)
     integer, intent(in) :: u
     type(event_sample_data_t) :: data
 
     write (u, "(A)")  "* Test output: eio_data_1"
     write (u, "(A)")  "*   Purpose:  display event sample data"
     write (u, "(A)")
 
     write (u, "(A)")  "* Decay process, one component"
     write (u, "(A)")
 
     call data%init (1, 1)
     data%n_beam = 1
     data%pdg_beam(1) = 25
     data%energy_beam(1) = 125
 
     data%norm_mode = NORM_UNIT
 
     data%proc_num_id = [42]
     data%cross_section = [1.23e-4_default]
     data%error = 5e-6_default
 
     data%md5sum_prc = "abcdefghijklmnopabcdefghijklmnop"
     data%md5sum_cfg = "12345678901234561234567890123456"
     data%md5sum_alt(1) = "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu"
 
     call data%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Scattering process, two components"
     write (u, "(A)")
 
     call data%init (2)
     data%n_beam = 2
     data%pdg_beam = [2212, -2212]
     data%energy_beam = [8._default, 10._default]
 
     data%norm_mode = NORM_SIGMA
 
     data%proc_num_id = [12, 34]
     data%cross_section = [100._default, 88._default]
     data%error = [1._default, 0.1_default]
 
     call data%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_data_1"
 
   end subroutine eio_data_1
 
 @ %def eio_data_1
 @
 \subsubsection{Event Normalization}
 Check the functions for translating modes and updating weights.
 <<EIO data: execute tests>>=
   call test (eio_data_2, "eio_data_2", &
        "event normalization", &
        u, results)
 <<EIO data: test declarations>>=
   public :: eio_data_2
 <<EIO data: tests>>=
   subroutine eio_data_2 (u)
     integer, intent(in) :: u
     type(string_t) :: s
     logical :: unweighted
     real(default) :: w, w0, sigma
     integer :: n
 
     write (u, "(A)")  "* Test output: eio_data_2"
     write (u, "(A)")  "*   Purpose:  handle event normalization"
     write (u, "(A)")
 
     write (u, "(A)")  "* Normalization strings"
     write (u, "(A)")
 
     s = "auto"
     unweighted = .true.
     write (u, "(1x,A,1x,L1,1x,A)")  char (s), unweighted, &
          char (event_normalization_string &
          (event_normalization_mode (s, unweighted)))
     s = "AUTO"
     unweighted = .false.
     write (u, "(1x,A,1x,L1,1x,A)")  char (s), unweighted, &
          char (event_normalization_string &
          (event_normalization_mode (s, unweighted)))
 
     unweighted = .true.
 
     s = "1"
     write (u, "(2(1x,A))") char (s), char (event_normalization_string &
          (event_normalization_mode (s, unweighted)))
     s = "1/n"
     write (u, "(2(1x,A))") char (s), char (event_normalization_string &
          (event_normalization_mode (s, unweighted)))
     s = "Sigma"
     write (u, "(2(1x,A))") char (s), char (event_normalization_string &
          (event_normalization_mode (s, unweighted)))
     s = "sigma/N"
     write (u, "(2(1x,A))") char (s), char (event_normalization_string &
          (event_normalization_mode (s, unweighted)))
 
     write (u, "(A)")
     write (u, "(A)")  "* Normalization update"
     write (u, "(A)")
 
     sigma = 5
     n = 2
 
     w0 = 1
 
     w = w0
     call event_normalization_update (w, sigma, n, NORM_UNIT, NORM_UNIT)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_N_EVT, NORM_UNIT)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_SIGMA, NORM_UNIT)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_S_N, NORM_UNIT)
     write (u, "(2(F6.3))")  w0, w
 
     write (u, *)
 
     w0 = 0.5
 
     w = w0
     call event_normalization_update (w, sigma, n, NORM_UNIT, NORM_N_EVT)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_N_EVT, NORM_N_EVT)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_SIGMA, NORM_N_EVT)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_S_N, NORM_N_EVT)
     write (u, "(2(F6.3))")  w0, w
 
     write (u, *)
 
     w0 = 5.0
 
     w = w0
     call event_normalization_update (w, sigma, n, NORM_UNIT, NORM_SIGMA)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_N_EVT, NORM_SIGMA)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_SIGMA, NORM_SIGMA)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_S_N, NORM_SIGMA)
     write (u, "(2(F6.3))")  w0, w
 
     write (u, *)
 
     w0 = 2.5
 
     w = w0
     call event_normalization_update (w, sigma, n, NORM_UNIT, NORM_S_N)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_N_EVT, NORM_S_N)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_SIGMA, NORM_S_N)
     write (u, "(2(F6.3))")  w0, w
     w = w0
     call event_normalization_update (w, sigma, n, NORM_S_N, NORM_S_N)
     write (u, "(2(F6.3))")  w0, w
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_data_2"
 
   end subroutine eio_data_2
 
 @ %def eio_data_2
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Abstract I/O Handler}
 
 This module defines an abstract object for event I/O and the
 associated methods.
 
 There are [[output]] and [[input]] methods which
 write or read a single event from/to the I/O stream, respectively.
 The I/O stream itself may be a file, a common block, or an externally
 linked structure, depending on the concrete implementation.
 
 A [[write]] method prints the current content of the
 implementation-dependent event record in human-readable form.
 
 The [[init_in]]/[[init_out]] and [[final]] prepare
 and finalize the I/O stream, respectively.  There is also a
 [[switch_inout]] method which turns an input stream into an output
 stream where events can be appended.
 
 Optionally, output files can be split in chunks of well-defined size.  The
 [[split_out]] method takes care of this.
 <<[[eio_base.f90]]>>=
 <<File header>>
 
 module eio_base
 
   use kinds, only: i64
 <<Use strings>>
-  use io_units
-  use diagnostics
   use model_data
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
 
 <<Standard module head>>
 
 <<EIO base: public>>
 
 <<EIO base: types>>
 
 <<EIO base: interfaces>>
 
+  interface
+<<EIO base: sub interfaces>>
+  end interface
+
+end module eio_base
+@ %def eio_base
+@
+<<[[eio_base_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_base) eio_base_s
+
+  use io_units
+  use diagnostics
+
+  implicit none
+
 contains
 
 <<EIO base: procedures>>
 
-end module eio_base
-@ %def eio_base
+end submodule eio_base_s
+
+@ %def eio_base_s
 @
 \subsection{Type}
 We can assume that most implementations will need the file extension as a
 fixed string and, if they support file splitting, the current file index.
 
 The fallback model is useful for implementations that are able to read
 unknown files which may contain hadrons etc., not in the current
 hard-interaction model.
 <<EIO base: public>>=
   public :: eio_t
 <<EIO base: types>>=
   type, abstract :: eio_t
      type(string_t) :: sample
      type(string_t) :: extension
      type(string_t) :: filename
      logical :: has_file = .false.
      logical :: split = .false.
      integer :: split_n_evt = 0
      integer :: split_n_kbytes = 0
      integer :: split_index = 0
      integer :: split_count = 0
      class(model_data_t), pointer :: fallback_model => null ()
    contains
    <<EIO base: eio: TBP>>
   end type eio_t
 
 @ %def eio_t
 @ Write to screen.  If possible, this should display the contents of the
 current event, i.e., the last one that was written or read.
 <<EIO base: eio: TBP>>=
   procedure (eio_write), deferred :: write
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_write (object, unit)
        import
        class(eio_t), intent(in) :: object
        integer, intent(in), optional :: unit
      end subroutine eio_write
   end interface
 
 @ %def eio_write
 @ Finalize.  This should write/read footer data and close input/output
 channels.
 <<EIO base: eio: TBP>>=
   procedure (eio_final), deferred :: final
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_final (object)
        import
        class(eio_t), intent(inout) :: object
      end subroutine eio_final
   end interface
 
 @ %def eio_final
 @ Determine splitting parameters from the event sample data.
 <<EIO base: eio: TBP>>=
   procedure :: set_splitting => eio_set_splitting
+<<EIO base: sub interfaces>>=
+    module subroutine eio_set_splitting (eio, data)
+      class(eio_t), intent(inout) :: eio
+      type(event_sample_data_t), intent(in) :: data
+    end subroutine eio_set_splitting
 <<EIO base: procedures>>=
-  subroutine eio_set_splitting (eio, data)
+  module subroutine eio_set_splitting (eio, data)
     class(eio_t), intent(inout) :: eio
     type(event_sample_data_t), intent(in) :: data
     eio%split = data%split_n_evt > 0 .or. data%split_n_kbytes > 0
     if (eio%split) then
        eio%split_n_evt = data%split_n_evt
        eio%split_n_kbytes = data%split_n_kbytes
        eio%split_index = data%split_index
        eio%split_count = 0
     end if
   end subroutine eio_set_splitting
 
 @ %def eio_set_splitting
 @ Update the byte count and check if it has increased.  We use integer
 division to determine the number of [[n_kbytes]] blocks that are in
 the event file.
 <<EIO base: eio: TBP>>=
   procedure :: update_split_count => eio_update_split_count
+<<EIO base: sub interfaces>>=
+    module subroutine eio_update_split_count (eio, increased)
+      class(eio_t), intent(inout) :: eio
+      logical, intent(out) :: increased
+    end subroutine eio_update_split_count
 <<EIO base: procedures>>=
-  subroutine eio_update_split_count (eio, increased)
+  module subroutine eio_update_split_count (eio, increased)
     class(eio_t), intent(inout) :: eio
     logical, intent(out) :: increased
     integer :: split_count_old
     if (eio%split_n_kbytes > 0) then
        split_count_old = eio%split_count
        eio%split_count = eio%file_size_kbytes () / eio%split_n_kbytes
        increased = eio%split_count > split_count_old
     end if
   end subroutine eio_update_split_count
 
 @ %def eio_update_split_count
 @ Generate a filename, taking a possible split index into account.
 <<EIO base: eio: TBP>>=
   procedure :: set_filename => eio_set_filename
+<<EIO base: sub interfaces>>=
+    module subroutine eio_set_filename (eio)
+      class(eio_t), intent(inout) :: eio
+    end subroutine eio_set_filename
 <<EIO base: procedures>>=
-  subroutine eio_set_filename (eio)
+  module subroutine eio_set_filename (eio)
     class(eio_t), intent(inout) :: eio
     character(32) :: buffer
     if (eio%split) then
        write (buffer, "(I0,'.')")  eio%split_index
        eio%filename = eio%sample // "." // trim (buffer) // eio%extension
        eio%has_file = .true.
     else
        eio%filename = eio%sample // "." // eio%extension
        eio%has_file = .true.
     end if
   end subroutine eio_set_filename
 
 @ %def eio_set_filename
 @ Set the fallback model.
 <<EIO base: eio: TBP>>=
   procedure :: set_fallback_model => eio_set_fallback_model
+<<EIO base: sub interfaces>>=
+    module subroutine eio_set_fallback_model (eio, model)
+      class(eio_t), intent(inout) :: eio
+      class(model_data_t), intent(in), target :: model
+    end subroutine eio_set_fallback_model
 <<EIO base: procedures>>=
-  subroutine eio_set_fallback_model (eio, model)
+  module subroutine eio_set_fallback_model (eio, model)
     class(eio_t), intent(inout) :: eio
     class(model_data_t), intent(in), target :: model
     eio%fallback_model => model
   end subroutine eio_set_fallback_model
 
 @ %def eio_set_fallback_model
 @ Initialize for output.  We provide process names.  This should
 open an event file if appropriate and write header data.  Some methods
 may require event sample data.
 <<EIO base: eio: TBP>>=
   procedure (eio_init_out), deferred :: init_out
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_init_out (eio, sample, data, success, extension)
        import
        class(eio_t), intent(inout) :: eio
        type(string_t), intent(in) :: sample
        type(event_sample_data_t), intent(in), optional :: data
        logical, intent(out), optional :: success
        type(string_t), intent(in), optional :: extension
      end subroutine eio_init_out
   end interface
 
 @ %def eio_init_out
 @ Initialize for input.  We provide process names.  This should open an event
 file if appropriate and read header data.  The [[md5sum]] can be used to check
 the integrity of the configuration, it it provides a checksum to compare with.
 In case the extension has changed the extension is also given as an argument.
 
 The [[data]] argument is [[intent(inout)]]: we may read part of it and
 keep other parts and/or check them against the data in the file.
 <<EIO base: eio: TBP>>=
   procedure (eio_init_in), deferred :: init_in
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_init_in (eio, sample, data, success, extension)
        import
        class(eio_t), intent(inout) :: eio
        type(string_t), intent(in) :: sample
        type(event_sample_data_t), intent(inout), optional :: data
        logical, intent(out), optional :: success
        type(string_t), intent(in), optional :: extension
      end subroutine eio_init_in
   end interface
 
 @ %def eio_init_in
 @ Re-initialize for output.  This should change the status of any event file
 from input to output and position it for appending new events.
 <<EIO base: eio: TBP>>=
   procedure (eio_switch_inout), deferred :: switch_inout
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_switch_inout (eio, success)
        import
        class(eio_t), intent(inout) :: eio
        logical, intent(out), optional :: success
      end subroutine eio_switch_inout
   end interface
 
 @ %def eio_switch_inout
 @ This is similar: split the output, i.e., close the current file and open a
 new one.  The default implementation does nothing.  For the feature to work,
 an implementation must override this.
 <<EIO base: eio: TBP>>=
   procedure :: split_out => eio_split_out
+<<EIO base: sub interfaces>>=
+    module subroutine eio_split_out (eio)
+      class(eio_t), intent(inout) :: eio
+    end subroutine eio_split_out
 <<EIO base: procedures>>=
-  subroutine eio_split_out (eio)
+  module subroutine eio_split_out (eio)
     class(eio_t), intent(inout) :: eio
   end subroutine eio_split_out
 
 @ %def eio_split_out
 @ Determine the file size in kilobytes.  More exactly, determine the
 size in units of 1024 storage units, as returned by the INQUIRE statement.
 
 The implementation returns zero if there is no file.  The
 [[has_file]] flag is set by the [[set_filename]] method, so we can be
 confident that the [[inquire]] call is meaningful.  If this algorithm
 doesn't apply for a particular format, we still can override the
 procedure.
 <<EIO base: eio: TBP>>=
   procedure :: file_size_kbytes => eio_file_size_kbytes
+<<EIO base: sub interfaces>>=
+    module function eio_file_size_kbytes (eio) result (kbytes)
+      class(eio_t), intent(in) :: eio
+      integer :: kbytes
+    end function eio_file_size_kbytes
 <<EIO base: procedures>>=
-  function eio_file_size_kbytes (eio) result (kbytes)
+  module function eio_file_size_kbytes (eio) result (kbytes)
     class(eio_t), intent(in) :: eio
     integer :: kbytes
     integer(i64) :: bytes
     if (eio%has_file) then
        inquire (file = char (eio%filename), size = bytes)
        if (bytes > 0) then
           kbytes = bytes / 1024
        else
           kbytes = 0
        end if
     else
        kbytes = 0
     end if
   end function eio_file_size_kbytes
 
 @ %def eio_file_size_kbytes
 @ Output an event.  All data can be taken from the [[event]] record.
 The index [[i_prc]] identifies the process among the processes that
 are contained in the current sample.  The [[reading]] flag, if present,
 indicates that the event was read from file, not generated.
 
 The [[passed]] flag tells us that this event has passed the selection
 criteria.  Depending on the event format, we may choose to skip events
 that have not passed.
 <<EIO base: eio: TBP>>=
   procedure (eio_output), deferred :: output
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_output &
           (eio, event, i_prc, reading, passed, pacify, event_handle)
        import
        class(eio_t), intent(inout) :: eio
        class(generic_event_t), intent(in), target :: event
        integer, intent(in) :: i_prc
        logical, intent(in), optional :: reading, passed, pacify
        class(event_handle_t), intent(inout), optional :: event_handle
      end subroutine eio_output
   end interface
 
 @ %def eio_output
 @ Input an event.  This should fill all event data that cannot be inferred
 from the associated process.
 
 The input is broken down into two parts.  First we read the [[i_prc]]
 index.  So we know which process to expect in the subsequent event.
 If we have reached end of file, we also will know.
 Then, we read the event itself.
 
 The parameter [[iostat]] is supposed to be set as the Fortran standard
 requires, negative for EOF and positive for error.
 <<EIO base: eio: TBP>>=
   procedure (eio_input_i_prc), deferred :: input_i_prc
   procedure (eio_input_event), deferred :: input_event
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_input_i_prc (eio, i_prc, iostat)
        import
        class(eio_t), intent(inout) :: eio
        integer, intent(out) :: i_prc
        integer, intent(out) :: iostat
      end subroutine eio_input_i_prc
   end interface
 
   abstract interface
      subroutine eio_input_event (eio, event, iostat, event_handle)
        import
        class(eio_t), intent(inout) :: eio
        class(generic_event_t), intent(inout), target :: event
        integer, intent(out) :: iostat
        class(event_handle_t), intent(inout), optional :: event_handle
      end subroutine eio_input_event
   end interface
 
 @ %def eio_input
 @
 <<EIO base: eio: TBP>>=
   procedure (eio_skip), deferred :: skip
 <<EIO base: interfaces>>=
   abstract interface
      subroutine eio_skip (eio, iostat)
        import
        class(eio_t), intent(inout) :: eio
        integer, intent(out) :: iostat
      end subroutine eio_skip
   end interface
 
 @ %def eio_skip
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_base_ut.f90]]>>=
 <<File header>>
 
 module eio_base_ut
   use unit_tests
   use eio_base_uti
 
 <<Standard module head>>
 
 <<EIO base: public test>>
 
 <<EIO base: public test auxiliary>>
 
 contains
 
 <<EIO base: test driver>>
 
 end module eio_base_ut
 @ %def eio_base_ut
 @
 <<[[eio_base_uti.f90]]>>=
 <<File header>>
 
 module eio_base_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use lorentz
   use model_data
   use particles
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
 
   use eio_base
 
 <<Standard module head>>
 
 <<EIO base: public test auxiliary>>
 
 <<EIO base: test declarations>>
 
 <<EIO base: test types>>
 
 <<EIO base: test variables>>
 
 contains
 
 <<EIO base: tests>>
 
 <<EIO base: test auxiliary>>
 
 end module eio_base_uti
 @ %def eio_base_ut
 @ API: driver for the unit tests below.
 <<EIO base: public test>>=
   public :: eio_base_test
 <<EIO base: test driver>>=
   subroutine eio_base_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO base: execute tests>>
   end subroutine eio_base_test
 
 @ %def eio_base_test
 @ The caller has to provide procedures that prepare and cleanup the test
 environment.  They depend on modules that are not available here.
 <<EIO base: test types>>=
   abstract interface
      subroutine eio_prepare_event (event, unweighted, n_alt, sample_norm)
        import
        class(generic_event_t), intent(inout), pointer :: event
        logical, intent(in), optional :: unweighted
        integer, intent(in), optional :: n_alt
        type(string_t), intent(in), optional :: sample_norm
      end subroutine eio_prepare_event
   end interface
 
   abstract interface
      subroutine eio_cleanup_event (event)
        import
        class(generic_event_t), intent(inout), pointer :: event
      end subroutine eio_cleanup_event
   end interface
 
 @ We store pointers to the test-environment handlers as module variables.
 This allows us to call them from the test routines themselves, which don't
 allow for extra arguments.
 <<EIO base: public test auxiliary>>=
   public :: eio_prepare_test, eio_cleanup_test
 <<EIO base: test types>>=
   procedure(eio_prepare_event), pointer :: eio_prepare_test => null ()
   procedure(eio_cleanup_event), pointer :: eio_cleanup_test => null ()
 
 @ %def eio_prepare_test eio_cleanup_test
 @ Similarly, for the fallback (hadron) model that some eio tests require:
 <<EIO base: test types>>=
   abstract interface
      subroutine eio_prepare_model (model)
        import
        class(model_data_t), intent(inout), pointer :: model
      end subroutine eio_prepare_model
   end interface
 
   abstract interface
      subroutine eio_cleanup_model (model)
        import
        class(model_data_t), intent(inout), target :: model
      end subroutine eio_cleanup_model
   end interface
 
 <<EIO base: public test auxiliary>>=
   public :: eio_prepare_fallback_model, eio_cleanup_fallback_model
 <<EIO base: test variables>>=
   procedure(eio_prepare_model), pointer :: eio_prepare_fallback_model => null ()
   procedure(eio_cleanup_model), pointer :: eio_cleanup_fallback_model => null ()
 
 @ %def eio_prepare_fallback_model eio_cleanup_fallback_model
 @
 \subsubsection{Test type for event I/O}
 The contents simulate the contents of an external file.  We have the
 [[sample]] string as the file name and the array of momenta
 [[event_p]] as the list of events.  The
 second index is the event index.  The [[event_i]] component is the pointer
 to the current event, [[event_n]] is the total number of stored events.
 <<EIO base: test types>>=
   type, extends (eio_t) :: eio_test_t
      integer :: event_n = 0
      integer :: event_i = 0
      integer :: i_prc = 0
      type(vector4_t), dimension(:,:), allocatable :: event_p
    contains
    <<EIO base: eio test: TBP>>
   end type eio_test_t
 
 @ %def eio_test_t
 @ Write to screen.  Pretend that this is an actual event format.
 <<EIO base: eio test: TBP>>=
   procedure :: write => eio_test_write
 <<EIO base: test auxiliary>>=
   subroutine eio_test_write (object, unit)
     class(eio_test_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "Test event stream"
     if (object%event_i /= 0) then
        write (u, "(1x,A,I0,A)")  "Event #", object%event_i, ":"
        do i = 1, size (object%event_p, 1)
           call vector4_write (object%event_p(i, object%event_i), u)
        end do
     end if
   end subroutine eio_test_write
 
 @ %def eio_test_write
 @ Finalizer.  For the test case, we just reset the event count,
 but keep the stored ``events''.  For the real implementations, the events
 would be stored on an external medium, so we would delete the object
 contents.
 <<EIO base: eio test: TBP>>=
   procedure :: final => eio_test_final
 <<EIO base: test auxiliary>>=
   subroutine eio_test_final (object)
     class(eio_test_t), intent(inout) :: object
     object%event_i = 0
   end subroutine eio_test_final
 
 @ %def eio_test_final
 @ Initialization: We store the process IDs and the energy from the beam-data
 object.  We also allocate the momenta (i.e., the simulated event record) for a
 fixed maximum size of 10 events, 2 momenta each.  There is only a single
 process.
 <<EIO base: eio test: TBP>>=
   procedure :: init_out => eio_test_init_out
 <<EIO base: test auxiliary>>=
   subroutine eio_test_init_out (eio, sample, data, success, extension)
     class(eio_test_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     type(string_t), intent(in), optional :: extension
     eio%sample = sample
     eio%event_n = 0
     eio%event_i = 0
     allocate (eio%event_p (2, 10))
     if (present (success))  success = .true.
   end subroutine eio_test_init_out
 
 @ %def eio_test_init_out
 @ Initialization for input.  Nothing to do for the test type.
 <<EIO base: eio test: TBP>>=
   procedure :: init_in => eio_test_init_in
 <<EIO base: test auxiliary>>=
   subroutine eio_test_init_in (eio, sample, data, success, extension)
     class(eio_test_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     type(string_t), intent(in), optional :: extension
     if (present (success))  success = .true.
   end subroutine eio_test_init_in
 
 @ %def eio_test_init_in
 @ Switch from output to input.  Again, nothing to do for the test type.
 <<EIO base: eio test: TBP>>=
   procedure :: switch_inout => eio_test_switch_inout
 <<EIO base: test auxiliary>>=
   subroutine eio_test_switch_inout (eio, success)
     class(eio_test_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     if (present (success))  success = .true.
   end subroutine eio_test_switch_inout
 
 @ %def eio_test_switch_inout
 @ Output.  Increment the event counter and store the momenta of the current
 event.
 <<EIO base: eio test: TBP>>=
   procedure :: output => eio_test_output
 <<EIO base: test auxiliary>>=
   subroutine eio_test_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_test_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     integer, intent(in) :: i_prc
     type(particle_set_t), pointer :: pset
     type(particle_t) :: prt
     eio%event_n = eio%event_n + 1
     eio%event_i = eio%event_n
     eio%i_prc = i_prc
     pset => event%get_particle_set_ptr ()
     prt = pset%get_particle (3)
     eio%event_p(1, eio%event_i) = prt%get_momentum ()
     prt = pset%get_particle (4)
     eio%event_p(2, eio%event_i) = prt%get_momentum ()
   end subroutine eio_test_output
 
 @ %def eio_test_output
 @ Input.  Increment the event counter and retrieve the momenta of the current
 event.  For the test case, we do not actually modify the current event.
 <<EIO base: eio test: TBP>>=
   procedure :: input_i_prc => eio_test_input_i_prc
   procedure :: input_event => eio_test_input_event
 <<EIO base: test auxiliary>>=
   subroutine eio_test_input_i_prc (eio, i_prc, iostat)
     class(eio_test_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     i_prc = eio%i_prc
     iostat = 0
   end subroutine eio_test_input_i_prc
 
   subroutine eio_test_input_event (eio, event, iostat, event_handle)
     class(eio_test_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     eio%event_i = eio%event_i + 1
     iostat = 0
   end subroutine eio_test_input_event
 
 @ %def eio_test_input_i_prc
 @ %def eio_test_input_event
 @
 <<EIO base: eio test: TBP>>=
   procedure :: skip => eio_test_skip
 <<EIO base: test auxiliary>>=
   subroutine eio_test_skip (eio, iostat)
     class(eio_test_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_test_skip
 
 @ %def eio_test_skip
 @
 \subsubsection{Test I/O methods}
 <<EIO base: execute tests>>=
   call test (eio_base_1, "eio_base_1", &
        "read and write event contents", &
        u, results)
 <<EIO base: test declarations>>=
   public :: eio_base_1
 <<EIO base: tests>>=
   subroutine eio_base_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     class(eio_t), allocatable :: eio
     integer :: i_prc,  iostat
     type(string_t) :: sample
 
     write (u, "(A)")  "* Test output: eio_base_1"
     write (u, "(A)")  "*   Purpose: generate and read/write an event"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_test1"
 
     allocate (eio_test_t :: eio)
 
     call eio%init_out (sample)
     call event%generate (1, [0._default, 0._default])
     call eio%output (event, 42)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Re-read the event"
     write (u, "(A)")
 
     call eio%init_in (sample)
     call eio%input_i_prc (i_prc, iostat)
     call eio%input_event (event, iostat)
     call eio%write (u)
     write (u, "(A)")
     write (u, "(1x,A,I0)")  "i = ", i_prc
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and append another event"
     write (u, "(A)")
 
     call eio%switch_inout ()
     call event%generate (1, [0._default, 0._default])
     call eio%output (event, 5)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Re-read both events"
     write (u, "(A)")
 
     call eio%init_in (sample)
     call eio%input_i_prc (i_prc, iostat)
     call eio%input_event (event, iostat)
     call eio%input_i_prc (i_prc, iostat)
     call eio%input_event (event, iostat)
     call eio%write (u)
     write (u, "(A)")
     write (u, "(1x,A,I0)")  "i = ", i_prc
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
     deallocate (eio)
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_base_1"
 
   end subroutine eio_base_1
 
 @ %def eio_base_1
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Direct Event Access}
 As a convenient application of the base type, we construct an event
 handler that allows us of setting and retrieving events just in the
 same way as an file I/O format, but directly dealing with particle
 data and momenta.  This is an input and output format, but we do not
 care about counting events.
 <<[[eio_direct.f90]]>>=
 <<File header>>
 
 module eio_direct
 
 <<Use kinds>>
 <<Use strings>>
-  use io_units
-  use diagnostics
-  use cputime
   use lorentz, only: vector4_t
   use particles, only: particle_set_t
   use model_data, only: model_data_t
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
   use eio_base
 
 <<Standard module head>>
 
 <<EIO direct: public>>
 
 <<EIO direct: types>>
 
+  interface
+<<EIO direct: sub interfaces>>
+  end interface
+
+end module eio_direct
+@ %def eio_direct
+@
+<<[[eio_direct_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_direct) eio_direct_s
+
+  use io_units
+  use diagnostics
+  use cputime
+
+  implicit none
+
 contains
 
 <<EIO direct: procedures>>
 
-end module eio_direct
-@ %def eio_direct
+end submodule eio_direct_s
+
+@ %def eio_direct_s
 @
 \subsection{Type}
 <<EIO direct: public>>=
   public :: eio_direct_t
 <<EIO direct: types>>=
   type, extends (eio_t) :: eio_direct_t
      private
      logical :: i_evt_set = .false.
      integer :: i_evt = 0
      integer :: i_prc = 0
      integer :: i_mci = 0
      integer :: i_term = 0
      integer :: channel = 0
      logical :: passed_set = .false.
      logical :: passed = .true.
      type(particle_set_t) :: pset
    contains
    <<EIO direct: eio direct: TBP>>
   end type eio_direct_t
 
 @ %def eio_direct_t
 @
 \subsection{Common Methods}
 Output.
 <<EIO direct: eio direct: TBP>>=
   procedure :: write => eio_direct_write
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_write (object, unit)
+      class(eio_direct_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_direct_write
 <<EIO direct: procedures>>=
-  subroutine eio_direct_write (object, unit)
+  module subroutine eio_direct_write (object, unit)
     class(eio_direct_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "Event direct access:"
     if (object%i_evt_set) then
        write (u, "(3x,A,1x,I0)")  "i_evt =", object%i_evt
     else
        write (u, "(3x,A)")  "i_evt = [undefined]"
     end if
     write (u, "(3x,A,1x,I0)")  "i_prc =", object%i_prc
     write (u, "(3x,A,1x,I0)")  "i_mci =", object%i_prc
     write (u, "(3x,A,1x,I0)")  "i_term =", object%i_prc
     write (u, "(3x,A,1x,I0)")  "channel =", object%i_prc
     if (object%passed_set) then
        write (u, "(3x,A,1x,L1)")  "passed =", object%passed
     else
        write (u, "(3x,A)")  "passed = [N/A]"
     end if
     call object%pset%write (u)
   end subroutine eio_direct_write
 
 @ %def eio_direct_write
 @ Finalizer: trivial.
 <<EIO direct: eio direct: TBP>>=
   procedure :: final => eio_direct_final
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_final (object)
+      class(eio_direct_t), intent(inout) :: object
+    end subroutine eio_direct_final
 <<EIO direct: procedures>>=
-  subroutine eio_direct_final (object)
+  module subroutine eio_direct_final (object)
     class(eio_direct_t), intent(inout) :: object
     call object%pset%final ()
   end subroutine eio_direct_final
 
 @ %def eio_direct_final
 @ Initialize for input and/or output, both are identical
 <<EIO direct: eio direct: TBP>>=
   procedure :: init_out => eio_direct_init_out
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_direct_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_direct_init_out
 <<EIO direct: procedures>>=
-  subroutine eio_direct_init_out (eio, sample, data, success, extension)
+  module subroutine eio_direct_init_out &
+       (eio, sample, data, success, extension)
     class(eio_direct_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     if (present (success))  success = .true.
   end subroutine eio_direct_init_out
 
 @ %def eio_direct_init_out
 @
 <<EIO direct: eio direct: TBP>>=
   procedure :: init_in => eio_direct_init_in
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_init_in &
+         (eio, sample, data, success, extension)
+      class(eio_direct_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_direct_init_in
 <<EIO direct: procedures>>=
-  subroutine eio_direct_init_in (eio, sample, data, success, extension)
+  module subroutine eio_direct_init_in &
+       (eio, sample, data, success, extension)
     class(eio_direct_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     if (present (success))  success = .true.
   end subroutine eio_direct_init_in
 
 @ %def eio_direct_init_in
 @ Switch from input to output: no-op
 <<EIO direct: eio direct: TBP>>=
   procedure :: switch_inout => eio_direct_switch_inout
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_switch_inout (eio, success)
+      class(eio_direct_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_direct_switch_inout
 <<EIO direct: procedures>>=
-  subroutine eio_direct_switch_inout (eio, success)
+  module subroutine eio_direct_switch_inout (eio, success)
     class(eio_direct_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     if (present (success))  success = .true.
   end subroutine eio_direct_switch_inout
 
 @ %def eio_direct_switch_inout
 @ Output: transfer event contents from the [[event]] object to the
 [[eio]] object.  Note that finalization of the particle set is not
 (yet) automatic.
 <<EIO direct: eio direct: TBP>>=
   procedure :: output => eio_direct_output
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_direct_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_direct_output
 <<EIO direct: procedures>>=
-  subroutine eio_direct_output &
+  module subroutine eio_direct_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_direct_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     type(particle_set_t), pointer :: pset_ptr
     call eio%pset%final ()
     if (event%has_index ()) then
        call eio%set_event_index (event%get_index ())
     else
        call eio%reset_event_index ()
     end if
     if (present (passed)) then
        eio%passed = passed
        eio%passed_set = .true.
     else
        eio%passed_set = .false.
     end if
     pset_ptr => event%get_particle_set_ptr ()
     if (associated (pset_ptr)) then
        eio%i_prc = i_prc
        eio%pset = pset_ptr
     end if
   end subroutine eio_direct_output
 
 @ %def eio_direct_output
 @ Input: transfer event contents from the [[eio]] object to the
 [[event]] object.  The [[i_prc]] parameter has been stored inside the
 [[eio]] record before.
 <<EIO direct: eio direct: TBP>>=
   procedure :: input_i_prc => eio_direct_input_i_prc
   procedure :: input_event => eio_direct_input_event
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_input_i_prc (eio, i_prc, iostat)
+      class(eio_direct_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_direct_input_i_prc
+    module subroutine eio_direct_input_event (eio, event, iostat, event_handle)
+      class(eio_direct_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_direct_input_event
 <<EIO direct: procedures>>=
-  subroutine eio_direct_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_direct_input_i_prc (eio, i_prc, iostat)
     class(eio_direct_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     i_prc = eio%i_prc
     iostat = 0
   end subroutine eio_direct_input_i_prc
 
-  subroutine eio_direct_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_direct_input_event (eio, event, iostat, event_handle)
     class(eio_direct_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     call event%select (eio%i_mci, eio%i_term, eio%channel)
     if (eio%has_event_index ()) then
        call event%set_index (eio%get_event_index ())
     else
        call event%reset_index ()
     end if
     call event%set_hard_particle_set (eio%pset)
   end subroutine eio_direct_input_event
 
 @ %def eio_direct_input_i_prc
 @ %def eio_direct_input_event
 @ No-op.
 <<EIO direct: eio direct: TBP>>=
   procedure :: skip => eio_direct_skip
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_skip (eio, iostat)
+      class(eio_direct_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_direct_skip
 <<EIO direct: procedures>>=
-  subroutine eio_direct_skip (eio, iostat)
+  module subroutine eio_direct_skip (eio, iostat)
     class(eio_direct_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_direct_skip
 
 @ %def eio_direct_skip
 @
 \subsection{Retrieve individual contents}
 <<EIO direct: eio direct: TBP>>=
   procedure :: has_event_index => eio_direct_has_event_index
   procedure :: get_event_index => eio_direct_get_event_index
   procedure :: passed_known => eio_direct_passed_known
   procedure :: has_passed => eio_direct_has_passed
   procedure :: get_n_in => eio_direct_get_n_in
   procedure :: get_n_out => eio_direct_get_n_out
   procedure :: get_n_tot => eio_direct_get_n_tot
+<<EIO direct: sub interfaces>>=
+    module function eio_direct_has_event_index (eio) result (flag)
+      class(eio_direct_t), intent(in) :: eio
+      logical :: flag
+    end function eio_direct_has_event_index
+    module function eio_direct_get_event_index (eio) result (index)
+      class(eio_direct_t), intent(in) :: eio
+      integer :: index
+    end function eio_direct_get_event_index
+    module function eio_direct_passed_known (eio) result (flag)
+      class(eio_direct_t), intent(in) :: eio
+      logical :: flag
+    end function eio_direct_passed_known
+    module function eio_direct_has_passed (eio) result (flag)
+      class(eio_direct_t), intent(in) :: eio
+      logical :: flag
+    end function eio_direct_has_passed
+    module function eio_direct_get_n_in (eio) result (n_in)
+      class(eio_direct_t), intent(in) :: eio
+      integer :: n_in
+    end function eio_direct_get_n_in
+    module function eio_direct_get_n_out (eio) result (n_out)
+      class(eio_direct_t), intent(in) :: eio
+      integer :: n_out
+    end function eio_direct_get_n_out
+    module function eio_direct_get_n_tot (eio) result (n_tot)
+      class(eio_direct_t), intent(in) :: eio
+      integer :: n_tot
+    end function eio_direct_get_n_tot
 <<EIO direct: procedures>>=
-  function eio_direct_has_event_index (eio) result (flag)
+  module function eio_direct_has_event_index (eio) result (flag)
     class(eio_direct_t), intent(in) :: eio
     logical :: flag
     flag = eio%i_evt_set
   end function eio_direct_has_event_index
 
-  function eio_direct_get_event_index (eio) result (index)
+  module function eio_direct_get_event_index (eio) result (index)
     class(eio_direct_t), intent(in) :: eio
     integer :: index
     if (eio%has_event_index ()) then
        index = eio%i_evt
     else
        index = 0
     end if
   end function eio_direct_get_event_index
 
-  function eio_direct_passed_known (eio) result (flag)
+  module function eio_direct_passed_known (eio) result (flag)
     class(eio_direct_t), intent(in) :: eio
     logical :: flag
     flag = eio%passed_set
   end function eio_direct_passed_known
 
-  function eio_direct_has_passed (eio) result (flag)
+  module function eio_direct_has_passed (eio) result (flag)
     class(eio_direct_t), intent(in) :: eio
     logical :: flag
     if (eio%passed_known ()) then
        flag = eio%passed
     else
        flag = .true.
     end if
   end function eio_direct_has_passed
 
-  function eio_direct_get_n_in (eio) result (n_in)
+  module function eio_direct_get_n_in (eio) result (n_in)
     class(eio_direct_t), intent(in) :: eio
     integer :: n_in
     n_in = eio%pset%get_n_in ()
   end function eio_direct_get_n_in
 
-  function eio_direct_get_n_out (eio) result (n_out)
+  module function eio_direct_get_n_out (eio) result (n_out)
     class(eio_direct_t), intent(in) :: eio
     integer :: n_out
     n_out = eio%pset%get_n_out ()
   end function eio_direct_get_n_out
 
-  function eio_direct_get_n_tot (eio) result (n_tot)
+  module function eio_direct_get_n_tot (eio) result (n_tot)
     class(eio_direct_t), intent(in) :: eio
     integer :: n_tot
     n_tot = eio%pset%get_n_tot ()
   end function eio_direct_get_n_tot
 
 @ %def eio_direct_has_event_index
 @ %def eio_direct_get_event_index
 @ %def eio_direct_passed_known
 @ %def eio_direct_has_passed
 @ %def eio_direct_get_n_in
 @ %def eio_direct_get_n_out
 @ %def eio_direct_get_n_tot
 @ All momenta as a single allocatable array.
 <<EIO direct: eio direct: TBP>>=
   procedure :: get_momentum_array => eio_direct_get_momentum_array
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_get_momentum_array (eio, p)
+      class(eio_direct_t), intent(in) :: eio
+      type(vector4_t), dimension(:), allocatable, intent(out) :: p
+    end subroutine eio_direct_get_momentum_array
 <<EIO direct: procedures>>=
-  subroutine eio_direct_get_momentum_array (eio, p)
+  module subroutine eio_direct_get_momentum_array (eio, p)
     class(eio_direct_t), intent(in) :: eio
     type(vector4_t), dimension(:), allocatable, intent(out) :: p
     integer :: n
     n = eio%get_n_tot ()
     allocate (p (n))
     p(:) = eio%pset%get_momenta ()
   end subroutine eio_direct_get_momentum_array
 
 @ %def eio_direct_get_momentum_array
 @
 \subsection{Manual access}
 Build the contained particle set from scratch.
 <<EIO direct: eio direct: TBP>>=
   procedure :: init_direct => eio_direct_init_direct
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_init_direct &
+         (eio, n_beam, n_in, n_rem, n_vir, n_out, pdg, model)
+      class(eio_direct_t), intent(out) :: eio
+      integer, intent(in) :: n_beam
+      integer, intent(in) :: n_in
+      integer, intent(in) :: n_rem
+      integer, intent(in) :: n_vir
+      integer, intent(in) :: n_out
+      integer, dimension(:), intent(in) :: pdg
+      class(model_data_t), intent(in), target :: model
+    end subroutine eio_direct_init_direct
 <<EIO direct: procedures>>=
-  subroutine eio_direct_init_direct &
+  module subroutine eio_direct_init_direct &
        (eio, n_beam, n_in, n_rem, n_vir, n_out, pdg, model)
     class(eio_direct_t), intent(out) :: eio
     integer, intent(in) :: n_beam
     integer, intent(in) :: n_in
     integer, intent(in) :: n_rem
     integer, intent(in) :: n_vir
     integer, intent(in) :: n_out
     integer, dimension(:), intent(in) :: pdg
     class(model_data_t), intent(in), target :: model
     call eio%pset%init_direct (n_beam, n_in, n_rem, n_vir, n_out, pdg, model)
   end subroutine eio_direct_init_direct
 
 @ %def eio_direct_init_direct
 @ Set/reset the event index, which is optional.
 <<EIO direct: eio direct: TBP>>=
   procedure :: set_event_index => eio_direct_set_event_index
   procedure :: reset_event_index => eio_direct_reset_event_index
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_set_event_index (eio, index)
+      class(eio_direct_t), intent(inout) :: eio
+      integer, intent(in) :: index
+    end subroutine eio_direct_set_event_index
+    module subroutine eio_direct_reset_event_index (eio)
+      class(eio_direct_t), intent(inout) :: eio
+    end subroutine eio_direct_reset_event_index
 <<EIO direct: procedures>>=
-  subroutine eio_direct_set_event_index (eio, index)
+  module subroutine eio_direct_set_event_index (eio, index)
     class(eio_direct_t), intent(inout) :: eio
     integer, intent(in) :: index
     eio%i_evt = index
     eio%i_evt_set = .true.
   end subroutine eio_direct_set_event_index
 
-  subroutine eio_direct_reset_event_index (eio)
+  module subroutine eio_direct_reset_event_index (eio)
     class(eio_direct_t), intent(inout) :: eio
     eio%i_evt_set = .false.
   end subroutine eio_direct_reset_event_index
 
 @ %def eio_direct_set_event_index
 @ %def eio_direct_reset_event_index
 @ Set the selection indices.  This is supposed to select the [[i_prc]],
 [[i_mci]], [[i_term]], and [[channel]]
 entries of the event where the momentum set has to be stored, respectively.
 The selection indices determine the process, MCI set, calculation term, and
 phase-space channel is to be used for recalculation.  The index values must
 not be zero, even if the do not apply.
 <<EIO direct: eio direct: TBP>>=
   procedure :: set_selection_indices => eio_direct_set_selection_indices
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_set_selection_indices &
+         (eio, i_prc, i_mci, i_term, channel)
+      class(eio_direct_t), intent(inout) :: eio
+      integer, intent(in) :: i_prc
+      integer, intent(in) :: i_mci
+      integer, intent(in) :: i_term
+      integer, intent(in) :: channel
+    end subroutine eio_direct_set_selection_indices
 <<EIO direct: procedures>>=
-  subroutine eio_direct_set_selection_indices &
+  module subroutine eio_direct_set_selection_indices &
        (eio, i_prc, i_mci, i_term, channel)
     class(eio_direct_t), intent(inout) :: eio
     integer, intent(in) :: i_prc
     integer, intent(in) :: i_mci
     integer, intent(in) :: i_term
     integer, intent(in) :: channel
     eio%i_prc = i_prc
     eio%i_mci = i_mci
     eio%i_term = i_term
     eio%channel = channel
   end subroutine eio_direct_set_selection_indices
 
 @ %def eio_direct_set_i_prc
 @ Set momentum (or momenta -- elemental).
 <<EIO direct: eio direct: TBP>>=
   generic :: set_momentum => set_momentum_single
   generic :: set_momentum => set_momentum_all
   procedure :: set_momentum_single => eio_direct_set_momentum_single
   procedure :: set_momentum_all => eio_direct_set_momentum_all
+<<EIO direct: sub interfaces>>=
+    module subroutine eio_direct_set_momentum_single (eio, i, p, p2, on_shell)
+      class(eio_direct_t), intent(inout) :: eio
+      integer, intent(in) :: i
+      type(vector4_t), intent(in) :: p
+      real(default), intent(in), optional :: p2
+      logical, intent(in), optional :: on_shell
+    end subroutine eio_direct_set_momentum_single
+    module subroutine eio_direct_set_momentum_all (eio, p, p2, on_shell)
+      class(eio_direct_t), intent(inout) :: eio
+      type(vector4_t), dimension(:), intent(in) :: p
+      real(default), dimension(:), intent(in), optional :: p2
+      logical, intent(in), optional :: on_shell
+    end subroutine eio_direct_set_momentum_all
 <<EIO direct: procedures>>=
-  subroutine eio_direct_set_momentum_single (eio, i, p, p2, on_shell)
+  module subroutine eio_direct_set_momentum_single (eio, i, p, p2, on_shell)
     class(eio_direct_t), intent(inout) :: eio
     integer, intent(in) :: i
     type(vector4_t), intent(in) :: p
     real(default), intent(in), optional :: p2
     logical, intent(in), optional :: on_shell
     call eio%pset%set_momentum (i, p, p2, on_shell)
   end subroutine eio_direct_set_momentum_single
 
-  subroutine eio_direct_set_momentum_all (eio, p, p2, on_shell)
+  module subroutine eio_direct_set_momentum_all (eio, p, p2, on_shell)
     class(eio_direct_t), intent(inout) :: eio
     type(vector4_t), dimension(:), intent(in) :: p
     real(default), dimension(:), intent(in), optional :: p2
     logical, intent(in), optional :: on_shell
     call eio%pset%set_momentum (p, p2, on_shell)
   end subroutine eio_direct_set_momentum_all
 
 @ %def eio_direct_set_momentum
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_direct_ut.f90]]>>=
 <<File header>>
 
 module eio_direct_ut
   use unit_tests
   use eio_direct_uti
 
 <<Standard module head>>
 
 <<EIO direct: public test>>
 
 contains
 
 <<EIO direct: test driver>>
 
 end module eio_direct_ut
 @ %def eio_direct_ut
 @
 <<[[eio_direct_uti.f90]]>>=
 <<File header>>
 
 module eio_direct_uti
 
 <<Use kinds>>
 <<Use strings>>
   use lorentz, only: vector4_t
   use model_data, only: model_data_t
   use event_base
   use eio_data
   use eio_base
 
   use eio_direct
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
 
 <<Standard module head>>
 
 <<EIO direct: test declarations>>
 
 contains
 
 <<EIO direct: tests>>
 
 end module eio_direct_uti
 @ %def eio_direct_ut
 @ API: driver for the unit tests below.
 <<EIO direct: public test>>=
   public :: eio_direct_test
 <<EIO direct: test driver>>=
   subroutine eio_direct_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO direct: execute tests>>
   end subroutine eio_direct_test
 
 @ %def eio_direct_test
 @
 \subsubsection{Test I/O methods}
 We test the implementation of all I/O methods.
 <<EIO direct: execute tests>>=
   call test (eio_direct_1, "eio_direct_1", &
        "read and write event contents", &
        u, results)
 <<EIO direct: test declarations>>=
   public :: eio_direct_1
 <<EIO direct: tests>>=
   subroutine eio_direct_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     class(eio_t), allocatable :: eio
     type(event_sample_data_t) :: data
     type(string_t) :: sample
     type(vector4_t), dimension(:), allocatable :: p
     class(model_data_t), pointer :: model
     integer :: i, n_events, iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_direct_1"
     write (u, "(A)")  "*   Purpose: generate and read/write an event"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     write (u, "(A)")
     write (u, "(A)")  "* Initial state"
     write (u, "(A)")
 
     allocate (eio_direct_t :: eio)
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Extract an empty event"
     write (u, "(A)")
 
     call eio%output (event, 1)
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Retrieve contents"
     write (u, "(A)")
 
     select type (eio)
     class is (eio_direct_t)
        if (eio%has_event_index ())  write (u, "(A,1x,I0)")  "index =", eio%get_event_index ()
        if (eio%passed_known ())  write (u, "(A,1x,L1)")  "passed =", eio%has_passed ()
        write (u, "(A,1x,I0)")  "n_in =", eio%get_n_in ()
        write (u, "(A,1x,I0)")  "n_out =", eio%get_n_out ()
     end select
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and extract an event"
     write (u, "(A)")
 
     call event%generate (1, [0._default, 0._default])
     call event%set_index (42)
     model => event%get_model_ptr ()
 
     sample = ""
     call eio%init_out (sample)
     call eio%output (event, 1, passed = .true.)
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Retrieve contents"
     write (u, "(A)")
 
     select type (eio)
     class is (eio_direct_t)
        if (eio%has_event_index ())  write (u, "(A,1x,I0)")  "index =", eio%get_event_index ()
        if (eio%passed_known ())  write (u, "(A,1x,L1)")  "passed =", eio%has_passed ()
        write (u, "(A,1x,I0)")  "n_in =", eio%get_n_in ()
        write (u, "(A,1x,I0)")  "n_out =", eio%get_n_out ()
     end select
 
     select type (eio)
     class is (eio_direct_t)
        call eio%get_momentum_array (p)
        if (allocated (p)) then
           write (u, "(A)")  "p[3] ="
           call p(3)%write (u)
        end if
     end select
 
     write (u, "(A)")
     write (u, "(A)")  "* Re-create an eio event record: initialization"
     write (u, "(A)")
 
     call eio%final ()
 
     select type (eio)
     class is (eio_direct_t)
        call eio%init_direct ( &
             n_beam = 0, n_in = 2, n_rem = 0, n_vir = 0, n_out = 2, &
             pdg = [25, 25, 25, 25], model = model)
        call eio%set_event_index (42)
        call eio%set_selection_indices (1, 1, 1, 1)
        call eio%write (u)
     end select
 
     write (u, "(A)")
     write (u, "(A)")  "* Re-create an eio event record: &
          &set momenta, interchanged"
     write (u, "(A)")
 
     select type (eio)
     class is (eio_direct_t)
        call eio%set_momentum (p([1,2,4,3]), on_shell=.true.)
        call eio%write (u)
     end select
 
     write (u, "(A)")
     write (u, "(A)")  "* 'read' i_prc"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(1x,A,1x,I0)")  "i_prc =", i_prc
     write (u, "(1x,A,1x,I0)")  "iostat =", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* 'read' (fill) event"
     write (u, "(A)")
 
     call eio%input_event (event, iostat)
     write (u, "(1x,A,1x,I0)")  "iostat =", iostat
     write (u, "(A)")
 
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
     deallocate (eio)
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_direct_1"
 
   end subroutine eio_direct_1
 
 @ %def eio_direct_1
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Event Generation Checkpoints}
 This is an output-only format.  Its only use is to write screen
 messages every $n$ events, to inform the user about progress.
 <<[[eio_checkpoints.f90]]>>=
 <<File header>>
 
 module eio_checkpoints
 
 <<Use strings>>
-  use io_units
-  use diagnostics
   use cputime
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
   use eio_base
 
 <<Standard module head>>
 
 <<EIO checkpoints: public>>
 
-<<EIO checkpoints: parameters>>
-
 <<EIO checkpoints: types>>
 
+  interface
+<<EIO checkpoints: sub interfaces>>
+  end interface
+
+end module eio_checkpoints
+@ %def eio_checkpoints
+@
+<<[[eio_checkpoints_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_checkpoints) eio_checkpoints_s
+
+  use io_units
+  use diagnostics
+
+  implicit none
+
+<<EIO checkpoints: parameters>>
+
 contains
 
 <<EIO checkpoints: procedures>>
 
-end module eio_checkpoints
-@ %def eio_checkpoints
+end submodule eio_checkpoints_s
+
+@ %def eio_checkpoints_s
 @
 \subsection{Type}
 <<EIO checkpoints: public>>=
   public :: eio_checkpoints_t
 <<EIO checkpoints: types>>=
   type, extends (eio_t) :: eio_checkpoints_t
      logical :: active = .false.
      logical :: running = .false.
      integer :: val = 0
      integer :: n_events = 0
      integer :: n_read = 0
      integer :: i_evt = 0
      logical :: blank = .false.
      type(timer_t) :: timer
    contains
    <<EIO checkpoints: eio checkpoints: TBP>>
   end type eio_checkpoints_t
 
 @ %def eio_checkpoints_t
 @
 \subsection{Specific Methods}
 Set parameters that are specifically used for checkpointing.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: set_parameters => eio_checkpoints_set_parameters
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_set_parameters (eio, checkpoint, blank)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      integer, intent(in) :: checkpoint
+      logical, intent(in), optional :: blank
+    end subroutine eio_checkpoints_set_parameters
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_set_parameters (eio, checkpoint, blank)
+  module subroutine eio_checkpoints_set_parameters (eio, checkpoint, blank)
     class(eio_checkpoints_t), intent(inout) :: eio
     integer, intent(in) :: checkpoint
     logical, intent(in), optional :: blank
     eio%val = checkpoint
     if (present (blank))  eio%blank = blank
   end subroutine eio_checkpoints_set_parameters
 
 @ %def eio_checkpoints_set_parameters
 @
 \subsection{Common Methods}
 Output.  This is not the actual event format, but a readable account
 of the current status.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: write => eio_checkpoints_write
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_write (object, unit)
+      class(eio_checkpoints_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_checkpoints_write
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_write (object, unit)
+  module subroutine eio_checkpoints_write (object, unit)
     class(eio_checkpoints_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u
     u = given_output_unit (unit)
     if (object%active) then
        write (u, "(1x,A)")  "Event-sample checkpoints:  active"
        write (u, "(3x,A,I0)")  "interval  = ", object%val
        write (u, "(3x,A,I0)")  "n_events  = ", object%n_events
        write (u, "(3x,A,I0)")  "n_read    = ", object%n_read
        write (u, "(3x,A,I0)")  "n_current = ", object%i_evt
        write (u, "(3x,A,L1)")  "blanking  = ", object%blank
        call object%timer%write (u)
     else
        write (u, "(1x,A)")  "Event-sample checkpoints:  off"
     end if
   end subroutine eio_checkpoints_write
 
 @ %def eio_checkpoints_write
 @ Finalizer: trivial.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: final => eio_checkpoints_final
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_final (object)
+      class(eio_checkpoints_t), intent(inout) :: object
+    end subroutine eio_checkpoints_final
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_final (object)
+  module subroutine eio_checkpoints_final (object)
     class(eio_checkpoints_t), intent(inout) :: object
     object%active = .false.
   end subroutine eio_checkpoints_final
 
 @ %def eio_checkpoints_final
 @ Activate checkpointing for event generation or writing.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: init_out => eio_checkpoints_init_out
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_checkpoints_init_out
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_init_out (eio, sample, data, success, extension)
+  module subroutine eio_checkpoints_init_out &
+       (eio, sample, data, success, extension)
     class(eio_checkpoints_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     if (present (data)) then
        if (eio%val > 0) then
           eio%active = .true.
           eio%i_evt = 0
           eio%n_read = 0
           eio%n_events = data%n_evt * data%nlo_multiplier
        end if
     end if
     if (present (success))  success = .true.
   end subroutine eio_checkpoints_init_out
 
 @ %def eio_checkpoints_init_out
 @ No checkpointing for event reading.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: init_in => eio_checkpoints_init_in
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_init_in &
+         (eio, sample, data, success, extension)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_checkpoints_init_in
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_init_in (eio, sample, data, success, extension)
+  module subroutine eio_checkpoints_init_in &
+       (eio, sample, data, success, extension)
     class(eio_checkpoints_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     call msg_bug ("Event checkpoints: event input not supported")
     if (present (success))  success = .false.
   end subroutine eio_checkpoints_init_in
 
 @ %def eio_checkpoints_init_in
 @ Switch from input to output: also not supported.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: switch_inout => eio_checkpoints_switch_inout
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_switch_inout (eio, success)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_checkpoints_switch_inout
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_switch_inout (eio, success)
+  module subroutine eio_checkpoints_switch_inout (eio, success)
     class(eio_checkpoints_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("Event checkpoints: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_checkpoints_switch_inout
 
 @ %def eio_checkpoints_switch_inout
 @ Checkpoints: display progress for the current event, if applicable.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: output => eio_checkpoints_output
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_checkpoints_output
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_output &
+  module subroutine eio_checkpoints_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_checkpoints_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     logical :: rd
     rd = .false.;  if (present (reading))  rd = reading
     if (eio%active) then
        if (.not. eio%running)  call eio%startup ()
        if (eio%running) then
           eio%i_evt = eio%i_evt + 1
           if (rd) then
              eio%n_read = eio%n_read + 1
           else if (mod (eio%i_evt, eio%val) == 0) then
              call eio%message (eio%blank)
           end if
           if (eio%i_evt == eio%n_events)  call eio%shutdown ()
        end if
     end if
   end subroutine eio_checkpoints_output
 
 @ %def eio_checkpoints_output
 @ When the first event is called, we have to initialize the screen output.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: startup => eio_checkpoints_startup
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_startup (eio)
+      class(eio_checkpoints_t), intent(inout) :: eio
+    end subroutine eio_checkpoints_startup
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_startup (eio)
+  module subroutine eio_checkpoints_startup (eio)
     class(eio_checkpoints_t), intent(inout) :: eio
     if (eio%active .and. eio%i_evt < eio%n_events) then
        call msg_message ("")
        call msg_message (checkpoint_bar)
        call msg_message (checkpoint_head)
        call msg_message (checkpoint_bar)
        write (msg_buffer, checkpoint_fmt) 0., 0, eio%n_events - eio%i_evt, "???"
        call msg_message ()
        eio%running = .true.
        call eio%timer%start ()
     end if
   end subroutine eio_checkpoints_startup
 
 @ %def eio_checkpoints_startup
 @ This message is printed at every checkpoint.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: message => eio_checkpoints_message
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_message (eio, testflag)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      logical, intent(in), optional :: testflag
+    end subroutine eio_checkpoints_message
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_message (eio, testflag)
+  module subroutine eio_checkpoints_message (eio, testflag)
     class(eio_checkpoints_t), intent(inout) :: eio
     logical, intent(in), optional :: testflag
     real :: t
     type(time_t) :: time_remaining
     type(string_t) :: time_string
     call eio%timer%stop ()
     t = eio%timer
     call eio%timer%restart ()
     time_remaining = &
          nint (t / (eio%i_evt - eio%n_read) * (eio%n_events - eio%i_evt))
     time_string = time_remaining%to_string_ms (blank = testflag)
     write (msg_buffer, checkpoint_fmt) &
          100 * (eio%i_evt - eio%n_read) / real (eio%n_events - eio%n_read), &
          eio%i_evt - eio%n_read, &
          eio%n_events - eio%i_evt, &
          char (time_string)
     call msg_message ()
   end subroutine eio_checkpoints_message
 
 @ %def eio_checkpoints_message
 @ When the last event is called, wrap up.
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: shutdown => eio_checkpoints_shutdown
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_shutdown (eio)
+      class(eio_checkpoints_t), intent(inout) :: eio
+    end subroutine eio_checkpoints_shutdown
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_shutdown (eio)
+  module subroutine eio_checkpoints_shutdown (eio)
     class(eio_checkpoints_t), intent(inout) :: eio
     if (mod (eio%i_evt, eio%val) /= 0) then
        write (msg_buffer, checkpoint_fmt) &
             100., eio%i_evt - eio%n_read, 0, "0m:00s"
        call msg_message ()
     end if
     call msg_message (checkpoint_bar)
     call msg_message ("")
     eio%running = .false.
   end subroutine eio_checkpoints_shutdown
 
 @ %def eio_checkpoints_shutdown
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: input_i_prc => eio_checkpoints_input_i_prc
   procedure :: input_event => eio_checkpoints_input_event
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_input_i_prc (eio, i_prc, iostat)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_checkpoints_input_i_prc
+    module subroutine eio_checkpoints_input_event &
+         (eio, event, iostat, event_handle)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_checkpoints_input_event
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_checkpoints_input_i_prc (eio, i_prc, iostat)
     class(eio_checkpoints_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     call msg_bug ("Event checkpoints: event input not supported")
     i_prc = 0
     iostat = 1
   end subroutine eio_checkpoints_input_i_prc
 
-  subroutine eio_checkpoints_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_checkpoints_input_event &
+       (eio, event, iostat, event_handle)
     class(eio_checkpoints_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     call msg_bug ("Event checkpoints: event input not supported")
     iostat = 1
   end subroutine eio_checkpoints_input_event
 
 @ %def eio_checkpoints_input_i_prc
 @ %def eio_checkpoints_input_event
 @
 <<EIO checkpoints: eio checkpoints: TBP>>=
   procedure :: skip => eio_checkpoints_skip
+<<EIO checkpoints: sub interfaces>>=
+    module subroutine eio_checkpoints_skip (eio, iostat)
+      class(eio_checkpoints_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_checkpoints_skip
 <<EIO checkpoints: procedures>>=
-  subroutine eio_checkpoints_skip (eio, iostat)
+  module subroutine eio_checkpoints_skip (eio, iostat)
     class(eio_checkpoints_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_checkpoints_skip
 
 @ %def eio_checkpoints_skip
 @
 \subsection{Message header}
 <<EIO checkpoints: parameters>>=
   character(*), parameter :: &
      checkpoint_head = "| % complete | events generated | events remaining &
      &| time remaining"
   character(*), parameter :: &
      checkpoint_bar  = "|==================================================&
      &=================|"
   character(*), parameter :: &
      checkpoint_fmt  = "('   ',F5.1,T16,I9,T35,I9,T58,A)"
 @ %def checkpoint_head
 @ %def checkpoint_bar
 @ %def checkpoint_fmt
 @ %def checkpointing_t
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_checkpoints_ut.f90]]>>=
 <<File header>>
 
 module eio_checkpoints_ut
   use unit_tests
   use eio_checkpoints_uti
 
 <<Standard module head>>
 
 <<EIO checkpoints: public test>>
 
 contains
 
 <<EIO checkpoints: test driver>>
 
 end module eio_checkpoints_ut
 @ %def eio_checkpoints_ut
 @
 <<[[eio_checkpoints_uti.f90]]>>=
 <<File header>>
 
 module eio_checkpoints_uti
 
 <<Use kinds>>
 <<Use strings>>
   use event_base
   use eio_data
   use eio_base
 
   use eio_checkpoints
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
 
 <<Standard module head>>
 
 <<EIO checkpoints: test declarations>>
 
 contains
 
 <<EIO checkpoints: tests>>
 
 end module eio_checkpoints_uti
 @ %def eio_checkpoints_ut
 @ API: driver for the unit tests below.
 <<EIO checkpoints: public test>>=
   public :: eio_checkpoints_test
 <<EIO checkpoints: test driver>>=
   subroutine eio_checkpoints_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO checkpoints: execute tests>>
   end subroutine eio_checkpoints_test
 
 @ %def eio_checkpoints_test
 @
 \subsubsection{Test I/O methods}
 We test the implementation of all I/O methods.
 <<EIO checkpoints: execute tests>>=
   call test (eio_checkpoints_1, "eio_checkpoints_1", &
        "read and write event contents", &
        u, results)
 <<EIO checkpoints: test declarations>>=
   public :: eio_checkpoints_1
 <<EIO checkpoints: tests>>=
   subroutine eio_checkpoints_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     class(eio_t), allocatable :: eio
     type(event_sample_data_t) :: data
     type(string_t) :: sample
     integer :: i, n_events
 
     write (u, "(A)")  "* Test output: eio_checkpoints_1"
     write (u, "(A)")  "*   Purpose: generate a number of events &
          &with screen output"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate events"
     write (u, "(A)")
 
     sample = "eio_checkpoints_1"
 
     allocate (eio_checkpoints_t :: eio)
 
     n_events = 10
     call data%init (1, 0)
     data%n_evt = n_events
 
     select type (eio)
     type is (eio_checkpoints_t)
        call eio%set_parameters (checkpoint = 4)
     end select
 
     call eio%init_out (sample, data)
 
     do i = 1, n_events
        call event%generate (1, [0._default, 0._default])
        call eio%output (event, i_prc = 0)
     end do
 
     write (u, "(A)")  "* Checkpointing status"
     write (u, "(A)")
 
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_checkpoints_1"
 
   end subroutine eio_checkpoints_1
 
 @ %def eio_checkpoints_1
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Event Generation Callback}
 This is an output-only format.  Its only use is to write screen
 messages every $n$ events, to inform the user about progress.
 <<[[eio_callback.f90]]>>=
 <<File header>>
 
 module eio_callback
 
   use kinds, only: i64
 <<Use strings>>
-  use io_units
-  use diagnostics
   use cputime
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
   use eio_base
 
 <<Standard module head>>
 
 <<EIO callback: public>>
 
 <<EIO callback: types>>
 
+  interface
+<<EIO callback: sub interfaces>>
+  end interface
+
+end module eio_callback
+@ %def eio_callback
+@
+<<[[eio_callback_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_callback) eio_callback_s
+
+  use io_units
+  use diagnostics
+
+  implicit none
+
 contains
 
 <<EIO callback: procedures>>
 
-end module eio_callback
-@ %def eio_callback
+end submodule eio_callback_s
+
+@ %def eio_callback_s
 @
 \subsection{Type}
 <<EIO callback: public>>=
   public :: eio_callback_t
 <<EIO callback: types>>=
   type, extends (eio_t) :: eio_callback_t
      class(event_callback_t), allocatable :: callback
      integer(i64) :: i_evt = 0
      integer :: i_interval = 0
      integer :: n_interval = 0
 !      type(timer_t) :: timer
    contains
    <<EIO callback: eio callback: TBP>>
   end type eio_callback_t
 
 @ %def eio_callback_t
 @
 \subsection{Specific Methods}
 Set parameters that are specifically used for callback: the procedure
 and the number of events to wait until the procedure is called (again).
 <<EIO callback: eio callback: TBP>>=
   procedure :: set_parameters => eio_callback_set_parameters
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_set_parameters &
+         (eio, callback, count_interval)
+      class(eio_callback_t), intent(inout) :: eio
+      class(event_callback_t), intent(in) :: callback
+      integer, intent(in) :: count_interval
+    end subroutine eio_callback_set_parameters
 <<EIO callback: procedures>>=
-  subroutine eio_callback_set_parameters (eio, callback, count_interval)
+  module subroutine eio_callback_set_parameters &
+       (eio, callback, count_interval)
     class(eio_callback_t), intent(inout) :: eio
     class(event_callback_t), intent(in) :: callback
     integer, intent(in) :: count_interval
     allocate (eio%callback, source = callback)
     eio%n_interval = count_interval
   end subroutine eio_callback_set_parameters
 
 @ %def eio_callback_set_parameters
 @
 \subsection{Common Methods}
 Output.  This is not the actual event format, but a readable account
 of the current status.
 <<EIO callback: eio callback: TBP>>=
   procedure :: write => eio_callback_write
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_write (object, unit)
+      class(eio_callback_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_callback_write
 <<EIO callback: procedures>>=
-  subroutine eio_callback_write (object, unit)
+  module subroutine eio_callback_write (object, unit)
     class(eio_callback_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "Event-sample callback:"
     write (u, "(3x,A,I0)")  "interval  = ", object%n_interval
     write (u, "(3x,A,I0)")  "evt count = ", object%i_evt
 !        call object%timer%write (u)
   end subroutine eio_callback_write
 
 @ %def eio_callback_write
 @ Finalizer: trivial.
 <<EIO callback: eio callback: TBP>>=
   procedure :: final => eio_callback_final
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_final (object)
+      class(eio_callback_t), intent(inout) :: object
+    end subroutine eio_callback_final
 <<EIO callback: procedures>>=
-  subroutine eio_callback_final (object)
+  module subroutine eio_callback_final (object)
     class(eio_callback_t), intent(inout) :: object
   end subroutine eio_callback_final
 
 @ %def eio_callback_final
 @ Activate checkpointing for event generation or writing.
 <<EIO callback: eio callback: TBP>>=
   procedure :: init_out => eio_callback_init_out
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_callback_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_callback_init_out
 <<EIO callback: procedures>>=
-  subroutine eio_callback_init_out (eio, sample, data, success, extension)
+  module subroutine eio_callback_init_out &
+       (eio, sample, data, success, extension)
     class(eio_callback_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     eio%i_evt = 0
-    eiO%i_interval = 0
+    eio%i_interval = 0
     if (present (success))  success = .true.
   end subroutine eio_callback_init_out
 
 @ %def eio_callback_init_out
 @ No callback for event reading.
 <<EIO callback: eio callback: TBP>>=
   procedure :: init_in => eio_callback_init_in
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_init_in &
+         (eio, sample, data, success, extension)
+      class(eio_callback_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_callback_init_in
 <<EIO callback: procedures>>=
-  subroutine eio_callback_init_in (eio, sample, data, success, extension)
+  module subroutine eio_callback_init_in &
+       (eio, sample, data, success, extension)
     class(eio_callback_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     call msg_bug ("Event callback: event input not supported")
     if (present (success))  success = .false.
   end subroutine eio_callback_init_in
 
 @ %def eio_callback_init_in
 @ Switch from input to output: also not supported.
 <<EIO callback: eio callback: TBP>>=
   procedure :: switch_inout => eio_callback_switch_inout
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_switch_inout (eio, success)
+      class(eio_callback_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_callback_switch_inout
 <<EIO callback: procedures>>=
-  subroutine eio_callback_switch_inout (eio, success)
+  module subroutine eio_callback_switch_inout (eio, success)
     class(eio_callback_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("Event callback: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_callback_switch_inout
 
 @ %def eio_callback_switch_inout
 @ The actual callback.  First increment counters, then call the
 procedure if the counter hits the interval.
 <<EIO callback: eio callback: TBP>>=
   procedure :: output => eio_callback_output
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_callback_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_callback_output
 <<EIO callback: procedures>>=
-  subroutine eio_callback_output &
+  module subroutine eio_callback_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_callback_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     eio%i_evt = eio%i_evt + 1
     if (eio%n_interval > 0) then
        eio%i_interval = eio%i_interval + 1
        if (eio%i_interval >= eio%n_interval) then
           call eio%callback%proc (eio%i_evt, event)
           eio%i_interval = 0
        end if
     end if
   end subroutine eio_callback_output
 
 @ %def eio_callback_output
 @ No input.
 <<EIO callback: eio callback: TBP>>=
   procedure :: input_i_prc => eio_callback_input_i_prc
   procedure :: input_event => eio_callback_input_event
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_input_i_prc (eio, i_prc, iostat)
+      class(eio_callback_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_callback_input_i_prc
+    module subroutine eio_callback_input_event &
+         (eio, event, iostat, event_handle)
+      class(eio_callback_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_callback_input_event
 <<EIO callback: procedures>>=
-  subroutine eio_callback_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_callback_input_i_prc (eio, i_prc, iostat)
     class(eio_callback_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     call msg_bug ("Event callback: event input not supported")
     i_prc = 0
     iostat = 1
   end subroutine eio_callback_input_i_prc
 
-  subroutine eio_callback_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_callback_input_event &
+       (eio, event, iostat, event_handle)
     class(eio_callback_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     call msg_bug ("Event callback: event input not supported")
     iostat = 1
   end subroutine eio_callback_input_event
 
 @ %def eio_callback_input_i_prc
 @ %def eio_callback_input_event
 @
 <<EIO callback: eio callback: TBP>>=
   procedure :: skip => eio_callback_skip
+<<EIO callback: sub interfaces>>=
+    module subroutine eio_callback_skip (eio, iostat)
+      class(eio_callback_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_callback_skip
 <<EIO callback: procedures>>=
-  subroutine eio_callback_skip (eio, iostat)
+  module subroutine eio_callback_skip (eio, iostat)
     class(eio_callback_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_callback_skip
 
 @ %def eio_callback_skip
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Event Weight Output}
 This is an output-only format.  For each event, we print the indices
 that identify process, process part (MCI group), and term.  As
 numerical information we print the squared matrix element (trace) and
 the event weight.
 <<[[eio_weights.f90]]>>=
 <<File header>>
 
 module eio_weights
 
 <<Use kinds>>
 <<Use strings>>
-  use io_units
-  use diagnostics
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
   use eio_base
 
 <<Standard module head>>
 
 <<EIO weights: public>>
 
 <<EIO weights: types>>
 
+  interface
+<<EIO weights: sub interfaces>>
+  end interface
+
+end module eio_weights
+@ %def eio_weights
+@
+<<[[eio_weights_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_weights) eio_weights_s
+
+  use io_units
+  use diagnostics
+
+  implicit none
+
 contains
 
 <<EIO weights: procedures>>
 
-end module eio_weights
-@ %def eio_weights
+end submodule eio_weights_s
+
+@ %def eio_weights_s
 @
 \subsection{Type}
 <<EIO weights: public>>=
   public :: eio_weights_t
 <<EIO weights: types>>=
   type, extends (eio_t) :: eio_weights_t
      logical :: writing = .false.
      integer :: unit = 0
      logical :: pacify = .false.
    contains
    <<EIO weights: eio weights: TBP>>
   end type eio_weights_t
 
 @ %def eio_weights_t
 @
 \subsection{Specific Methods}
 Set pacify flags.
 <<EIO weights: eio weights: TBP>>=
   procedure :: set_parameters => eio_weights_set_parameters
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_set_parameters (eio, pacify)
+      class(eio_weights_t), intent(inout) :: eio
+      logical, intent(in), optional :: pacify
+    end subroutine eio_weights_set_parameters
 <<EIO weights: procedures>>=
-  subroutine eio_weights_set_parameters (eio, pacify)
+  module subroutine eio_weights_set_parameters (eio, pacify)
     class(eio_weights_t), intent(inout) :: eio
     logical, intent(in), optional :: pacify
     if (present (pacify))  eio%pacify = pacify
     eio%extension = "weights.dat"
   end subroutine eio_weights_set_parameters
 
 @ %def eio_weights_set_parameters
 @
 \subsection{Common Methods}
 @ Output.  This is not the actual event format, but a readable account
 of the current object status.
 <<EIO weights: eio weights: TBP>>=
   procedure :: write => eio_weights_write
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_write (object, unit)
+      class(eio_weights_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_weights_write
 <<EIO weights: procedures>>=
-  subroutine eio_weights_write (object, unit)
+  module subroutine eio_weights_write (object, unit)
     class(eio_weights_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "Weight stream:"
     if (object%writing) then
        write (u, "(3x,A,A)")  "Writing to file   = ", char (object%filename)
        write (u, "(3x,A,L1)") "Reduced I/O prec. = ", object%pacify
     else
        write (u, "(3x,A)")  "[closed]"
     end if
   end subroutine eio_weights_write
 
 @ %def eio_weights_write
 @ Finalizer: close any open file.
 <<EIO weights: eio weights: TBP>>=
   procedure :: final => eio_weights_final
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_final (object)
+      class(eio_weights_t), intent(inout) :: object
+    end subroutine eio_weights_final
 <<EIO weights: procedures>>=
-  subroutine eio_weights_final (object)
+  module subroutine eio_weights_final (object)
     class(eio_weights_t), intent(inout) :: object
     if (object%writing) then
        write (msg_buffer, "(A,A,A)")  "Events: closing weight stream file '", &
             char (object%filename), "'"
        call msg_message ()
        close (object%unit)
        object%writing = .false.
     end if
   end subroutine eio_weights_final
 
 @ %def eio_weights_final
 @ Initialize event writing.
 <<EIO weights: eio weights: TBP>>=
   procedure :: init_out => eio_weights_init_out
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_weights_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_weights_init_out
 <<EIO weights: procedures>>=
-  subroutine eio_weights_init_out (eio, sample, data, success, extension)
+  module subroutine eio_weights_init_out &
+       (eio, sample, data, success, extension)
     class(eio_weights_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     if (present(extension)) then
        eio%extension = extension
     else
        eio%extension = "weights.dat"
     end if
     eio%filename = sample // "." // eio%extension
     eio%unit = free_unit ()
     write (msg_buffer, "(A,A,A)")  "Events: writing to weight stream file '", &
          char (eio%filename), "'"
     call msg_message ()
     eio%writing = .true.
     open (eio%unit, file = char (eio%filename), &
          action = "write", status = "replace")
     if (present (success))  success = .true.
   end subroutine eio_weights_init_out
 
 @ %def eio_weights_init_out
 @ Initialize event reading.
 <<EIO weights: eio weights: TBP>>=
   procedure :: init_in => eio_weights_init_in
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_init_in &
+         (eio, sample, data, success, extension)
+      class(eio_weights_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_weights_init_in
 <<EIO weights: procedures>>=
-  subroutine eio_weights_init_in (eio, sample, data, success, extension)
+  module subroutine eio_weights_init_in &
+       (eio, sample, data, success, extension)
     class(eio_weights_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     call msg_bug ("Weight stream: event input not supported")
     if (present (success))  success = .false.
   end subroutine eio_weights_init_in
 
 @ %def eio_weights_init_in
 @ Switch from input to output: reopen the file for reading.
 <<EIO weights: eio weights: TBP>>=
   procedure :: switch_inout => eio_weights_switch_inout
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_switch_inout (eio, success)
+      class(eio_weights_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_weights_switch_inout
 <<EIO weights: procedures>>=
-  subroutine eio_weights_switch_inout (eio, success)
+  module subroutine eio_weights_switch_inout (eio, success)
     class(eio_weights_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("Weight stream: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_weights_switch_inout
 
 @ %def eio_weights_switch_inout
 @ Output an event.  Write first the event indices, then weight and two
 values of the squared matrix element: [[sqme_ref]] is the value stored
 in the event record, and [[sqme_prc]] is the one stored in the process
 instance.  (They can differ: when recalculating, the former is read
 from file and the latter is the result of the new calculation.)
 
 For the alternative entries, the [[sqme]] value is always obtained by
 a new calculation, and thus qualifies as [[sqme_prc]].
 
 Don't write the file if the [[passed]] flag is set and false.
 <<EIO weights: eio weights: TBP>>=
   procedure :: output => eio_weights_output
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_weights_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_weights_output
 <<EIO weights: procedures>>=
-  subroutine eio_weights_output &
+  module subroutine eio_weights_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_weights_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     integer :: n_alt, i
     real(default) :: weight, sqme_ref, sqme_prc
     logical :: evt_pacify, evt_passed
     evt_pacify = eio%pacify;  if (present (pacify))  evt_pacify = pacify
     evt_passed = .true.;  if (present (passed))  evt_passed = passed
     if (eio%writing) then
        if (evt_passed) then
           weight = event%get_weight_prc ()
           sqme_ref = event%get_sqme_ref ()
           sqme_prc = event%get_sqme_prc ()
           n_alt = event%get_n_alt ()
 1         format (I0,3(1x,ES17.10),3(1x,I0))
 2         format (I0,3(1x,ES15.8),3(1x,I0))
           if (evt_pacify) then
              write (eio%unit, 2)  0, weight, sqme_prc, sqme_ref, &
                   i_prc
           else
              write (eio%unit, 1)  0, weight, sqme_prc, sqme_ref, &
                   i_prc
           end if
           do i = 1, n_alt
              weight = event%get_weight_alt(i)
              sqme_prc = event%get_sqme_alt(i)
              if (evt_pacify) then
                 write (eio%unit, 2)  i, weight, sqme_prc
              else
                 write (eio%unit, 1)  i, weight, sqme_prc
              end if
           end do
        end if
     else
        call eio%write ()
        call msg_fatal ("Weight stream file is not open for writing")
     end if
   end subroutine eio_weights_output
 
 @ %def eio_weights_output
 @ Input an event.
 <<EIO weights: eio weights: TBP>>=
   procedure :: input_i_prc => eio_weights_input_i_prc
   procedure :: input_event => eio_weights_input_event
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_input_i_prc (eio, i_prc, iostat)
+      class(eio_weights_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_weights_input_i_prc
+    module subroutine eio_weights_input_event &
+         (eio, event, iostat, event_handle)
+      class(eio_weights_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_weights_input_event
 <<EIO weights: procedures>>=
-  subroutine eio_weights_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_weights_input_i_prc (eio, i_prc, iostat)
     class(eio_weights_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     call msg_bug ("Weight stream: event input not supported")
     i_prc = 0
     iostat = 1
   end subroutine eio_weights_input_i_prc
 
-  subroutine eio_weights_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_weights_input_event &
+       (eio, event, iostat, event_handle)
     class(eio_weights_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     call msg_bug ("Weight stream: event input not supported")
     iostat = 1
   end subroutine eio_weights_input_event
 
 @ %def eio_weights_input_i_prc
 @ %def eio_weights_input_event
 @
 <<EIO weights: eio weights: TBP>>=
   procedure :: skip => eio_weights_skip
+<<EIO weights: sub interfaces>>=
+    module subroutine eio_weights_skip (eio, iostat)
+      class(eio_weights_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_weights_skip
 <<EIO weights: procedures>>=
-  subroutine eio_weights_skip (eio, iostat)
+  module subroutine eio_weights_skip (eio, iostat)
     class(eio_weights_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_weights_skip
 
 @ %def eio_weights_skip
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_weights_ut.f90]]>>=
 <<File header>>
 
 module eio_weights_ut
   use unit_tests
   use eio_weights_uti
 
 <<Standard module head>>
 
 <<EIO weights: public test>>
 
 contains
 
 <<EIO weights: test driver>>
 
 end module eio_weights_ut
 @ %def eio_weights_ut
 @
 <<[[eio_weights_uti.f90]]>>=
 <<File header>>
 
 module eio_weights_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use event_base
   use eio_data
   use eio_base
 
   use eio_weights
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
 
 <<Standard module head>>
 
 <<EIO weights: test declarations>>
 
 contains
 
 <<EIO weights: tests>>
 
 end module eio_weights_uti
 @ %def eio_weights_ut
 @ API: driver for the unit tests below.
 <<EIO weights: public test>>=
   public :: eio_weights_test
 <<EIO weights: test driver>>=
   subroutine eio_weights_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO weights: execute tests>>
   end subroutine eio_weights_test
 
 @ %def eio_weights_test
 @
 \subsubsection{Simple event}
 We test the implementation of all I/O methods.
 <<EIO weights: execute tests>>=
   call test (eio_weights_1, "eio_weights_1", &
        "read and write event contents", &
        u, results)
 <<EIO weights: test declarations>>=
   public :: eio_weights_1
 <<EIO weights: tests>>=
   subroutine eio_weights_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_weights_1"
     write (u, "(A)")  "*   Purpose: generate an event and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_weights_1"
 
     allocate (eio_weights_t :: eio)
 
     call eio%init_out (sample)
     call event%generate (1, [0._default, 0._default])
 
     call eio%output (event, i_prc = 42)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents: &
          &(weight, sqme(evt), sqme(prc), i_prc)"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "eio_weights_1.weights.dat", &
          action = "read", status = "old")
     read (u_file, "(A)")  buffer
     write (u, "(A)") trim (buffer)
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_weights_1"
   end subroutine eio_weights_1
 
 @ %def eio_weights_1
 @
 \subsubsection{Multiple weights}
 Event with several weight entries set.
 <<EIO weights: execute tests>>=
   call test (eio_weights_2, "eio_weights_2", &
        "multiple weights", &
        u, results)
 <<EIO weights: test declarations>>=
   public :: eio_weights_2
 <<EIO weights: tests>>=
   subroutine eio_weights_2 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, i
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_weights_2"
     write (u, "(A)")  "*   Purpose: generate an event and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false., n_alt = 2)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_weights_2"
 
     allocate (eio_weights_t :: eio)
 
     call eio%init_out (sample)
     select type (eio)
     type is (eio_weights_t)
        call eio%set_parameters (pacify = .true.)
     end select
     call event%generate (1, [0._default, 0._default])
     call event%set (sqme_alt = [2._default, 3._default])
     call event%set (weight_alt = &
          [2 * event%get_weight_prc (), 3 * event%get_weight_prc ()])
 
     call eio%output (event, i_prc = 42)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents: &
          &(weight, sqme(evt), sqme(prc), i_prc)"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "eio_weights_2.weights.dat", &
          action = "read", status = "old")
     do i = 1, 3
        read (u_file, "(A)")  buffer
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_weights_2"
 
   end subroutine eio_weights_2
 
 @ %def eio_weights_2
 @
 \subsubsection{Multiple events}
 Events with [[passed]] flag switched on/off.
 <<EIO weights: execute tests>>=
   call test (eio_weights_3, "eio_weights_3", &
        "check passed-flag", &
        u, results)
 <<EIO weights: test declarations>>=
   public :: eio_weights_3
 <<EIO weights: tests>>=
   subroutine eio_weights_3 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_weights_3"
     write (u, "(A)")  "*   Purpose: generate three events and write to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write events"
     write (u, "(A)")
 
     sample = "eio_weights_3"
 
     allocate (eio_weights_t :: eio)
     select type (eio)
     type is (eio_weights_t)
        call eio%set_parameters (pacify = .true.)
     end select
 
     call eio%init_out (sample)
 
     call event%generate (1, [0._default, 0._default])
     call eio%output (event, i_prc = 1)
 
     call event%generate (1, [0.1_default, 0._default])
     call eio%output (event, i_prc = 1, passed = .false.)
 
     call event%generate (1, [0.2_default, 0._default])
     call eio%output (event, i_prc = 1, passed = .true.)
 
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents: &
          &(weight, sqme(evt), sqme(prc), i_prc), should be just two entries"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "eio_weights_3.weights.dat", &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat=iostat)  buffer
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_weights_3"
   end subroutine eio_weights_3
 
 @ %def eio_weights_3
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Event Dump Output}
 This is an output-only format.  We simply dump the contents of the
 [[particle_set]], using the [[write]] method of that type.  The
 event-format options are the options of that procedure.
 <<[[eio_dump.f90]]>>=
 <<File header>>
 
 module eio_dump
 
   use, intrinsic :: iso_fortran_env, only: output_unit
 
   use kinds, only: i64
 <<Use strings>>
-  use format_utils, only: write_separator
-  use format_utils, only: pac_fmt
-  use format_defs, only: FMT_16, FMT_19
-  use io_units
-  use diagnostics
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
   use eio_base
 
 <<Standard module head>>
 
 <<EIO dump: public>>
 
 <<EIO dump: types>>
 
+  interface
+<<EIO dump: sub interfaces>>
+  end interface
+
+end module eio_dump
+@ %def eio_dump
+@
+<<[[eio_dump_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_dump) eio_dump_s
+
+  use io_units
+  use diagnostics
+  use format_utils, only: write_separator
+  use format_utils, only: pac_fmt
+  use format_defs, only: FMT_16, FMT_19
+
+  implicit none
+
 contains
 
 <<EIO dump: procedures>>
 
-end module eio_dump
-@ %def eio_dump
+end submodule eio_dump_s
+
+@ %def eio_dump_s
 @
 \subsection{Type}
 <<EIO dump: public>>=
   public :: eio_dump_t
 <<EIO dump: types>>=
   type, extends (eio_t) :: eio_dump_t
      integer(i64) :: count = 0
      integer :: unit = 0
      logical :: writing = .false.
      logical :: screen = .false.
      logical :: pacify = .false.
      logical :: weights = .false.
      logical :: compressed = .false.
      logical :: summary = .false.
    contains
    <<EIO dump: eio dump: TBP>>
   end type eio_dump_t
 
 @ %def eio_dump_t
 @
 \subsection{Specific Methods}
 Set control parameters.  We may provide a [[unit]] for input or output; this
 will be taken if the sample file name is empty.  In that case, the unit is
 assumed to be open and will be kept open; no messages will be issued.
 <<EIO dump: eio dump: TBP>>=
   procedure :: set_parameters => eio_dump_set_parameters
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_set_parameters (eio, extension, &
+         pacify, weights, compressed, summary, screen, unit)
+      class(eio_dump_t), intent(inout) :: eio
+      type(string_t), intent(in), optional :: extension
+      logical, intent(in), optional :: pacify
+      logical, intent(in), optional :: weights
+      logical, intent(in), optional :: compressed
+      logical, intent(in), optional :: summary
+      logical, intent(in), optional :: screen
+      integer, intent(in), optional :: unit
+    end subroutine eio_dump_set_parameters
 <<EIO dump: procedures>>=
-  subroutine eio_dump_set_parameters (eio, extension, &
+  module subroutine eio_dump_set_parameters (eio, extension, &
        pacify, weights, compressed, summary, screen, unit)
     class(eio_dump_t), intent(inout) :: eio
     type(string_t), intent(in), optional :: extension
     logical, intent(in), optional :: pacify
     logical, intent(in), optional :: weights
     logical, intent(in), optional :: compressed
     logical, intent(in), optional :: summary
     logical, intent(in), optional :: screen
     integer, intent(in), optional :: unit
     if (present (pacify))  eio%pacify = pacify
     if (present (weights))  eio%weights = weights
     if (present (compressed))  eio%compressed = compressed
     if (present (summary))  eio%summary = summary
     if (present (screen))  eio%screen = screen
     if (present (unit))  eio%unit = unit
     eio%extension = "pset.dat"
     if (present (extension))  eio%extension = extension
   end subroutine eio_dump_set_parameters
 
 @ %def eio_dump_set_parameters
 @
 \subsection{Common Methods}
 @ Output.  This is not the actual event format, but a readable account
 of the current object status.
 <<EIO dump: eio dump: TBP>>=
   procedure :: write => eio_dump_write
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_write (object, unit)
+      class(eio_dump_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_dump_write
 <<EIO dump: procedures>>=
-  subroutine eio_dump_write (object, unit)
+  module subroutine eio_dump_write (object, unit)
     class(eio_dump_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "Dump event stream:"
     if (object%writing) then
        write (u, "(3x,A,L1)") "Screen output     = ", object%screen
        write (u, "(3x,A,A,A)")  "Writing to file   = '", char (object%filename), "'"
        write (u, "(3x,A,L1)") "Reduced I/O prec. = ", object%pacify
        write (u, "(3x,A,L1)") "Show weights/sqme = ", object%weights
        write (u, "(3x,A,L1)") "Compressed        = ", object%compressed
        write (u, "(3x,A,L1)") "Summary           = ", object%summary
     else
        write (u, "(3x,A)")  "[closed]"
     end if
   end subroutine eio_dump_write
 
 @ %def eio_dump_write
 @ Finalizer: close any open file.
 <<EIO dump: eio dump: TBP>>=
   procedure :: final => eio_dump_final
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_final (object)
+      class(eio_dump_t), intent(inout) :: object
+    end subroutine eio_dump_final
 <<EIO dump: procedures>>=
-  subroutine eio_dump_final (object)
+  module subroutine eio_dump_final (object)
     class(eio_dump_t), intent(inout) :: object
     if (object%screen) then
        write (msg_buffer, "(A,A,A)")  "Events: display complete"
        call msg_message ()
        object%screen = .false.
     end if
     if (object%writing) then
        if (object%filename /= "") then
           write (msg_buffer, "(A,A,A)")  "Events: closing event dump file '", &
                char (object%filename), "'"
           call msg_message ()
           close (object%unit)
        end if
        object%writing = .false.
     end if
   end subroutine eio_dump_final
 
 @ %def eio_dump_final
 @ Initialize event writing.
 <<EIO dump: eio dump: TBP>>=
   procedure :: init_out => eio_dump_init_out
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_dump_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_dump_init_out
 <<EIO dump: procedures>>=
-  subroutine eio_dump_init_out (eio, sample, data, success, extension)
+  module subroutine eio_dump_init_out &
+       (eio, sample, data, success, extension)
     class(eio_dump_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     if (present(extension)) then
        eio%extension = extension
     else
        eio%extension = "pset.dat"
     end if
     if (sample == "" .and. eio%unit /= 0) then
        eio%filename = ""
        eio%writing = .true.
     else if (sample /= "") then
        eio%filename = sample // "." // eio%extension
        eio%unit = free_unit ()
        write (msg_buffer, "(A,A,A)")  "Events: writing to event dump file '", &
             char (eio%filename), "'"
        call msg_message ()
        eio%writing = .true.
        open (eio%unit, file = char (eio%filename), &
             action = "write", status = "replace")
     end if
     if (eio%screen) then
        write (msg_buffer, "(A,A,A)")  "Events: display on standard output"
        call msg_message ()
     end if
     eio%count = 0
     if (present (success))  success = .true.
   end subroutine eio_dump_init_out
 
 @ %def eio_dump_init_out
 @ Initialize event reading.
 <<EIO dump: eio dump: TBP>>=
   procedure :: init_in => eio_dump_init_in
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_init_in &
+         (eio, sample, data, success, extension)
+      class(eio_dump_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_dump_init_in
 <<EIO dump: procedures>>=
-  subroutine eio_dump_init_in (eio, sample, data, success, extension)
+  module subroutine eio_dump_init_in &
+       (eio, sample, data, success, extension)
     class(eio_dump_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     call msg_bug ("Event dump: event input not supported")
     if (present (success))  success = .false.
   end subroutine eio_dump_init_in
 
 @ %def eio_dump_init_in
 @ Switch from input to output: reopen the file for reading.
 <<EIO dump: eio dump: TBP>>=
   procedure :: switch_inout => eio_dump_switch_inout
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_switch_inout (eio, success)
+      class(eio_dump_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_dump_switch_inout
 <<EIO dump: procedures>>=
-  subroutine eio_dump_switch_inout (eio, success)
+  module subroutine eio_dump_switch_inout (eio, success)
     class(eio_dump_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("Event dump: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_dump_switch_inout
 
 @ %def eio_dump_switch_inout
 @ Output an event.  Delegate the output call to the [[write]] method
 of the current particle set, if valid.  Output both to file (if defined)
 and to screen (if requested).
 <<EIO dump: eio dump: TBP>>=
   procedure :: output => eio_dump_output
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_dump_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_dump_output
 <<EIO dump: procedures>>=
-  subroutine eio_dump_output &
+  module subroutine eio_dump_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_dump_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     character(len=7) :: fmt
     eio%count = eio%count + 1
     if (present (pacify)) then
        call pac_fmt (fmt, FMT_19, FMT_16, pacify)
     else
        call pac_fmt (fmt, FMT_19, FMT_16, eio%pacify)
     end if
     if (eio%writing)  call dump (eio%unit)
     if (eio%screen) then
        call dump (output_unit)
        if (logfile_unit () > 0)  call dump (logfile_unit ())
     end if
   contains
     subroutine dump (u)
       integer, intent(in) :: u
       integer :: i
       call write_separator (u, 2)
       write (u, "(1x,A,I0)", advance="no")  "Event"
       if (event%has_index ()) then
          write (u, "(1x,'#',I0)")  event%get_index ()
       else
          write (u, *)
       end if
       call write_separator (u, 2)
       write (u, "(1x,A,1x,I0)")  "count  =", eio%count
       if (present (passed)) then
          write (u, "(1x,A,1x,L1)")  "passed =", passed
       else
          write (u, "(1x,A)")  "passed = [N/A]"
       end if
       write (u, "(1x,A,1x,I0)")  "prc id =", i_prc
       if (eio%weights) then
          call write_separator (u)
          if (event%sqme_ref_known) then
             write (u, "(1x,A," // fmt // ")")  "sqme (ref)   = ", &
                  event%sqme_ref
          else
             write (u, "(1x,A)")  "sqme (ref)    = [undefined]"
          end if
          if (event%sqme_prc_known) then
             write (u, "(1x,A," // fmt // ")")  "sqme (prc)   = ", &
                  event%sqme_prc
          else
             write (u, "(1x,A)")  "sqme (prc)    = [undefined]"
          end if
          if (event%weight_ref_known) then
             write (u, "(1x,A," // fmt // ")")  "weight (ref) = ", &
                  event%weight_ref
          else
             write (u, "(1x,A)")  "weight (ref) = [undefined]"
          end if
          if (event%weight_prc_known) then
             write (u, "(1x,A," // fmt // ")")  "weight (prc) = ", &
                  event%weight_prc
          else
             write (u, "(1x,A)")  "weight (prc) = [undefined]"
          end if
          if (event%excess_prc_known) then
             write (u, "(1x,A," // fmt // ")")  "excess (prc) = ", &
                  event%excess_prc
          else
             write (u, "(1x,A)")  "excess (prc) = [undefined]"
          end if
          do i = 1, event%n_alt
             if (event%sqme_ref_known) then
                write (u, "(1x,A,I0,A," // fmt // ")")  "sqme (", i, ")     = ",&
                     event%sqme_prc
             else
                write (u, "(1x,A,I0,A)")  "sqme (", i, ")    = [undefined]"
             end if
             if (event%weight_prc_known) then
                write (u, "(1x,A,I0,A," // fmt // ")")  "weight (", i, ")   = ",&
                     event%weight_prc
             else
                write (u, "(1x,A,I0,A)")  "weight (", i, ")   = [undefined]"
             end if
          end do
       end if
       call write_separator (u)
       if (event%particle_set_is_valid) then
          call event%particle_set%write (unit = u, &
               summary = eio%summary, compressed = eio%compressed, &
               testflag = eio%pacify)
       else
          write (u, "(1x,A)")  "Particle set: [invalid]"
       end if
     end subroutine dump
   end subroutine eio_dump_output
 
 @ %def eio_dump_output
 @ Input an event.
 <<EIO dump: eio dump: TBP>>=
   procedure :: input_i_prc => eio_dump_input_i_prc
   procedure :: input_event => eio_dump_input_event
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_input_i_prc (eio, i_prc, iostat)
+      class(eio_dump_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_dump_input_i_prc
+    module subroutine eio_dump_input_event &
+         (eio, event, iostat, event_handle)
+      class(eio_dump_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_dump_input_event
 <<EIO dump: procedures>>=
-  subroutine eio_dump_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_dump_input_i_prc (eio, i_prc, iostat)
     class(eio_dump_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     call msg_bug ("Dump stream: event input not supported")
     i_prc = 0
     iostat = 1
   end subroutine eio_dump_input_i_prc
 
-  subroutine eio_dump_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_dump_input_event &
+       (eio, event, iostat, event_handle)
     class(eio_dump_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     call msg_bug ("Dump stream: event input not supported")
     iostat = 1
   end subroutine eio_dump_input_event
 
 @ %def eio_dump_input_i_prc
 @ %def eio_dump_input_event
 @
 <<EIO dump: eio dump: TBP>>=
   procedure :: skip => eio_dump_skip
+<<EIO dump: sub interfaces>>=
+    module subroutine eio_dump_skip (eio, iostat)
+      class(eio_dump_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_dump_skip
 <<EIO dump: procedures>>=
-  subroutine eio_dump_skip (eio, iostat)
+  module subroutine eio_dump_skip (eio, iostat)
     class(eio_dump_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_dump_skip
 
 @ %def eio_dump_skip
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_dump_ut.f90]]>>=
 <<File header>>
 
 module eio_dump_ut
   use unit_tests
   use eio_dump_uti
 
 <<Standard module head>>
 
 <<EIO dump: public test>>
 
 contains
 
 <<EIO dump: test driver>>
 
 end module eio_dump_ut
 @ %def eio_dump_ut
 @
 <<[[eio_dump_uti.f90]]>>=
 <<File header>>
 
 module eio_dump_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use event_base
   use eio_data
   use eio_base
 
   use eio_dump
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
 
 <<Standard module head>>
 
 <<EIO dump: test declarations>>
 
 contains
 
 <<EIO dump: tests>>
 
 end module eio_dump_uti
 @ %def eio_dump_ut
 @ API: driver for the unit tests below.
 <<EIO dump: public test>>=
   public :: eio_dump_test
 <<EIO dump: test driver>>=
   subroutine eio_dump_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO dump: execute tests>>
   end subroutine eio_dump_test
 
 @ %def eio_dump_test
 @
 \subsubsection{Test I/O methods}
 We test the implementation of all I/O methods.
 <<EIO dump: execute tests>>=
   call test (eio_dump_1, "eio_dump_1", &
        "write event contents", &
        u, results)
 <<EIO dump: test declarations>>=
   public :: eio_dump_1
 <<EIO dump: tests>>=
   subroutine eio_dump_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     class(eio_t), allocatable :: eio
     integer :: i_prc
     integer :: u_file
 
     write (u, "(A)")  "* Test output: eio_dump_1"
     write (u, "(A)")  "*   Purpose: generate events and write essentials to output"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write three events (two passed)"
     write (u, "(A)")
 
     allocate (eio_dump_t :: eio)
     select type (eio)
     type is (eio_dump_t)
        call eio%set_parameters (unit = u, weights = .true., pacify = .true.)
     end select
 
     i_prc = 42
 
     call eio%init_out (var_str (""))
 
     call event%generate (1, [0._default, 0._default])
     call eio%output (event, i_prc = i_prc)
 
     call event%generate (1, [0.1_default, 0._default])
     call event%set_index (99)
     call eio%output (event, i_prc = i_prc, passed = .false.)
 
     call event%generate (1, [0.2_default, 0._default])
     call event%increment_index ()
     call eio%output (event, i_prc = i_prc, passed = .true.)
 
     write (u, "(A)")
     write (u, "(A)")  "* Contents of eio_dump object"
     write (u, "(A)")
 
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     select type (eio)
     type is (eio_dump_t)
        eio%writing = .false.
     end select
     call eio%final ()
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_dump_1"
   end subroutine eio_dump_1
 
 @ %def eio_dump_1
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{ASCII File Formats}
 Here, we implement several ASCII file formats. It is possible to
 switch between them using flags.
 <<[[eio_ascii.f90]]>>=
 <<File header>>
 
 module eio_ascii
 
 <<Use strings>>
-  use io_units
-  use diagnostics
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
   use eio_base
-  use hep_common
-  use hep_events
 
 <<Standard module head>>
 
 <<EIO ascii: public>>
 
 <<EIO ascii: types>>
 
+  interface
+<<EIO ascii: sub interfaces>>
+  end interface
+
+end module eio_ascii
+@ %def eio_ascii
+@
+<<[[eio_ascii_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_ascii) eio_ascii_s
+
+  use io_units
+  use diagnostics
+  use hep_common
+  use hep_events
+
+  implicit none
+
 contains
 
 <<EIO ascii: procedures>>
 
-end module eio_ascii
-@ %def eio_ascii
+end submodule eio_ascii_s
+
+@ %def eio_ascii_s
 @
 \subsection{Type}
 <<EIO ascii: public>>=
   public :: eio_ascii_t
 <<EIO ascii: types>>=
   type, abstract, extends (eio_t) :: eio_ascii_t
      logical :: writing = .false.
      integer :: unit = 0
      logical :: keep_beams = .false.
      logical :: keep_remnants = .true.
      logical :: ensure_order = .false.
    contains
    <<EIO ascii: eio ascii: TBP>>
   end type eio_ascii_t
 
 @ %def eio_ascii_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_ascii_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_ascii_t
   end type eio_ascii_ascii_t
 
 @ %def eio_ascii_ascii_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_athena_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_athena_t
   end type eio_ascii_athena_t
 
 @ %def eio_ascii_athena_t
 @ The debug format has a few options that can be controlled by
 Sindarin variables.
 <<EIO ascii: public>>=
   public :: eio_ascii_debug_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_debug_t
      logical :: show_process = .true.
      logical :: show_transforms = .true.
      logical :: show_decay = .true.
      logical :: verbose = .true.
   end type eio_ascii_debug_t
 
 @ %def eio_ascii_debug_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_hepevt_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_hepevt_t
   end type eio_ascii_hepevt_t
 
 @ %def eio_ascii_hepevt_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_hepevt_verb_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_hepevt_verb_t
   end type eio_ascii_hepevt_verb_t
 
 @ %def eio_ascii_hepevt_verb_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_lha_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_lha_t
   end type eio_ascii_lha_t
 
 @ %def eio_ascii_lha_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_lha_verb_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_lha_verb_t
   end type eio_ascii_lha_verb_t
 
 @ %def eio_ascii_lha_verb_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_long_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_long_t
   end type eio_ascii_long_t
 
 @ %def eio_ascii_long_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_mokka_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_mokka_t
   end type eio_ascii_mokka_t
 
 @ %def eio_ascii_mokka_t
 @
 <<EIO ascii: public>>=
   public :: eio_ascii_short_t
 <<EIO ascii: types>>=
   type, extends (eio_ascii_t) :: eio_ascii_short_t
   end type eio_ascii_short_t
 
 @ %def eio_ascii_short_t
 @
 \subsection{Specific Methods}
 Set parameters that are specifically used with ASCII file formats.  In
 particular, this is the file extension.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: set_parameters => eio_ascii_set_parameters
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_set_parameters (eio, &
+         keep_beams, keep_remnants, ensure_order, extension, &
+         show_process, show_transforms, show_decay, verbose)
+      class(eio_ascii_t), intent(inout) :: eio
+      logical, intent(in), optional :: keep_beams
+      logical, intent(in), optional :: keep_remnants
+      logical, intent(in), optional :: ensure_order
+      type(string_t), intent(in), optional :: extension
+      logical, intent(in), optional :: show_process, show_transforms, show_decay
+      logical, intent(in), optional :: verbose
+    end subroutine eio_ascii_set_parameters
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_set_parameters (eio, &
+  module subroutine eio_ascii_set_parameters (eio, &
        keep_beams, keep_remnants, ensure_order, extension, &
        show_process, show_transforms, show_decay, verbose)
     class(eio_ascii_t), intent(inout) :: eio
     logical, intent(in), optional :: keep_beams
     logical, intent(in), optional :: keep_remnants
     logical, intent(in), optional :: ensure_order
     type(string_t), intent(in), optional :: extension
     logical, intent(in), optional :: show_process, show_transforms, show_decay
     logical, intent(in), optional :: verbose
     if (present (keep_beams))  eio%keep_beams = keep_beams
     if (present (keep_remnants))  eio%keep_remnants = keep_remnants
     if (present (ensure_order))  eio%ensure_order = ensure_order
     if (present (extension)) then
        eio%extension = extension
     else
        select type (eio)
        type is (eio_ascii_ascii_t)
           eio%extension = "evt"
        type is (eio_ascii_athena_t)
           eio%extension = "athena.evt"
        type is (eio_ascii_debug_t)
           eio%extension = "debug"
        type is (eio_ascii_hepevt_t)
           eio%extension = "hepevt"
        type is (eio_ascii_hepevt_verb_t)
           eio%extension = "hepevt.verb"
        type is (eio_ascii_lha_t)
           eio%extension = "lha"
        type is (eio_ascii_lha_verb_t)
           eio%extension = "lha.verb"
        type is (eio_ascii_long_t)
           eio%extension = "long.evt"
        type is (eio_ascii_mokka_t)
           eio%extension = "mokka.evt"
        type is (eio_ascii_short_t)
           eio%extension = "short.evt"
        end select
     end if
     select type (eio)
     type is (eio_ascii_debug_t)
        if (present (show_process))  eio%show_process = show_process
        if (present (show_transforms))  eio%show_transforms = show_transforms
        if (present (show_decay))  eio%show_decay = show_decay
        if (present (verbose))  eio%verbose = verbose
     end select
   end subroutine eio_ascii_set_parameters
 
 @ %def eio_ascii_set_parameters
 @
 \subsection{Common Methods}
 Output.  This is not the actual event format, but a readable account
 of the current object status.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: write => eio_ascii_write
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_write (object, unit)
+      class(eio_ascii_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_ascii_write
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_write (object, unit)
+  module subroutine eio_ascii_write (object, unit)
     class(eio_ascii_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u
     u = given_output_unit (unit)
     select type (object)
     type is (eio_ascii_ascii_t)
        write (u, "(1x,A)")  "ASCII event stream (default format):"
     type is (eio_ascii_athena_t)
        write (u, "(1x,A)")  "ASCII event stream (ATHENA format):"
     type is (eio_ascii_debug_t)
        write (u, "(1x,A)")  "ASCII event stream (Debugging format):"
     type is (eio_ascii_hepevt_t)
        write (u, "(1x,A)")  "ASCII event stream (HEPEVT format):"
     type is (eio_ascii_hepevt_verb_t)
        write (u, "(1x,A)")  "ASCII event stream (verbose HEPEVT format):"
     type is (eio_ascii_lha_t)
        write (u, "(1x,A)")  "ASCII event stream (LHA format):"
     type is (eio_ascii_lha_verb_t)
        write (u, "(1x,A)")  "ASCII event stream (verbose LHA format):"
     type is (eio_ascii_long_t)
        write (u, "(1x,A)")  "ASCII event stream (long format):"
     type is (eio_ascii_mokka_t)
        write (u, "(1x,A)")  "ASCII event stream (MOKKA format):"
     type is (eio_ascii_short_t)
        write (u, "(1x,A)")  "ASCII event stream (short format):"
     end select
     if (object%writing) then
        write (u, "(3x,A,A)")  "Writing to file   = ", char (object%filename)
     else
        write (u, "(3x,A)")  "[closed]"
     end if
     write (u, "(3x,A,L1)")    "Keep beams        = ", object%keep_beams
     write (u, "(3x,A,L1)")    "Keep remnants     = ", object%keep_remnants
     select type (object)
     type is (eio_ascii_debug_t)
        write (u, "(3x,A,L1)")    "Show process      = ", object%show_process
        write (u, "(3x,A,L1)")    "Show transforms   = ", object%show_transforms
        write (u, "(3x,A,L1)")    "Show decay tree   = ", object%show_decay
        write (u, "(3x,A,L1)")    "Verbose output    = ", object%verbose
     end select
   end subroutine eio_ascii_write
 
 @ %def eio_ascii_write
 @ Finalizer: close any open file.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: final => eio_ascii_final
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_final (object)
+      class(eio_ascii_t), intent(inout) :: object
+    end subroutine eio_ascii_final
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_final (object)
+  module subroutine eio_ascii_final (object)
     class(eio_ascii_t), intent(inout) :: object
     if (object%writing) then
        write (msg_buffer, "(A,A,A)")  "Events: closing ASCII file '", &
             char (object%filename), "'"
        call msg_message ()
        close (object%unit)
        object%writing = .false.
     end if
   end subroutine eio_ascii_final
 
 @ %def eio_ascii_final
 @ Initialize event writing.
 
 Check weight normalization.  This applies to all ASCII-type files that
 use the HEPRUP common block.  We can't allow normalization conventions
 that are not covered by the HEPRUP definition.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: init_out => eio_ascii_init_out
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_ascii_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_ascii_init_out
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_init_out (eio, sample, data, success, extension)
+  module subroutine eio_ascii_init_out &
+       (eio, sample, data, success, extension)
     class(eio_ascii_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     logical :: is_width
     integer :: i
     if (.not. present (data)) &
          call msg_bug ("ASCII initialization: missing data")
     is_width = data%n_beam == 1
     eio%sample = sample
     call eio%check_normalization (data)
     call eio%set_splitting (data)
     call eio%set_filename ()
     eio%unit = free_unit ()
     write (msg_buffer, "(A,A,A)")  "Events: writing to ASCII file '", &
          char (eio%filename), "'"
     call msg_message ()
     eio%writing = .true.
     open (eio%unit, file = char (eio%filename), &
          action = "write", status = "replace")
     select type (eio)
     type is (eio_ascii_lha_t)
        call heprup_init( &
             data%pdg_beam, &
             data%energy_beam, &
             n_processes = data%n_proc, &
             unweighted = data%unweighted, &
             negative_weights = data%negative_weights)
        do i = 1, data%n_proc
           call heprup_set_process_parameters (i = i, &
                process_id = data%proc_num_id(i), &
                cross_section = data%cross_section(i), &
                error = data%error(i), &
                is_width = is_width)
        end do
        call heprup_write_ascii (eio%unit)
     type is (eio_ascii_lha_verb_t)
        call heprup_init( &
             data%pdg_beam, &
             data%energy_beam, &
             n_processes = data%n_proc, &
             unweighted = data%unweighted, &
             negative_weights = data%negative_weights)
        do i = 1, data%n_proc
           call heprup_set_process_parameters (i = i, &
                process_id = data%proc_num_id(i), &
                cross_section = data%cross_section(i), &
                error = data%error(i), &
                is_width = is_width)
        end do
        call heprup_write_verbose (eio%unit)
     end select
     if (present (success))  success = .true.
   end subroutine eio_ascii_init_out
 
 @ %def eio_ascii_init_out
 @ Some event properties do not go well with some output formats.  In
 particular, many formats require unweighted events.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: check_normalization => eio_ascii_check_normalization
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_check_normalization (eio, data)
+      class(eio_ascii_t), intent(in) :: eio
+      type(event_sample_data_t), intent(in) :: data
+    end subroutine eio_ascii_check_normalization
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_check_normalization (eio, data)
+  module subroutine eio_ascii_check_normalization (eio, data)
     class(eio_ascii_t), intent(in) :: eio
     type(event_sample_data_t), intent(in) :: data
     if (data%unweighted) then
     else
        select type (eio)
        type is (eio_ascii_athena_t);  call msg_fatal &
             ("Event output (Athena format): events must be unweighted.")
        type is (eio_ascii_hepevt_t);  call msg_fatal &
             ("Event output (HEPEVT format): events must be unweighted.")
        type is (eio_ascii_hepevt_verb_t);  call msg_fatal &
             ("Event output (HEPEVT format): events must be unweighted.")
        end select
        select case (data%norm_mode)
        case (NORM_SIGMA)
        case default
           select type (eio)
           type is (eio_ascii_lha_t)
              call msg_fatal &
                   ("Event output (LHA): normalization for weighted events &
                   &must be 'sigma'")
           type is (eio_ascii_lha_verb_t)
              call msg_fatal &
                   ("Event output (LHA): normalization for weighted events &
                   &must be 'sigma'")
           end select
        end select
     end if
   end subroutine eio_ascii_check_normalization
 
 @ %def check_normalization
 @ Initialize event reading.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: init_in => eio_ascii_init_in
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_init_in &
+         (eio, sample, data, success, extension)
+      class(eio_ascii_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_ascii_init_in
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_init_in (eio, sample, data, success, extension)
+  module subroutine eio_ascii_init_in &
+       (eio, sample, data, success, extension)
     class(eio_ascii_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     call msg_bug ("ASCII: event input not supported")
     if (present (success))  success = .false.
   end subroutine eio_ascii_init_in
 
 @ %def eio_ascii_init_in
 @ Switch from input to output: reopen the file for reading.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: switch_inout => eio_ascii_switch_inout
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_switch_inout (eio, success)
+      class(eio_ascii_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_ascii_switch_inout
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_switch_inout (eio, success)
+  module subroutine eio_ascii_switch_inout (eio, success)
     class(eio_ascii_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("ASCII: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_ascii_switch_inout
 
 @ %def eio_ascii_switch_inout
 @ Split event file: increment the counter, close the current file, open a new
 one.  If the file needs a header, repeat it for the new file.  (We assume that
 the common block contents are still intact.)
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: split_out => eio_ascii_split_out
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_split_out (eio)
+      class(eio_ascii_t), intent(inout) :: eio
+    end subroutine eio_ascii_split_out
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_split_out (eio)
+  module subroutine eio_ascii_split_out (eio)
     class(eio_ascii_t), intent(inout) :: eio
     if (eio%split) then
        eio%split_index = eio%split_index + 1
        call eio%set_filename ()
        write (msg_buffer, "(A,A,A)")  "Events: writing to ASCII file '", &
             char (eio%filename), "'"
        call msg_message ()
        close (eio%unit)
        open (eio%unit, file = char (eio%filename), &
             action = "write", status = "replace")
        select type (eio)
        type is (eio_ascii_lha_t)
           call heprup_write_ascii (eio%unit)
        type is (eio_ascii_lha_verb_t)
           call heprup_write_verbose (eio%unit)
        end select
     end if
   end subroutine eio_ascii_split_out
 
 @ %def eio_ascii_split_out
 @ Output an event.  Write first the event indices, then weight and
 squared matrix element, then the particle set.
 
 Events that did not pass the selection are skipped.  The exceptions are
 the [[ascii]] and [[debug]] formats.  These are the formats that
 contain the [[passed]] flag in their output, and should be most useful
 for debugging purposes.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: output => eio_ascii_output
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_ascii_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_ascii_output
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_output &
+  module subroutine eio_ascii_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_ascii_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     if (present (passed)) then
        if (.not. passed) then
           select type (eio)
           type is (eio_ascii_debug_t)
           type is (eio_ascii_ascii_t)
           class default
              return
           end select
        end if
     end if
     if (eio%writing) then
        select type (eio)
        type is (eio_ascii_lha_t)
           call hepeup_from_event (event, &
                process_index = i_prc, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants)
           call hepeup_write_lha (eio%unit)
        type is (eio_ascii_lha_verb_t)
           call hepeup_from_event (event, &
                process_index = i_prc, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants)
           call hepeup_write_verbose (eio%unit)
        type is (eio_ascii_ascii_t)
           call event%write (eio%unit, &
                show_process = .false., &
                show_transforms = .false., &
                show_decay = .false., &
                verbose = .false., testflag = pacify)
        type is (eio_ascii_athena_t)
           call hepevt_from_event (event, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order)
           call hepevt_write_athena (eio%unit)
        type is (eio_ascii_debug_t)
           call event%write (eio%unit, &
                show_process = eio%show_process, &
                show_transforms = eio%show_transforms, &
                show_decay = eio%show_decay, &
                verbose = eio%verbose, &
                testflag = pacify)
        type is (eio_ascii_hepevt_t)
           call hepevt_from_event (event, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order)
           call hepevt_write_hepevt (eio%unit)
        type is (eio_ascii_hepevt_verb_t)
           call hepevt_from_event (event, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order)
           call hepevt_write_verbose (eio%unit)
        type is (eio_ascii_long_t)
           call hepevt_from_event (event, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order)
           call hepevt_write_ascii (eio%unit, .true.)
        type is (eio_ascii_mokka_t)
           call hepevt_from_event (event, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order)
           call hepevt_write_mokka (eio%unit)
        type is (eio_ascii_short_t)
           call hepevt_from_event (event, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order)
           call hepevt_write_ascii (eio%unit, .false.)
        end select
     else
        call eio%write ()
        call msg_fatal ("ASCII file is not open for writing")
     end if
   end subroutine eio_ascii_output
 
 @ %def eio_ascii_output
 @ Input an event.
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: input_i_prc => eio_ascii_input_i_prc
   procedure :: input_event => eio_ascii_input_event
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_input_i_prc (eio, i_prc, iostat)
+      class(eio_ascii_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_ascii_input_i_prc
+    module subroutine eio_ascii_input_event &
+         (eio, event, iostat, event_handle)
+      class(eio_ascii_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_ascii_input_event
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_ascii_input_i_prc (eio, i_prc, iostat)
     class(eio_ascii_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     call msg_bug ("ASCII: event input not supported")
     i_prc = 0
     iostat = 1
   end subroutine eio_ascii_input_i_prc
 
-  subroutine eio_ascii_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_ascii_input_event &
+       (eio, event, iostat, event_handle)
     class(eio_ascii_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     call msg_bug ("ASCII: event input not supported")
     iostat = 1
   end subroutine eio_ascii_input_event
 
 @ %def eio_ascii_input_i_prc
 @ %def eio_ascii_input_event
 @
 <<EIO ascii: eio ascii: TBP>>=
   procedure :: skip => eio_ascii_skip
+<<EIO ascii: sub interfaces>>=
+    module subroutine eio_ascii_skip (eio, iostat)
+       class(eio_ascii_t), intent(inout) :: eio
+       integer, intent(out) :: iostat
+    end subroutine eio_ascii_skip
 <<EIO ascii: procedures>>=
-  subroutine eio_ascii_skip (eio, iostat)
+  module subroutine eio_ascii_skip (eio, iostat)
      class(eio_ascii_t), intent(inout) :: eio
      integer, intent(out) :: iostat
      iostat = 0
   end subroutine eio_ascii_skip
 
 @ %def eio_asciii_skip
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_ascii_ut.f90]]>>=
 <<File header>>
 
 module eio_ascii_ut
   use unit_tests
   use eio_ascii_uti
 
 <<Standard module head>>
 
 <<EIO ascii: public test>>
 
 contains
 
 <<EIO ascii: test driver>>
 
 end module eio_ascii_ut
 @ %def eio_ascii_ut
 @
 <<[[eio_ascii_uti.f90]]>>=
 <<File header>>
 
 module eio_ascii_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use lorentz
   use model_data
   use event_base
   use particles
   use eio_data
   use eio_base
 
   use eio_ascii
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
 
 <<Standard module head>>
 
 <<EIO ascii: test declarations>>
 
 contains
 
 <<EIO ascii: tests>>
 
 end module eio_ascii_uti
 @ %def eio_ascii_uti
 @ API: driver for the unit tests below.
 <<EIO ascii: public test>>=
   public :: eio_ascii_test
 <<EIO ascii: test driver>>=
   subroutine eio_ascii_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO ascii: execute tests>>
   end subroutine eio_ascii_test
 
 @ %def eio_ascii_test
 @
 \subsubsection{Test I/O methods}
 We test the implementation of all I/O methods, method [[ascii]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_1, "eio_ascii_1", &
        "read and write event contents, format [ascii]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_1
 <<EIO ascii: tests>>=
   subroutine eio_ascii_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_1"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII ascii format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_1"
 
     allocate (eio_ascii_ascii_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (42)
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".evt"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_ascii_t :: eio)
 
     select type (eio)
     type is (eio_ascii_ascii_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_1"
 
   end subroutine eio_ascii_1
 
 @ %def eio_ascii_1
 @
 We test the implementation of all I/O methods, method [[athena]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_2, "eio_ascii_2", &
        "read and write event contents, format [athena]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_2
 <<EIO ascii: tests>>=
   subroutine eio_ascii_2 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_2"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII athena format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_2"
 
     allocate (eio_ascii_athena_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (42)
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char(sample // ".athena.evt"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_athena_t :: eio)
 
     select type (eio)
     type is (eio_ascii_athena_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_2"
 
   end subroutine eio_ascii_2
 
 @ %def eio_ascii_2
 @
 We test the implementation of all I/O methods, method [[debug]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_3, "eio_ascii_3", &
        "read and write event contents, format [debug]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_3
 <<EIO ascii: tests>>=
   subroutine eio_ascii_3 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_3"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII debug format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_3"
 
     allocate (eio_ascii_debug_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".debug"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_debug_t :: eio)
 
     select type (eio)
     type is (eio_ascii_debug_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_3"
 
   end subroutine eio_ascii_3
 
 @ %def eio_ascii_3
 @
 We test the implementation of all I/O methods, method [[hepevt]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_4, "eio_ascii_4", &
        "read and write event contents, format [hepevt]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_4
 <<EIO ascii: tests>>=
   subroutine eio_ascii_4 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_4"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII hepevt format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_4"
 
     allocate (eio_ascii_hepevt_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".hepevt"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_hepevt_t :: eio)
 
     select type (eio)
     type is (eio_ascii_hepevt_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_4"
 
   end subroutine eio_ascii_4
 
 @ %def eio_ascii_4
 @
 We test the implementation of all I/O methods, method [[lha]] (old LHA):
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_5, "eio_ascii_5", &
        "read and write event contents, format [lha]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_5
 <<EIO ascii: tests>>=
   subroutine eio_ascii_5 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_5"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII LHA format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_5"
 
     allocate (eio_ascii_lha_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".lha"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_lha_t :: eio)
 
     select type (eio)
     type is (eio_ascii_lha_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_5"
 
   end subroutine eio_ascii_5
 
 @ %def eio_ascii_5
 @
 We test the implementation of all I/O methods, method [[long]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_6, "eio_ascii_6", &
        "read and write event contents, format [long]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_6
 <<EIO ascii: tests>>=
   subroutine eio_ascii_6 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_6"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII long format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_6"
 
     allocate (eio_ascii_long_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".long.evt"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_long_t :: eio)
 
     select type (eio)
     type is (eio_ascii_long_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_6"
 
   end subroutine eio_ascii_6
 
 @ %def eio_ascii_6
 @
 We test the implementation of all I/O methods, method [[mokka]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_7, "eio_ascii_7", &
        "read and write event contents, format [mokka]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_7
 <<EIO ascii: tests>>=
   subroutine eio_ascii_7 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_7"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII mokka format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_7"
 
     allocate (eio_ascii_mokka_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".mokka.evt"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_mokka_t :: eio)
 
     select type (eio)
     type is (eio_ascii_mokka_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_7"
 
   end subroutine eio_ascii_7
 
 @ %def eio_ascii_7
 @
 We test the implementation of all I/O methods, method [[short]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_8, "eio_ascii_8", &
        "read and write event contents, format [short]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_8
 <<EIO ascii: tests>>=
   subroutine eio_ascii_8 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_8"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII short format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_8"
 
     allocate (eio_ascii_short_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".short.evt"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_short_t :: eio)
 
     select type (eio)
     type is (eio_ascii_short_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_8"
 
   end subroutine eio_ascii_8
 
 @ %def eio_ascii_8
 @
 We test the implementation of all I/O methods, method [[lha]]  (old
 LHA) in verbose version:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_9, "eio_ascii_9", &
        "read and write event contents, format [lha_verb]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_9
 <<EIO ascii: tests>>=
   subroutine eio_ascii_9 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_9"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII LHA verbose format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_9"
 
     allocate (eio_ascii_lha_verb_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".lha.verb"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_lha_verb_t :: eio)
 
     select type (eio)
     type is (eio_ascii_lha_verb_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_9"
 
   end subroutine eio_ascii_9
 
 @ %def eio_ascii_9
 @
 We test the implementation of all I/O methods, method [[hepevt_verb]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_10, "eio_ascii_10", &
        "read and write event contents, format [hepevt_verb]", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_10
 <<EIO ascii: tests>>=
   subroutine eio_ascii_10 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_ascii_10"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII hepevt verbose format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_10"
 
     allocate (eio_ascii_hepevt_verb_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".hepevt.verb"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_ascii_hepevt_verb_t :: eio)
 
     select type (eio)
     type is (eio_ascii_hepevt_verb_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_10"
 
   end subroutine eio_ascii_10
 
 @ %def eio_ascii_10
 @
 We test the implementation of all I/O methods, method [[mokka]]:
 <<EIO ascii: execute tests>>=
   call test (eio_ascii_11, "eio_ascii_11", &
        "read and write event contents, format [mokka], tiny value", &
        u, results)
 <<EIO ascii: test declarations>>=
   public :: eio_ascii_11
 <<EIO ascii: tests>>=
   subroutine eio_ascii_11 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(particle_set_t), pointer :: pset
     type(vector4_t) :: pnew
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(128) :: buffer
     real(default), parameter :: tval = 1.e-111_default
 
     write (u, "(A)")  "* Test output: eio_ascii_11"
     write (u, "(A)")  "*   Purpose: generate an event in ASCII mokka format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")  "*      with low-value cutoff"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_ascii_11"
 
     allocate (eio_ascii_mokka_t :: eio)
 
     select type (eio)
     class is (eio_ascii_t);  call eio%set_parameters ()
     end select
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%increment_index ()
     call event%evaluate_expressions ()
 
     ! Manipulate values in the event record
     pset => event%get_particle_set_ptr ()
     call pset%set_momentum (3, &
          vector4_moving (-tval, vector3_moving  ([-tval, -tval, -tval])), &
          -tval**2)
     call pset%set_momentum (4, &
          vector4_moving (tval, vector3_moving  ([tval, tval, tval])), &
          tval**2)
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".mokka.evt"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_ascii_11"
 
   end subroutine eio_ascii_11
 
 @ %def eio_ascii_11
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{HEP Common Blocks}
 
 Long ago, to transfer data between programs one had to set up a common
 block and link both programs as libraries to the main executable.  The
 HEP community standardizes several of those common blocks.
 
 The modern way of data exchange uses data files with standard
 formats.  However, the LHEF standard data format derives from a common
 block (actually, two).
 
 \whizard\ used to support those common blocks, and LHEF was
 implemented via writing/reading blocks.  We still keep this
 convention, but intend to eliminate common blocks (or any other static
 storage) from the workflow in the future.  This will gain flexibility
 towards concurrent running of program images.
 
 We encapsulate everything here in a module.  The module holds the
 variables which are part of the common block.  To access the common
 block variables, we just have to [[use]] this module.  (They are
 nevertheless in the common block, since external software may access
 it in this way.)
 
 Note: This code is taken essentially unchanged from \whizard\ 2.1 and
 does not (yet) provide unit tests.
 <<[[hep_common.f90]]>>=
 <<File header>>
 
 module hep_common
 
 <<Use kinds>>
   use kinds, only: double
   use constants
 <<Use strings>>
 <<Use debug>>
-  use io_units
-  use diagnostics
-  use numeric_utils
-  use format_utils, only: refmt_tiny
-  use physics_defs, only: HADRON_REMNANT
-  use physics_defs, only: HADRON_REMNANT_SINGLET
-  use physics_defs, only: HADRON_REMNANT_TRIPLET
-  use physics_defs, only: HADRON_REMNANT_OCTET
-  use physics_defs, only: pb_per_fb
-  use xml
   use lorentz
-  use flavors
-  use colors
   use polarizations
   use model_data
   use particles
-  use subevents, only: PRT_BEAM, PRT_INCOMING, PRT_OUTGOING
-  use subevents, only: PRT_UNDEFINED
-  use subevents, only: PRT_VIRTUAL, PRT_RESONANT, PRT_BEAM_REMNANT
 
 <<Standard module head>>
 
 <<HEP common: public>>
 
 <<HEP common: interfaces>>
 
 <<HEP common: parameters>>
 
 <<HEP common: variables>>
 
 <<HEP common: common blocks>>
 
+  interface
+<<HEP common: sub interfaces>>
+  end interface
+
+end module hep_common
+@ %def hep_common
+@
+<<[[hep_common_sub.f90]]>>=
+<<File header>>
+
+submodule (hep_common) hep_common_s
+
+  use io_units
+  use diagnostics
+  use numeric_utils
+  use format_utils, only: refmt_tiny
+  use physics_defs, only: pb_per_fb
+  use physics_defs, only: HADRON_REMNANT
+  use physics_defs, only: HADRON_REMNANT_SINGLET
+  use physics_defs, only: HADRON_REMNANT_TRIPLET
+  use physics_defs, only: HADRON_REMNANT_OCTET
+  use xml
+  use flavors
+  use colors
+  use subevents, only: PRT_BEAM, PRT_INCOMING, PRT_OUTGOING
+  use subevents, only: PRT_UNDEFINED
+  use subevents, only: PRT_VIRTUAL, PRT_RESONANT, PRT_BEAM_REMNANT
+
+  implicit none
+
 contains
 
 <<HEP common: procedures>>
 
-end module hep_common
-@ %def hep_common
+end submodule hep_common_s
+
+@ %def hep_common_s
 @
 \subsection{Event characteristics}
 The maximal number of particles in an event record.
 <<HEP common: parameters>>=
   integer, parameter, public :: MAXNUP = 500
 @ %def MAXNUP
 @ The number of particles in this event.
 <<HEP common: variables>>=
   integer, public :: NUP
 @ %def NUP
 @ The process ID for this event.
 <<HEP common: variables>>=
   integer, public :: IDPRUP
 @ %def IDPRUP
 @ The weight of this event ($\pm 1$ for unweighted events).
 <<HEP common: variables>>=
   double precision, public :: XWGTUP
 @ %def XWGTUP
 @ The factorization scale that is used for PDF calculation ($-1$ if
 undefined).
 <<HEP common: variables>>=
   double precision, public :: SCALUP
 @ %def SCALUP
 @ The QED and QCD couplings $\alpha$ used for this event ($-1$ if
 undefined).
 <<HEP common: variables>>=
   double precision, public :: AQEDUP
   double precision, public :: AQCDUP
 @ %def AQEDUP AQCDUP
 @
 
 \subsection{Particle characteristics}
 The PDG code:
 <<HEP common: variables>>=
   integer, dimension(MAXNUP), public :: IDUP
 @ %def IDUP
 @ The status code.  Incoming: $-1$, outgoing: $+1$.  Intermediate
 t-channel propagator: $-2$ (currently not used by WHIZARD).
 Intermediate resonance whose mass should be preserved: $2$.
 Intermediate resonance for documentation: $3$ (currently not used).
 Beam particles: $-9$.
 <<HEP common: variables>>=
   integer, dimension(MAXNUP), public :: ISTUP
 @ %def ISTUP
 @ Index of first and last mother.
 <<HEP common: variables>>=
   integer, dimension(2,MAXNUP), public :: MOTHUP
 @ %def MOTHUP
 @ Color line index of the color and anticolor entry for the particle.
 The standard recommends using large numbers; we start from MAXNUP+1.
 <<HEP common: variables>>=
   integer, dimension(2,MAXNUP), public :: ICOLUP
 @ %def ICOLUP
 @ Momentum, energy, and invariant mass: $(p_x,p_y,p_z,E,M)$.  For
 space-like particles, $M$ is the negative square root of the absolute
 value of the invariant mass.
 <<HEP common: variables>>=
   double precision, dimension(5,MAXNUP), public :: PUP
 @ %def PUP
 @ Invariant lifetime (distance) from production to decay in mm.
 <<HEP common: variables>>=
   double precision, dimension(MAXNUP), public :: VTIMUP
 @ %def VTIMUP
 @ Cosine of the angle between the spin-vector and a particle and the
 3-momentum of its mother, given in the lab frame.  If
 undefined/unpolarized: $9$.
 <<HEP common: variables>>=
   double precision, dimension(MAXNUP), public :: SPINUP
 @ %def SPINUP
 @
 \subsection{The HEPRUP common block}
 This common block is filled once per run.
 
 \subsubsection{Run characteristics}
 The maximal number of different processes.
 <<HEP common: parameters>>=
   integer, parameter, public :: MAXPUP = 100
 @ %def MAXPUP
 @ The beam PDG codes.
 <<HEP common: variables>>=
   integer, dimension(2), public :: IDBMUP
 @ %def IDBMUP
 @ The beam energies in GeV.
 <<HEP common: variables>>=
   double precision, dimension(2), public :: EBMUP
 @ %def EBMUP
 @ The PDF group and set for the two beams.  (Undefined: use $-1$;
 LHAPDF: use group = $0$).
 <<HEP common: variables>>=
   integer, dimension(2), public :: PDFGUP
   integer, dimension(2), public :: PDFSUP
 @ %def PDFGUP PDFSUP
 @ The (re)weighting model.  1: events are weighted, the shower
 generator (SHG) selects processes according to the maximum weight (in
 pb) and unweights events.  2: events are weighted, the SHG selects
 processes according to their cross section (in pb) and unweights
 events.  3: events are unweighted and simply run through the SHG.  4:
 events are weighted, and the SHG keeps the weight.  Negative numbers:
 negative weights are allowed (and are reweighted to $\pm 1$ by the
 SHG, if allowed).
 
 \whizard\ only supports modes 3 and 4, as the SHG is not given control
 over process selection.  This is consistent with writing events to
 file, for offline showering.
 <<HEP common: variables>>=
   integer, public :: IDWTUP
 @ %def IDWTUP
 @ The number of different processes.
 <<HEP common: variables>>=
   integer, public :: NPRUP
 @ %def NPRUP
 @
 \subsubsection{Process characteristics}
 Cross section and error in pb.  (Cross section is needed only for
 $[[IDWTUP]] = 2$, so here both values are given for informational
 purposes only.)
 <<HEP common: variables>>=
   double precision, dimension(MAXPUP), public :: XSECUP
   double precision, dimension(MAXPUP), public :: XERRUP
 @ %def XSECUP XERRUP
 @ Maximum weight, i.e., the maximum value that [[XWGTUP]] can take.
 Also unused for the supported weighting models. It is $\pm 1$ for
 unweighted events.
 <<HEP common: variables>>=
   double precision, dimension(MAXPUP), public :: XMAXUP
 @ %def XMAXUP
 @ Internal ID of the selected process, matches [[IDPRUP]] below.
 <<HEP common: variables>>=
   integer, dimension(MAXPUP), public :: LPRUP
 @ %def LPRUP
 @
 \subsubsection{The common block}
 <<HEP common: common blocks>>=
   common /HEPRUP/ &
        IDBMUP, EBMUP, PDFGUP, PDFSUP, IDWTUP, NPRUP, &
        XSECUP, XERRUP, XMAXUP, LPRUP
   save /HEPRUP/
 
 @ %def HEPRUP
 @ Fill the run characteristics of the common block.  The
 initialization sets the beam properties, number of processes, and
 weighting model.
 <<HEP common: public>>=
   public :: heprup_init
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_init &
+         (beam_pdg, beam_energy, n_processes, unweighted, negative_weights)
+      integer, dimension(2), intent(in) :: beam_pdg
+      real(default), dimension(2), intent(in) :: beam_energy
+      integer, intent(in) :: n_processes
+      logical, intent(in) :: unweighted
+      logical, intent(in) :: negative_weights
+    end subroutine heprup_init
 <<HEP common: procedures>>=
-  subroutine heprup_init &
+  module subroutine heprup_init &
        (beam_pdg, beam_energy, n_processes, unweighted, negative_weights)
     integer, dimension(2), intent(in) :: beam_pdg
     real(default), dimension(2), intent(in) :: beam_energy
     integer, intent(in) :: n_processes
     logical, intent(in) :: unweighted
     logical, intent(in) :: negative_weights
     IDBMUP = beam_pdg
     EBMUP = beam_energy
     PDFGUP = -1
     PDFSUP = -1
     if (unweighted) then
        IDWTUP = 3
     else
        IDWTUP = 4
     end if
     if (negative_weights)  IDWTUP = - IDWTUP
     NPRUP = n_processes
   end subroutine heprup_init
 
 @ %def heprup_init
 The HEPRUP (event) common block is needed for the interface to the shower.
 Filling of it is triggered by some output file formats.  If these are not
 present, the common block is filled with some dummy information. Be generous
 with the number of processes in HEPRUP so that PYTHIA only rarely needs to be
 reinitialized in case events with higher process ids are generated.
 <<HEP common: public>>=
   public :: assure_heprup
+<<HEP common: sub interfaces>>=
+    module subroutine assure_heprup (pset)
+      type(particle_set_t), intent(in) :: pset
+    end subroutine assure_heprup
 <<HEP common: procedures>>=
-  subroutine assure_heprup (pset)
+  module subroutine assure_heprup (pset)
     type(particle_set_t), intent(in) :: pset
     integer :: i, num_id
     integer, parameter :: min_processes = 10
     num_id = 1
     if (LPRUP (num_id) /= 0)  return
     call heprup_init ( &
          [pset%prt(1)%get_pdg (), pset%prt(2)%get_pdg ()] , &
          [pset%prt(1)%p%p(0), pset%prt(2)%p%p(0)], &
          num_id, .false., .false.)
     do i = 1, (num_id / min_processes + 1) * min_processes
        call heprup_set_process_parameters (i = i, process_id = &
             i, cross_section = 1._default, error = 1._default)
     end do
   end subroutine assure_heprup
 
 @ %def assure_heprup
 @ Read in the LHE file opened in unit [[u]] and add the final
 particles to the [[particle_set]], the outgoing particles of the existing
 [[particle_set]] are compared to the particles that are read in. When
 they are equal in flavor and momenta, they are erased and their
 mother-daughter relations are transferred to the existing particles.
 <<HEP common: public>>=
   public :: combine_lhef_with_particle_set
+<<HEP common: sub interfaces>>=
+    module subroutine combine_lhef_with_particle_set &
+         (particle_set, u, model_in, model_hadrons)
+      type(particle_set_t), intent(inout) :: particle_set
+      integer, intent(in) :: u
+      class(model_data_t), intent(in), target :: model_in
+      class(model_data_t), intent(in), target :: model_hadrons
+    end subroutine combine_lhef_with_particle_set
 <<HEP common: procedures>>=
-  subroutine combine_lhef_with_particle_set &
+  module subroutine combine_lhef_with_particle_set &
        (particle_set, u, model_in, model_hadrons)
     type(particle_set_t), intent(inout) :: particle_set
     integer, intent(in) :: u
     class(model_data_t), intent(in), target :: model_in
     class(model_data_t), intent(in), target :: model_hadrons
     type(flavor_t) :: flv
     type(color_t) :: col
     class(model_data_t), pointer :: model
     type(particle_t), dimension(:), allocatable :: prt_tmp, prt
     integer :: i, j
     type(vector4_t) :: mom, d_mom
     integer, PARAMETER :: MAXLEN=200
     character(len=maxlen) :: string
     integer :: ibeg, n_tot, n_entries
     integer, dimension(:), allocatable :: relations, mothers, tbd
     INTEGER :: NUP,IDPRUP,IDUP,ISTUP
     real(kind=double) :: XWGTUP,SCALUP,AQEDUP,AQCDUP,VTIMUP,SPINUP
     integer :: MOTHUP(1:2), ICOLUP(1:2)
     real(kind=double) :: PUP(1:5)
     real(kind=default) :: pup_dum(1:5)
     character(len=5) :: buffer
     character(len=6) :: strfmt
     logical :: not_found
     logical :: debug_lhef = .false.
     STRFMT='(A000)'
     WRITE (STRFMT(3:5),'(I3)') MAXLEN
 
     if (debug_lhef)  call particle_set%write ()
 
     rewind (u)
 
     do
        read (u,*, END=501, ERR=502) STRING
        IBEG = 0
        do
           if (signal_is_pending ()) return
           IBEG = IBEG + 1
           ! Allow indentation.
           IF (STRING (IBEG:IBEG) .EQ. ' ' .and. IBEG < MAXLEN-6) cycle
           exit
        end do
        IF (string(IBEG:IBEG+6) /= '<event>' .and. &
             string(IBEG:IBEG+6) /= '<event ') cycle
        exit
     end do
     !!! Read first line of event info -> number of entries
     read (u, *, END=503, ERR=504) NUP, IDPRUP, XWGTUP, SCALUP, AQEDUP, AQCDUP
     n_tot = particle_set%get_n_tot ()
     allocate (prt_tmp (1:n_tot+NUP))
     allocate (relations (1:NUP), mothers (1:NUP), tbd(1:NUP))
     do i = 1, n_tot
        if (signal_is_pending ()) return
        prt_tmp (i) = particle_set%get_particle (i)
     end do
     !!! transfer particles from lhef to particle_set
     !!!...Read NUP subsequent lines with information on each particle.
     n_entries = 1
     mothers = 0
     relations = 0
     PARTICLE_LOOP: do I = 1, NUP
        read (u,*, END=200, ERR=505) IDUP, ISTUP, MOTHUP(1), MOTHUP(2), &
             ICOLUP(1), ICOLUP(2), (PUP (J),J=1,5), VTIMUP, SPINUP
        if (model_in%test_field (IDUP)) then
           model => model_in
        else if (model_hadrons%test_field (IDUP)) then
           model => model_hadrons
        else
           write (buffer, "(I5)") IDUP
           call msg_error ("Parton " // buffer // &
                " found neither in given model file nor in SM_hadrons")
           return
        end if
        if (debug_lhef) then
           print *, "IDUP, ISTUP, MOTHUP, PUP = ", IDUP, ISTUP, MOTHUP(1), &
 	     MOTHUP(2), PUP
        end if
        call flv%init (IDUP, model)
        if (IABS(IDUP) == 2212 .or. IABS(IDUP) == 2112) then
           ! PYTHIA sometimes sets color indices for protons and neutrons (?)
           ICOLUP (1) = 0
           ICOLUP (2) = 0
        end if
        call col%init_col_acl (ICOLUP (1), ICOLUP (2))
        !!! Settings for unpolarized particles
        ! particle_set%prt (oldsize+i)%hel = ??
        ! particle_set%prt (oldsize+i)%pol = ??
        if (MOTHUP(1) /= 0) then
           mothers(i) = MOTHUP(1)
        end if
        pup_dum = PUP
        if (pup_dum(4) < 1E-10_default)  cycle
        mom = vector4_moving (pup_dum (4), &
             vector3_moving ([pup_dum (1), pup_dum (2), pup_dum (3)]))
        not_found = .true.
        SCAN_PARTICLES: do j = 1, n_tot
           d_mom = prt_tmp(j)%get_momentum ()
           if (all (nearly_equal &
                (mom%p, d_mom%p, abs_smallness = 1.E-4_default)) .and. &
                 (prt_tmp(j)%get_pdg () == IDUP)) then
              if (.not. prt_tmp(j)%get_status () == PRT_BEAM .or. &
                   .not. prt_tmp(j)%get_status () == PRT_BEAM_REMNANT) &
                   relations(i) = j
                   not_found = .false.
           end if
        end do SCAN_PARTICLES
        if (not_found) then
           if (debug_lhef) &
              print *, "Not found: adding particle"
           call prt_tmp(n_tot+n_entries)%set_flavor (flv)
           call prt_tmp(n_tot+n_entries)%set_color (col)
           call prt_tmp(n_tot+n_entries)%set_momentum (mom)
           if (MOTHUP(1) /= 0) then
              if (relations(MOTHUP(1)) /= 0) then
                 call prt_tmp(n_tot+n_entries)%set_parents &
                      ([relations(MOTHUP(1))])
                 call prt_tmp(relations(MOTHUP(1)))%add_child (n_tot+n_entries)
                 if (prt_tmp(relations(MOTHUP(1)))%get_status () &
                      == PRT_OUTGOING) &
                      call prt_tmp(relations(MOTHUP(1)))%reset_status &
                      (PRT_VIRTUAL)
              end if
           end if
           call prt_tmp(n_tot+n_entries)%set_status (PRT_OUTGOING)
           if (debug_lhef) call prt_tmp(n_tot+n_entries)%write ()
           n_entries = n_entries + 1
        end if
     end do PARTICLE_LOOP
     do i = 1, n_tot
        if (prt_tmp(i)%get_status () == PRT_OUTGOING .and. &
            prt_tmp(i)%get_n_children () /= 0) then
                 call prt_tmp(i)%reset_status (PRT_VIRTUAL)
        end if
     end do
 
     allocate (prt (1:n_tot+n_entries-1))
     prt = prt_tmp (1:n_tot+n_entries-1)
     ! transfer to particle_set
     call particle_set%replace (prt)
     deallocate (prt, prt_tmp)
 
     if (debug_lhef) then
        call particle_set%write ()
        print *, "combine_lhef_with_particle_set"
        ! stop
     end if
 
 200 continue
     return
 
 501 write(*,*) "READING LHEF failed 501"
     return
 502 write(*,*) "READING LHEF failed 502"
     return
 503 write(*,*) "READING LHEF failed 503"
     return
 504 write(*,*) "READING LHEF failed 504"
     return
 505 write(*,*) "READING LHEF failed 505"
     return
   end subroutine combine_lhef_with_particle_set
 
 @ %def combine_lhef_with_particle_set
 @
 <<HEP common: public>>=
   public :: w2p_write_lhef_event
+<<HEP common: sub interfaces>>=
+    module subroutine w2p_write_lhef_event (unit)
+      integer, intent(in) :: unit
+    end subroutine w2p_write_lhef_event
 <<HEP common: procedures>>=
-  subroutine w2p_write_lhef_event (unit)
+  module subroutine w2p_write_lhef_event (unit)
     integer, intent(in) :: unit
     type(xml_tag_t), allocatable :: tag_lhef, tag_head, tag_init, &
          tag_event, tag_gen_n, tag_gen_v
     if (debug_on) call msg_debug (D_EVENTS, "w2p_write_lhef_event")
     allocate (tag_lhef, tag_head, tag_init, tag_event, &
          tag_gen_n, tag_gen_v)
     call tag_lhef%init (var_str ("LesHouchesEvents"), &
          [xml_attribute (var_str ("version"), var_str ("1.0"))], .true.)
     call tag_head%init (var_str ("header"), .true.)
     call tag_init%init (var_str ("init"), .true.)
     call tag_event%init (var_str ("event"), .true.)
     call tag_gen_n%init (var_str ("generator_name"), .true.)
     call tag_gen_v%init (var_str ("generator_version"), .true.)
     call tag_lhef%write (unit); write (unit, *)
     call tag_head%write (unit); write (unit, *)
     write (unit, "(2x)", advance = "no")
     call tag_gen_n%write (var_str ("WHIZARD"), unit)
     write (unit, *)
     write (unit, "(2x)", advance = "no")
     call tag_gen_v%write (var_str ("<<Version>>"), unit)
     write (unit, *)
     call tag_head%close (unit); write (unit, *)
     call tag_init%write (unit); write (unit, *)
     call heprup_write_lhef (unit)
     call tag_init%close (unit); write (unit, *)
     call tag_event%write (unit); write (unit, *)
     call hepeup_write_lhef (unit)
     call tag_event%close (unit); write (unit, *)
     call tag_lhef%close (unit); write (unit, *)
     deallocate (tag_lhef, tag_head, tag_init, tag_event, &
          tag_gen_n, tag_gen_v)
   end subroutine w2p_write_lhef_event
 
 @ %def w2p_write_lhef_event
 @ Extract parameters from the common block.  We leave it to the caller
 to specify which parameters it actually needs.
 
 [[PDFGUP]] and [[PDFSUP]] are not extracted.  [[IDWTUP=1,2]] are not
 supported by \whizard, but correspond to weighted events.
 <<HEP common: public>>=
   public :: heprup_get_run_parameters
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_get_run_parameters &
+         (beam_pdg, beam_energy, n_processes, unweighted, negative_weights)
+      integer, dimension(2), intent(out), optional :: beam_pdg
+      real(default), dimension(2), intent(out), optional :: beam_energy
+      integer, intent(out), optional :: n_processes
+      logical, intent(out), optional :: unweighted
+      logical, intent(out), optional :: negative_weights
+    end subroutine heprup_get_run_parameters
 <<HEP common: procedures>>=
-  subroutine heprup_get_run_parameters &
+  module subroutine heprup_get_run_parameters &
        (beam_pdg, beam_energy, n_processes, unweighted, negative_weights)
     integer, dimension(2), intent(out), optional :: beam_pdg
     real(default), dimension(2), intent(out), optional :: beam_energy
     integer, intent(out), optional :: n_processes
     logical, intent(out), optional :: unweighted
     logical, intent(out), optional :: negative_weights
     if (present (beam_pdg))  beam_pdg = IDBMUP
     if (present (beam_energy))  beam_energy = EBMUP
     if (present (n_processes))  n_processes = NPRUP
     if (present (unweighted)) then
        select case (abs (IDWTUP))
        case (3)
           unweighted = .true.
        case (4)
           unweighted = .false.
        case (1,2)  !!! not supported by WHIZARD
           unweighted = .false.
        case default
           call msg_fatal ("HEPRUP: unsupported IDWTUP value")
        end select
     end if
     if (present (negative_weights)) then
        negative_weights = IDWTUP < 0
     end if
   end subroutine heprup_get_run_parameters
 
 @ %def heprup_get_run_parameters
 @ Specify PDF set info.  Since we support only LHAPDF, the group entry
 is zero.
 <<HEP common: public>>=
   public :: heprup_set_lhapdf_id
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_set_lhapdf_id (i_beam, pdf_id)
+      integer, intent(in) :: i_beam, pdf_id
+    end subroutine heprup_set_lhapdf_id
 <<HEP common: procedures>>=
-  subroutine heprup_set_lhapdf_id (i_beam, pdf_id)
+  module subroutine heprup_set_lhapdf_id (i_beam, pdf_id)
     integer, intent(in) :: i_beam, pdf_id
     PDFGUP(i_beam) = 0
     PDFSUP(i_beam) = pdf_id
   end subroutine heprup_set_lhapdf_id
 
 @ %def heprup_set_lhapdf_id
 @ Fill the characteristics for a particular process.  Only the process
 ID is mandatory.  Note that \whizard\ computes cross sections in fb,
 so we have to rescale to pb.  The maximum weight is meaningless for
 unweighted events.
 <<HEP common: public>>=
   public :: heprup_set_process_parameters
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_set_process_parameters &
+         (i, process_id, cross_section, error, max_weight, is_width)
+      integer, intent(in) :: i, process_id
+      real(default), intent(in), optional :: cross_section, error, max_weight
+      logical, intent(in), optional :: is_width
+    end subroutine heprup_set_process_parameters
 <<HEP common: procedures>>=
-  subroutine heprup_set_process_parameters &
+  module subroutine heprup_set_process_parameters &
        (i, process_id, cross_section, error, max_weight, is_width)
     integer, intent(in) :: i, process_id
     real(default), intent(in), optional :: cross_section, error, max_weight
     logical, intent(in), optional :: is_width
     logical :: is_w
     is_w = .false.
     if (present (is_width))  is_w = is_width
     LPRUP(i) = process_id
     if (present (cross_section)) then
        if (is_w) then
           XSECUP(i) = cross_section
        else
           XSECUP(i) = cross_section * pb_per_fb
        end if
     else
        XSECUP(i) = 0
     end if
     if (present (error)) then
        if (is_w) then
           XERRUP(i) = error
        else
           XERRUP(i) = error * pb_per_fb
        end if
     else
        XERRUP(i) = 0
     end if
     select case (IDWTUP)
     case (3);  XMAXUP(i) = 1
     case (4)
        if (present (max_weight)) then
           if (is_w) then
              XMAXUP(i) = max_weight
           else
              XMAXUP(i) = max_weight * pb_per_fb
           end if
        else
           XMAXUP(i) = 0
        end if
     end select
   end subroutine heprup_set_process_parameters
 
 @ %def heprup_set_process_parameters
 @ Extract the process parameters, as far as needed.
 <<HEP common: public>>=
   public :: heprup_get_process_parameters
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_get_process_parameters  &
+         (i, process_id, cross_section, error, max_weight, is_width)
+      integer, intent(in) :: i
+      integer, intent(out), optional :: process_id
+      real(default), intent(out), optional :: cross_section, error, max_weight
+      logical, intent(in), optional :: is_width
+    end subroutine heprup_get_process_parameters
 <<HEP common: procedures>>=
-  subroutine heprup_get_process_parameters  &
+  module subroutine heprup_get_process_parameters  &
        (i, process_id, cross_section, error, max_weight, is_width)
     integer, intent(in) :: i
     integer, intent(out), optional :: process_id
     real(default), intent(out), optional :: cross_section, error, max_weight
     logical, intent(in), optional :: is_width
     logical :: is_w
     is_w = .false.
     if (present (is_width))  is_w = is_width
     if (present (process_id))  process_id = LPRUP(i)
     if (present (cross_section)) then
        if (is_w) then
           cross_section = XSECUP(i)
        else
           cross_section = XSECUP(i) / pb_per_fb
        end if
     end if
     if (present (error)) then
        if (is_w) then
           error = XERRUP(i)
        else
           error = XERRUP(i) / pb_per_fb
        end if
     end if
     if (present (max_weight)) then
        select case (IDWTUP)
        case (3)
           max_weight = 1
        case (4)
           max_weight = XMAXUP(i) / pb_per_fb
        case (1,2)   !!! not supported by WHIZARD
           max_weight = 0
        case default
           call msg_fatal ("HEPRUP: unsupported IDWTUP value")
        end select
     end if
   end subroutine heprup_get_process_parameters
 
 @ %def heprup_get_process_parameters
 @
 \subsection{Run parameter output (verbose)}
 This is a verbose output of the HEPRUP block.
 <<HEP common: public>>=
   public :: heprup_write_verbose
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_write_verbose (unit)
+      integer, intent(in), optional :: unit
+    end subroutine heprup_write_verbose
 <<HEP common: procedures>>=
-  subroutine heprup_write_verbose (unit)
+  module subroutine heprup_write_verbose (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(A)")  "HEPRUP Common Block"
     write (u, "(3x,A6,' = ',I9,3x,1x,I9,3x,8x,A)")  "IDBMUP", IDBMUP, &
          "PDG code of beams"
     write (u, "(3x,A6,' = ',G12.5,1x,G12.5,8x,A)")  "EBMUP ", EBMUP, &
          "Energy of beams in GeV"
     write (u, "(3x,A6,' = ',I9,3x,1x,I9,3x,8x,A)")  "PDFGUP", PDFGUP, &
          "PDF author group [-1 = undefined]"
     write (u, "(3x,A6,' = ',I9,3x,1x,I9,3x,8x,A)")  "PDFSUP", PDFSUP, &
          "PDF set ID       [-1 = undefined]"
     write (u, "(3x,A6,' = ',I9,3x,1x,9x,3x,8x,A)")  "IDWTUP", IDWTUP, &
          "LHA code for event weight mode"
     write (u, "(3x,A6,' = ',I9,3x,1x,9x,3x,8x,A)")  "NPRUP ", NPRUP, &
          "Number of user subprocesses"
     do i = 1, NPRUP
        write (u, "(1x,A,I0)")  "Subprocess #", i
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "XSECUP", XSECUP(i), &
             "Cross section in pb"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "XERRUP", XERRUP(i), &
             "Cross section error in pb"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "XMAXUP", XMAXUP(i), &
             "Maximum event weight (cf. IDWTUP)"
        write (u, "(3x,A6,' = ',I9,3x,1x,12x,8x,A)")  "LPRUP ", LPRUP(i), &
             "Subprocess ID"
     end do
   end subroutine heprup_write_verbose
 
 @ %def heprup_write_verbose
 @
 \subsection{Run parameter output (other formats)}
 This routine writes the initialization block according to the LHEF
 standard.  It uses the current contents of the HEPRUP block.
 <<HEP common: public>>=
   public :: heprup_write_lhef
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_write_lhef (unit)
+      integer, intent(in), optional :: unit
+    end subroutine heprup_write_lhef
 <<HEP common: procedures>>=
-  subroutine heprup_write_lhef (unit)
+  module subroutine heprup_write_lhef (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(2(1x,I0),2(1x,ES17.10),6(1x,I0))") &
          IDBMUP, EBMUP, PDFGUP, PDFSUP, IDWTUP, NPRUP
     do i = 1, NPRUP
        write (u, "(3(1x,ES17.10),1x,I0)") &
             XSECUP(i), XERRUP(i), XMAXUP(i), LPRUP(i)
     end do
   end subroutine heprup_write_lhef
 
 @ %def heprup_write_lhef
 @
 This routine is a complete dummy at the moment. It uses the current
 contents of the HEPRUP block. At the end, it should depend on certain
 input flags for the different ASCII event formats.
 <<HEP common: public>>=
   public :: heprup_write_ascii
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_write_ascii (unit)
+      integer, intent(in), optional :: unit
+    end subroutine heprup_write_ascii
 <<HEP common: procedures>>=
-  subroutine heprup_write_ascii (unit)
+  module subroutine heprup_write_ascii (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(2(1x,I0),2(1x,ES17.10),6(1x,I0))") &
          IDBMUP, EBMUP, PDFGUP, PDFSUP, IDWTUP, NPRUP
     do i = 1, NPRUP
        write (u, "(3(1x,ES17.10),1x,I0)") &
             XSECUP(i), XERRUP(i), XMAXUP(i), LPRUP(i)
     end do
   end subroutine heprup_write_ascii
 
 @ %def heprup_write_ascii
 @
 \subsubsection{Run parameter input (LHEF)}
 In a LHEF file, the parameters are written in correct order on
 separate lines, but we should not count on the precise format.
 List-directed input should just work.
 <<HEP common: public>>=
   public :: heprup_read_lhef
+<<HEP common: sub interfaces>>=
+    module subroutine heprup_read_lhef (u)
+      integer, intent(in) :: u
+    end subroutine heprup_read_lhef
 <<HEP common: procedures>>=
-  subroutine heprup_read_lhef (u)
+  module subroutine heprup_read_lhef (u)
     integer, intent(in) :: u
     integer :: i
     read (u, *) &
          IDBMUP, EBMUP, PDFGUP, PDFSUP, IDWTUP, NPRUP
     do i = 1, NPRUP
        read (u, *) &
             XSECUP(i), XERRUP(i), XMAXUP(i), LPRUP(i)
     end do
   end subroutine heprup_read_lhef
 
 @ %def heprup_read_lhef
 @
 \subsection{The HEPEUP common block}
 <<HEP common: common blocks>>=
   common /HEPEUP/ &
        NUP, IDPRUP, XWGTUP, SCALUP, AQEDUP, AQCDUP, &
        IDUP, ISTUP, MOTHUP, ICOLUP, PUP, VTIMUP, SPINUP
   save /HEPEUP/
 
 @ %def HEPEUP
 @
 \subsubsection{Initialization}
 Fill the event characteristics of the common block.  The
 initialization sets only the number of particles and initializes the
 rest with default values.  The other routine sets the optional
 parameters.
 <<HEP common: public>>=
   public :: hepeup_init
   public :: hepeup_set_event_parameters
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_init (n_tot)
+      integer, intent(in) :: n_tot
+    end subroutine hepeup_init
+    module subroutine hepeup_set_event_parameters &
+         (proc_id, weight, scale, alpha_qed, alpha_qcd)
+      integer, intent(in), optional :: proc_id
+      real(default), intent(in), optional :: &
+           weight, scale, alpha_qed, alpha_qcd
+    end subroutine hepeup_set_event_parameters
 <<HEP common: procedures>>=
-  subroutine hepeup_init (n_tot)
+  module subroutine hepeup_init (n_tot)
     integer, intent(in) :: n_tot
     NUP = n_tot
     IDPRUP = 0
     XWGTUP = 1
     SCALUP = -1
     AQEDUP = -1
     AQCDUP = -1
   end subroutine hepeup_init
 
-  subroutine hepeup_set_event_parameters &
+  module subroutine hepeup_set_event_parameters &
        (proc_id, weight, scale, alpha_qed, alpha_qcd)
     integer, intent(in), optional :: proc_id
-    real(default), intent(in), optional :: weight, scale, alpha_qed, alpha_qcd
+    real(default), intent(in), optional :: &
+         weight, scale, alpha_qed, alpha_qcd
     if (present (proc_id))   IDPRUP = proc_id
     if (present (weight))    XWGTUP = weight
     if (present (scale))     SCALUP = scale
     if (present (alpha_qed)) AQEDUP = alpha_qed
     if (present (alpha_qcd)) AQCDUP = alpha_qcd
   end subroutine hepeup_set_event_parameters
 
 @ %def hepeup_init hepeup_set_event_parameters
 @ Extract event information.  The caller determines the parameters.
 <<HEP common: public>>=
   public :: hepeup_get_event_parameters
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_get_event_parameters &
+         (proc_id, weight, scale, alpha_qed, alpha_qcd)
+      integer, intent(out), optional :: proc_id
+      real(default), intent(out), optional :: &
+           weight, scale, alpha_qed, alpha_qcd
+    end subroutine hepeup_get_event_parameters
 <<HEP common: procedures>>=
-  subroutine hepeup_get_event_parameters &
+  module subroutine hepeup_get_event_parameters &
        (proc_id, weight, scale, alpha_qed, alpha_qcd)
     integer, intent(out), optional :: proc_id
-    real(default), intent(out), optional :: weight, scale, alpha_qed, alpha_qcd
+    real(default), intent(out), optional :: &
+         weight, scale, alpha_qed, alpha_qcd
     if (present (proc_id))   proc_id   = IDPRUP
     if (present (weight))    weight    = XWGTUP
     if (present (scale))     scale     = SCALUP
     if (present (alpha_qed)) alpha_qed = AQEDUP
     if (present (alpha_qcd)) alpha_qcd = AQCDUP
   end subroutine hepeup_get_event_parameters
 
 @ %def hepeup_get_event_parameters
 @
 \subsubsection{Particle data}
 Below we need the particle status codes which are actually defined
 in the [[subevents]] module.
 
 Set the entry for a specific particle.  All parameters are set with
 the exception of lifetime and spin, where default values are stored.
 <<HEP common: public>>=
   public :: hepeup_set_particle
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_set_particle (i, pdg, status, parent, col, p, m2)
+      integer, intent(in) :: i
+      integer, intent(in) :: pdg, status
+      integer, dimension(:), intent(in) :: parent
+      type(vector4_t), intent(in) :: p
+      integer, dimension(2), intent(in) :: col
+      real(default), intent(in) :: m2
+    end subroutine hepeup_set_particle
 <<HEP common: procedures>>=
-  subroutine hepeup_set_particle (i, pdg, status, parent, col, p, m2)
+  module subroutine hepeup_set_particle (i, pdg, status, parent, col, p, m2)
     integer, intent(in) :: i
     integer, intent(in) :: pdg, status
     integer, dimension(:), intent(in) :: parent
     type(vector4_t), intent(in) :: p
     integer, dimension(2), intent(in) :: col
     real(default), intent(in) :: m2
     if (i > MAXNUP) then
        call msg_error (arr=[ &
             var_str ("Too many particles in HEPEUP common block. " // &
                             "If this happened "), &
             var_str ("during event output, your events will be " // &
                             "invalid; please consider "), &
             var_str ("switching to a modern event format like HEPMC. " // &
                             "If you are not "), &
             var_str ("using an old, HEPEUP based format and " // &
                             "nevertheless get this error,"), &
             var_str ("please notify the WHIZARD developers,") ])
        return
     end if
     IDUP(i) = pdg
     select case (status)
     case (PRT_BEAM);         ISTUP(i) = -9
     case (PRT_INCOMING);     ISTUP(i) = -1
     case (PRT_BEAM_REMNANT); ISTUP(i) =  3
     case (PRT_OUTGOING);     ISTUP(i) =  1
     case (PRT_RESONANT);     ISTUP(i) =  2
     case (PRT_VIRTUAL);      ISTUP(i) =  3
     case default;            ISTUP(i) =  0
     end select
     select case (size (parent))
     case (0);      MOTHUP(:,i) = 0
     case (1);      MOTHUP(1,i) = parent(1); MOTHUP(2,i) = 0
     case default;  MOTHUP(:,i) = [ parent(1), parent(size (parent)) ]
     end select
     if (col(1) > 0) then
        ICOLUP(1,i) = 500 + col(1)
     else
        ICOLUP(1,i) = 0
     end if
     if (col(2) > 0) then
        ICOLUP(2,i) = 500 + col(2)
     else
        ICOLUP(2,i) = 0
     end if
     PUP(1:3,i) = refmt_tiny (vector3_get_components (space_part (p)))
     PUP(4,i) = refmt_tiny (energy (p))
     PUP(5,i) = refmt_tiny (sign (sqrt (abs (m2)), m2))
     VTIMUP(i) = 0
     SPINUP(i) = 9
   end subroutine hepeup_set_particle
 
 @ %def hepeup_set_particle
 @ Set the lifetime, actually $c\tau$ measured im mm, where $\tau$ is
 the invariant lifetime.
 <<HEP common: public>>=
   public :: hepeup_set_particle_lifetime
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_set_particle_lifetime (i, lifetime)
+      integer, intent(in) :: i
+      real(default), intent(in) :: lifetime
+    end subroutine hepeup_set_particle_lifetime
 <<HEP common: procedures>>=
-  subroutine hepeup_set_particle_lifetime (i, lifetime)
+  module subroutine hepeup_set_particle_lifetime (i, lifetime)
     integer, intent(in) :: i
     real(default), intent(in) :: lifetime
     VTIMUP(i) = lifetime
   end subroutine hepeup_set_particle_lifetime
 
 @ %def hepeup_set_particle_lifetime
 @ Set the particle spin entry.  We need the cosine of the angle of the
 spin axis with respect to the three-momentum of the parent particle.
 
 If the particle has a full polarization density matrix given, we need
 the particle momentum and polarization as well as the mother-particle
 momentum.  The polarization is transformed into a spin vector (which
 is sensible only for spin-1/2 or massless particles), which then is
 transformed into the lab frame (by a rotation of the 3-axis to the
 particle momentum axis).  Finally, we compute the scalar product of
 this vector with the mother-particle three-momentum.
 
 This puts severe restrictions on the applicability of this definition,
 and Lorentz invariance is lost.  Unfortunately, the Les Houches Accord
 requires this computation.
 <<HEP common: public>>=
   public :: hepeup_set_particle_spin
 <<HEP common: interfaces>>=
   interface hepeup_set_particle_spin
      module procedure hepeup_set_particle_spin_pol
   end interface
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_set_particle_spin_pol (i, p, pol, p_mother)
+      integer, intent(in) :: i
+      type(vector4_t), intent(in) :: p
+      type(polarization_t), intent(in) :: pol
+      type(vector4_t), intent(in) :: p_mother
+    end subroutine hepeup_set_particle_spin_pol
 <<HEP common: procedures>>=
-  subroutine hepeup_set_particle_spin_pol (i, p, pol, p_mother)
+  module subroutine hepeup_set_particle_spin_pol (i, p, pol, p_mother)
     integer, intent(in) :: i
     type(vector4_t), intent(in) :: p
     type(polarization_t), intent(in) :: pol
     type(vector4_t), intent(in) :: p_mother
     type(vector3_t) :: s3, p3
     type(vector4_t) :: s4
     s3 = vector3_moving (pol%get_axis ())
     p3 = space_part (p)
     s4 = rotation_to_2nd (3, p3) * vector4_moving (0._default, s3)
     SPINUP(i) = enclosed_angle_ct (s4, p_mother)
   end subroutine hepeup_set_particle_spin_pol
 
 @ %def hepeup_set_particle_spin
 @
 Extract particle data.  The caller decides which ones to retrieve.
 
 Status codes: beam remnants share the status code with virtual particles.
 However, for the purpose of WHIZARD we should identify them.  We
 use the PDG code for this.
 <<HEP common: public>>=
   public :: hepeup_get_particle
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_get_particle (i, pdg, status, parent, col, p, m2)
+      integer, intent(in) :: i
+      integer, intent(out), optional :: pdg, status
+      integer, dimension(:), intent(out), optional :: parent
+      type(vector4_t), intent(out), optional :: p
+      integer, dimension(2), intent(out), optional :: col
+      real(default), dimension(5,MAXNUP) :: pup_def
+      real(default), intent(out), optional :: m2
+    end subroutine hepeup_get_particle
 <<HEP common: procedures>>=
-  subroutine hepeup_get_particle (i, pdg, status, parent, col, p, m2)
+  module subroutine hepeup_get_particle (i, pdg, status, parent, col, p, m2)
     integer, intent(in) :: i
     integer, intent(out), optional :: pdg, status
     integer, dimension(:), intent(out), optional :: parent
     type(vector4_t), intent(out), optional :: p
     integer, dimension(2), intent(out), optional :: col
     real(default), dimension(5,MAXNUP) :: pup_def
     real(default), intent(out), optional :: m2
     if (present (pdg))  pdg = IDUP(i)
     if (present (status)) then
        select case (ISTUP(i))
        case (-9);  status = PRT_BEAM
        case (-1);  status = PRT_INCOMING
        case (1);   status = PRT_OUTGOING
        case (2);   status = PRT_RESONANT
        case (3);
           select case (abs (IDUP(i)))
           case (HADRON_REMNANT, HADRON_REMNANT_SINGLET, &
                HADRON_REMNANT_TRIPLET, HADRON_REMNANT_OCTET)
              status = PRT_BEAM_REMNANT
           case default
              status = PRT_VIRTUAL
           end select
        case default
           status = PRT_UNDEFINED
        end select
     end if
     if (present (parent)) then
        select case (size (parent))
        case (0)
        case (1);    parent(1) = MOTHUP(1,i)
        case (2);    parent = MOTHUP(:,i)
        end select
     end if
     if (present (col)) then
        col = ICOLUP(:,i)
     end if
     if (present (p)) then
        pup_def = PUP
        p = vector4_moving (pup_def(4,i), vector3_moving (pup_def(1:3,i)))
     end if
     if (present (m2)) then
        m2 = sign (PUP(5,i) ** 2, PUP(5,i))
     end if
   end subroutine hepeup_get_particle
 
 @ %def hepeup_get_particle
 @
 \subsection{The HEPEVT and HEPEV4 common block}
 
 For the LEP Monte Carlos, a standard common block has been proposed
 in AKV89.  We strongly recommend its use.  (The description is an
 abbreviated transcription of AKV89, Vol. 3, pp. 327-330).
 
 [[NMXHEP]] is the maximum number of entries:
 <<HEP common: variables>>=
   integer, parameter :: NMXHEP = 4000
 
 @ %def NMXHEP
 @ [[NEVHEP]] is normally the event number, but may take special
 values as follows:
 
    0   the program does not keep track of event numbers.
   -1   a special initialization record.
   -2   a special final record.
 <<HEP common: variables>>=
   integer :: NEVHEP
 
 @ %def NEVHEP
 @  [[NHEP]] holds the number of entries for this event.
 <<HEP common: variables>>=
   integer, public :: NHEP
 
 @ %def NHEP
 @ The entry [[ISTHEP(N)]] gives the status code for the [[N]]th entry,
 with the following semantics:
    0       a null entry.
    1       an existing entry, which has not decayed or fragmented.
    2       a decayed or fragmented entry, which is retained for
            event history information.
    3       documentation line.
    4- 10   reserved for future standards.
   11-200   at the disposal of each model builder.
  201-      at the disposal of users.
 <<HEP common: variables>>=
   integer, dimension(NMXHEP), public :: ISTHEP
 
 @ %def ISTHEP
 @
 The Particle Data Group has proposed standard particle codes,
 which are to be stored in [[IDHEP(N)]].
 <<HEP common: variables>>=
   integer, dimension(NMXHEP), public :: IDHEP
 
 @ %def IDHEP
 @ [[JMOHEP(1,N)]] points to the mother of the [[N]]th entry, if any.
 It is set to zero for initial entries.
 [[JMOHEP(2,N)]] points to the second mother, if any.
 <<HEP common: variables>>=
   integer, dimension(2, NMXHEP), public :: JMOHEP
 
 @ %def JMOHEP
 @ [[JDAHEP(1,N)]] and [[JDAHEP(2,N)]] point to the first and last daughter
 of the [[N]]th entry, if any.  These are zero for entries which have not
 yet decayed.  The other daughters are stored in between these two.
 <<HEP common: variables>>=
   integer, dimension(2, NMXHEP), public :: JDAHEP
 
 @ %def JDAHEP
 @ In [[PHEP]] we store the momentum of the particle, more specifically
 this means that [[PHEP(1,N)]], [[PHEP(2,N)]], and [[PHEP(3,N)]] contain the
 momentum in the $x$, $y$, and $z$ direction (as defined by the machine
 people), measured in GeV/c.  [[PHEP(4,N)]] contains the energy in GeV
 and [[PHEP(5,N)]] the mass in GeV$/c^2$.  The latter may be negative for
 spacelike partons.
 <<HEP common: variables>>=
   double precision, dimension(5, NMXHEP), public :: PHEP
 
 @ %def PHEP
 @ Finally [[VHEP]] is the place to store the position of the production
 vertex.  [[VHEP(1,N)]], [[VHEP(2,N)]], and [[VHEP(3,N)]] contain the $x$, $y$,
 and $z$ coordinate (as defined by the machine people), measured in mm.
 [[VHEP(4,N)]] contains the production time in mm/c.
 <<HEP common: variables>>=
   double precision, dimension(4, NMXHEP) :: VHEP
 
 @ %def VHEP
 @ As an amendment to the proposed standard common block HEPEVT, we
 also have a polarisation common block HEPSPN, as described in
 AKV89.  [[SHEP(1,N)]], [[SHEP(2,N)]], and [[SHEP(3,N)]] give the $x$, $y$, and $z$
 component of the spinvector $s$ of a fermion in the fermions restframe.
 
 Furthermore, we add the polarization of the corresponding outgoing
 particles:
 <<HEP common: variables>>=
   integer, dimension(NMXHEP) :: hepevt_pol
 
 @ %def hepevt_pol
 @
 By this variable the identity of the current process is given, defined
 via the LPRUP codes.
 <<HEP common: variables>>=
   integer, public :: idruplh
 
 @ %def idruplh
 This is the event weight, i.e. the cross section divided by the total
 number of generated events for the output of the parton shower programs.
 <<HEP common: variables>>=
   double precision, public :: eventweightlh
 
 @ %def eventweightlh
 @ There are the values for the electromagnetic and the strong coupling
 constants, $\alpha_{em}$ and $\alpha_s$.
 <<HEP common: variables>>=
   double precision, public :: alphaqedlh, alphaqcdlh
 
 @ %def alphaqedlh, alphaqcdlh
 @ This is the squared scale $Q$ of the event.
 <<HEP common: variables>>=
   double precision, dimension(10), public :: scalelh
 
 @ %def scalelh
 @ Finally, these variables contain the spin information and the
 color/anticolor flow of the particles.
 <<HEP common: variables>>=
   double precision, dimension (3,NMXHEP), public :: spinlh
   integer, dimension (2,NMXHEP), public :: icolorflowlh
 
 @ %def spinlh icolorflowlh
 By convention, [[SHEP(4,N)]] is always 1. All this is taken from StdHep
 4.06 manual and written using Fortran90 conventions.
 <<HEP common: common blocks>>=
   common /HEPEVT/ &
        NEVHEP, NHEP, ISTHEP, IDHEP, &
        JMOHEP, JDAHEP, PHEP, VHEP
   save /HEPEVT/
 
 @ %def HEPEVT
 @ Here we store HEPEVT parameters of the WHIZARD 1 realization which
 are not part of the HEPEVT common block.
 <<HEP common: variables>>=
   integer :: hepevt_n_out, hepevt_n_remnants
 
 @ %def hepevt_n_out, hepevt_n_remnants
 @
 <<HEP common: variables>>=
   double precision :: hepevt_weight, hepevt_function_value
   double precision :: hepevt_function_ratio
 
 @ %def hepevt_weight hepevt_function_value
 @ The HEPEV4 common block is an extension of the HEPEVT common block
 to allow for partonic colored events, including especially the color
 flow etc.
 <<HEP common: common blocks>>=
   common /HEPEV4/ &
        eventweightlh, alphaqedlh, alphaqcdlh, scalelh, &
        spinlh, icolorflowlh, idruplh
   save /HEPEV4/
 
 @ %def HEPEV4
 @ Filling HEPEVT: If the event count is not provided, set [[NEVHEP]]
 to zero.  If the event count is [[-1]] or [[-2]], the record
 corresponds to initialization and finalization, and the event is
 irrelevant.
 
 Note that the event count may be larger than $2^{31}$ (2 GEvents).  In
 that case, cut off the upper bits since [[NEVHEP]] is probably limited
 to default integer.
 
 For the HEPEV4 common block, it is unclear why the [[scalelh]] variable
 is 10-dimensional. We choose to only set the first value of the array.
 <<HEP common: public>>=
   public :: hepevt_init
   public :: hepevt_set_event_parameters
+<<HEP common: sub interfaces>>=
+    module subroutine hepevt_init (n_tot, n_out)
+      integer, intent(in) :: n_tot, n_out
+    end subroutine hepevt_init
+    module subroutine hepevt_set_event_parameters &
+         (proc_id, weight, function_value, function_ratio, &
+         alpha_qcd, alpha_qed, scale, i_evt)
+      integer, intent(in), optional :: proc_id
+      integer, intent(in), optional :: i_evt
+      real(default), intent(in), optional :: weight, function_value, &
+         function_ratio, alpha_qcd, alpha_qed, scale
+    end subroutine hepevt_set_event_parameters
 <<HEP common: procedures>>=
-  subroutine hepevt_init (n_tot, n_out)
+  module subroutine hepevt_init (n_tot, n_out)
     integer, intent(in) :: n_tot, n_out
     NHEP              = n_tot
     NEVHEP            = 0
     idruplh           = 0
     hepevt_n_out      = n_out
     hepevt_n_remnants = 0
     hepevt_weight     = 1
     eventweightlh     = 1
     hepevt_function_value = 0
     hepevt_function_ratio = 1
     alphaqcdlh        = -1
     alphaqedlh        = -1
     scalelh           = -1
   end subroutine hepevt_init
 
-  subroutine hepevt_set_event_parameters &
+  module subroutine hepevt_set_event_parameters &
        (proc_id, weight, function_value, function_ratio, &
        alpha_qcd, alpha_qed, scale, i_evt)
     integer, intent(in), optional :: proc_id
     integer, intent(in), optional :: i_evt
     real(default), intent(in), optional :: weight, function_value, &
        function_ratio, alpha_qcd, alpha_qed, scale
     if (present (proc_id))  idruplh = proc_id
     if (present (i_evt))  NEVHEP = i_evt
     if (present (weight)) then
        hepevt_weight = weight
        eventweightlh = weight
     end if
     if (present (function_value)) hepevt_function_value = &
          function_value
     if (present (function_ratio)) hepevt_function_ratio = &
          function_ratio
     if (present (alpha_qcd))  alphaqcdlh = alpha_qcd
     if (present (alpha_qed))  alphaqedlh = alpha_qed
     if (present (scale))  scalelh(1) = scale
     if (present (i_evt))  NEVHEP = i_evt
   end subroutine hepevt_set_event_parameters
 
 @ %def hepevt_init hepevt_set_event_parameters
 @ Set the entry for a specific particle.  All parameters are set with
 the exception of lifetime and spin, where default values are stored.
 <<HEP common: public>>=
   public :: hepevt_set_particle
+<<HEP common: sub interfaces>>=
+    module subroutine hepevt_set_particle &
+         (i, pdg, status, parent, child, p, m2, hel, vtx, &
+         col, pol_status, pol, fill_hepev4)
+      integer, intent(in) :: i
+      integer, intent(in) :: pdg, status
+      integer, dimension(:), intent(in) :: parent
+      integer, dimension(:), intent(in) :: child
+      logical, intent(in), optional :: fill_hepev4
+      type(vector4_t), intent(in) :: p
+      real(default), intent(in) :: m2
+      integer, dimension(2), intent(in) :: col
+      integer, intent(in) :: pol_status
+      integer, intent(in) :: hel
+      type(polarization_t), intent(in), optional :: pol
+      type(vector4_t), intent(in) :: vtx
+    end subroutine hepevt_set_particle
 <<HEP common: procedures>>=
-  subroutine hepevt_set_particle &
+  module subroutine hepevt_set_particle &
        (i, pdg, status, parent, child, p, m2, hel, vtx, &
        col, pol_status, pol, fill_hepev4)
     integer, intent(in) :: i
     integer, intent(in) :: pdg, status
     integer, dimension(:), intent(in) :: parent
     integer, dimension(:), intent(in) :: child
     logical, intent(in), optional :: fill_hepev4
     type(vector4_t), intent(in) :: p
     real(default), intent(in) :: m2
     integer, dimension(2), intent(in) :: col
     integer, intent(in) :: pol_status
     integer, intent(in) :: hel
     type(polarization_t), intent(in), optional :: pol
     type(vector4_t), intent(in) :: vtx
     logical :: hepev4
     hepev4 = .false.; if (present (fill_hepev4))  hepev4 = fill_hepev4
     IDHEP(i) = pdg
     select case (status)
       case (PRT_BEAM);      ISTHEP(i) = 2
       case (PRT_INCOMING);  ISTHEP(i) = 2
       case (PRT_OUTGOING);  ISTHEP(i) = 1
       case (PRT_VIRTUAL);   ISTHEP(i) = 2
       case (PRT_RESONANT);  ISTHEP(i) = 2
       case default;         ISTHEP(i) = 0
     end select
     select case (size (parent))
     case (0);      JMOHEP(:,i) = 0
     case (1);      JMOHEP(1,i) = parent(1); JMOHEP(2,i) = 0
     case default;  JMOHEP(:,i) = [ parent(1), parent(size (parent)) ]
     end select
     select case (size (child))
     case (0);      JDAHEP(:,i) = 0
     case (1);      JDAHEP(:,i) = child(1)
     case default;  JDAHEP(:,i) = [ child(1), child(size (child)) ]
     end select
     PHEP(1:3,i) = refmt_tiny (vector3_get_components (space_part (p)))
     PHEP(4,i) = refmt_tiny (energy (p))
     PHEP(5,i) = refmt_tiny (sign (sqrt (abs (m2)), m2))
     VHEP(1:3,i) = vtx%p(1:3)
     VHEP(4,i) = vtx%p(0)
     hepevt_pol(i) = hel
     if (hepev4) then
        if (col(1) > 0) then
           icolorflowlh(1,i) = 500 + col(1)
        else
           icolorflowlh(1,i) = 0
        end if
        if (col(2) > 0) then
           icolorflowlh(2,i) = 500 + col(2)
        else
           icolorflowlh(2,i) = 0
        end if
        if (present (pol) .and. &
             pol_status == PRT_GENERIC_POLARIZATION) then
           if (pol%is_polarized ()) &
              spinlh(:,i) = pol%get_axis ()
        else
           spinlh(:,i) = zero
           spinlh(3,i) = hel
        end if
     end if
   end subroutine hepevt_set_particle
 
 @ %def hepevt_set_particle
 @
 \subsection{Event output}
 This is a verbose output of the HEPEVT block.
 <<HEP common: public>>=
   public :: hepevt_write_verbose
+<<HEP common: sub interfaces>>=
+    module subroutine hepevt_write_verbose (unit)
+      integer, intent(in), optional :: unit
+    end subroutine hepevt_write_verbose
 <<HEP common: procedures>>=
-  subroutine hepevt_write_verbose (unit)
+  module subroutine hepevt_write_verbose (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(A)")  "HEPEVT Common Block"
     write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)")  "NEVHEP", NEVHEP, &
          "Event number"
     write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)")  "NHEP  ", NHEP, &
          "Number of particles in event"
     do i = 1, NHEP
        write (u, "(1x,A,I0)")  "Particle #", i
        write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)", advance="no") &
             "ISTHEP", ISTHEP(i), "Status code: "
        select case (ISTHEP(i))
        case ( 0);  write (u, "(A)")  "null entry"
        case ( 1);  write (u, "(A)")  "outgoing"
        case ( 2);  write (u, "(A)")  "decayed"
        case ( 3);  write (u, "(A)")  "documentation"
        case (4:10);  write (u, "(A)")  "[unspecified]"
        case (11:200);  write (u, "(A)")  "[model-specific]"
        case (201:);  write (u, "(A)")  "[user-defined]"
        case default;  write (u, "(A)")  "[undefined]"
        end select
        write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)")  "IDHEP ", IDHEP(i), &
             "PDG code of particle"
        write (u, "(3x,A6,' = ',I9,3x,1x,I9,3x,8x,A)")  "JMOHEP", JMOHEP(:,i), &
             "Index of first/second mother"
        write (u, "(3x,A6,' = ',I9,3x,1x,I9,3x,8x,A)")  "JDAHEP", JDAHEP(:,i), &
             "Index of first/last daughter"
        write (u, "(3x,A6,' = ',ES12.5,1x,ES12.5,8x,A)")  "PHEP12", &
             PHEP(1:2,i), "Transversal momentum (x/y) in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "PHEP3 ", PHEP(3,i), &
             "Longitudinal momentum (z) in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "PHEP4 ", PHEP(4,i), &
             "Energy in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "PHEP5 ", PHEP(5,i), &
             "Invariant mass in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,ES12.5,8x,A)")  "VHEP12", VHEP(1:2,i), &
             "Transversal displacement (xy) in mm"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "VHEP3 ", VHEP(3,i), &
             "Longitudinal displacement (z) in mm"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "VHEP4 ", VHEP(4,i), &
             "Production time in mm"
     end do
   end subroutine hepevt_write_verbose
 
 @ %def hepevt_write_verbose
 @
 This is a verbose output of the HEPEUP block.
 <<HEP common: public>>=
   public :: hepeup_write_verbose
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_write_verbose (unit)
+      integer, intent(in), optional :: unit
+    end subroutine hepeup_write_verbose
 <<HEP common: procedures>>=
-  subroutine hepeup_write_verbose (unit)
+  module subroutine hepeup_write_verbose (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(A)")  "HEPEUP Common Block"
     write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)")  "NUP   ", NUP, &
          "Number of particles in event"
     write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)")  "IDPRUP", IDPRUP, &
          "Subprocess ID"
     write (u, "(3x,A6,' = ',ES12.5,1x,20x,A)")  "XWGTUP", XWGTUP, &
          "Event weight"
     write (u, "(3x,A6,' = ',ES12.5,1x,20x,A)")  "SCALUP", SCALUP, &
          "Event energy scale in GeV"
     write (u, "(3x,A6,' = ',ES12.5,1x,20x,A)")  "AQEDUP", AQEDUP, &
          "QED coupling [-1 = undefined]"
     write (u, "(3x,A6,' = ',ES12.5,1x,20x,A)")  "AQCDUP", AQCDUP, &
          "QCD coupling [-1 = undefined]"
     do i = 1, NUP
        write (u, "(1x,A,I0)")  "Particle #", i
        write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)")  "IDUP  ", IDUP(i), &
             "PDG code of particle"
        write (u, "(3x,A6,' = ',I9,3x,1x,20x,A)", advance="no") &
             "ISTUP ", ISTUP(i), "Status code: "
        select case (ISTUP(i))
        case (-1);  write (u, "(A)")  "incoming"
        case ( 1);  write (u, "(A)")  "outgoing"
        case (-2);  write (u, "(A)")  "spacelike"
        case ( 2);  write (u, "(A)")  "resonance"
        case ( 3);  write (u, "(A)")  "resonance (doc)"
        case (-9);  write (u, "(A)")  "beam"
        case default;  write (u, "(A)")  "[undefined]"
        end select
        write (u, "(3x,A6,' = ',I9,3x,1x,I9,3x,8x,A)")  "MOTHUP", MOTHUP(:,i), &
             "Index of first/last mother"
        write (u, "(3x,A6,' = ',I9,3x,1x,I9,3x,8x,A)")  "ICOLUP", ICOLUP(:,i), &
             "Color/anticolor flow index"
        write (u, "(3x,A6,' = ',ES12.5,1x,ES12.5,8x,A)")  "PUP1/2", PUP(1:2,i), &
             "Transversal momentum (x/y) in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "PUP3  ", PUP(3,i), &
             "Longitudinal momentum (z) in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "PUP4  ", PUP(4,i), &
             "Energy in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "PUP5  ", PUP(5,i), &
             "Invariant mass in GeV"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "VTIMUP", VTIMUP(i), &
             "Invariant lifetime in mm"
        write (u, "(3x,A6,' = ',ES12.5,1x,12x,8x,A)")  "SPINUP", SPINUP(i), &
             "cos(spin angle) [9 = undefined]"
     end do
   end subroutine hepeup_write_verbose
 
 @ %def hepeup_write_verbose
 @
 \subsection{Event output in various formats}
 This routine writes event output according to the LHEF standard.  It
 uses the current contents of the HEPEUP block.
 <<HEP common: public>>=
   public :: hepeup_write_lhef
   public :: hepeup_write_lha
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_write_lhef (unit)
+      integer, intent(in), optional :: unit
+    end subroutine hepeup_write_lhef
+    module subroutine hepeup_write_lha (unit)
+      integer, intent(in), optional :: unit
+    end subroutine hepeup_write_lha
 <<HEP common: procedures>>=
-  subroutine hepeup_write_lhef (unit)
+  module subroutine hepeup_write_lhef (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     if (debug_on) call msg_debug (D_EVENTS, "hepeup_write_lhef")
     if (debug_on) call msg_debug2 (D_EVENTS, "ID IST MOTH ICOL P VTIM SPIN")
     write (u, "(2(1x,I0),4(1x,ES17.10))") &
          NUP, IDPRUP, XWGTUP, SCALUP, AQEDUP, AQCDUP
     do i = 1, NUP
        write (u, "(6(1x,I0),7(1x,ES17.10))") &
             IDUP(i), ISTUP(i), MOTHUP(:,i), ICOLUP(:,i), &
             PUP(:,i), VTIMUP(i), SPINUP(i)
        if (debug2_active (D_EVENTS)) then
           write (msg_buffer, "(6(1x,I0),7(1x,ES17.10))") &
                IDUP(i), ISTUP(i), MOTHUP(:,i), ICOLUP(:,i), &
                PUP(:,i), VTIMUP(i), SPINUP(i)
           call msg_message ()
        end if
     end do
   end subroutine hepeup_write_lhef
 
-  subroutine hepeup_write_lha (unit)
+  module subroutine hepeup_write_lha (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     integer, dimension(MAXNUP) :: spin_up
     spin_up = int(SPINUP)
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(2(1x,I5),1x,ES17.10,3(1x,ES13.6))") &
          NUP, IDPRUP, XWGTUP, SCALUP, AQEDUP, AQCDUP
     write (u, "(500(1x,I5))") IDUP(:NUP)
     write (u, "(500(1x,I5))") MOTHUP(1,:NUP)
     write (u, "(500(1x,I5))") MOTHUP(2,:NUP)
     write (u, "(500(1x,I5))") ICOLUP(1,:NUP)
     write (u, "(500(1x,I5))") ICOLUP(2,:NUP)
     write (u, "(500(1x,I5))") ISTUP(:NUP)
     write (u, "(500(1x,I5))") spin_up(:NUP)
     do i = 1, NUP
             write (u, "(1x,I5,4(1x,ES17.10))") i, PUP([ 4,1,2,3 ], i)
     end do
 
   end subroutine hepeup_write_lha
 
 @ %def hepeup_write_lhef hepeup_write_lha
 @ This routine writes event output according to the HEPEVT standard.  It
 uses the current contents of the HEPEVT block and some additional
 parameters according to the standard in WHIZARD 1. For the long ASCII
 format, the value of the sample function (i.e. the product of squared
 matrix element, structure functions and phase space factor is printed out).
 The option of reweighting matrix elements with respect to some
 reference cross section is not implemented in WHIZARD 2 for this event
 format, therefore the second entry in the long ASCII format (the
 function ratio) is always one. The ATHENA format is an implementation
 of the HEPEVT format that is readable by the ATLAS ATHENA software
 framework. It is very similar to the WHIZARD 1 HEPEVT format, except
 that it contains an event counter, a particle counter inside the
 event, and has the HEPEVT [[ISTHEP]] status before the PDG code. The
 MOKKA format is a special ASCII format  that contains the information
 to be parsed to the MOKKA LC fast simulation software.
 <<HEP common: public>>=
   public :: hepevt_write_hepevt
   public :: hepevt_write_ascii
   public :: hepevt_write_athena
   public :: hepevt_write_mokka
+<<HEP common: sub interfaces>>=
+    module subroutine hepevt_write_hepevt (unit)
+      integer, intent(in), optional :: unit
+    end subroutine hepevt_write_hepevt
+    module subroutine hepevt_write_ascii (unit, long)
+      integer, intent(in), optional :: unit
+      logical, intent(in) :: long
+    end subroutine hepevt_write_ascii
+    module subroutine hepevt_write_athena (unit)
+      integer, intent(in), optional :: unit
+    end subroutine hepevt_write_athena
+    module subroutine hepevt_write_mokka (unit)
+      integer, intent(in), optional :: unit
+    end subroutine hepevt_write_mokka
 <<HEP common: procedures>>=
-  subroutine hepevt_write_hepevt (unit)
+  module subroutine hepevt_write_hepevt (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(3(1x,I0),(1x,ES17.10))") &
          NHEP, hepevt_n_out, hepevt_n_remnants, hepevt_weight
     do i = 1, NHEP
        write (u, "(7(1x,I0))") &
             ISTHEP(i), IDHEP(i), JMOHEP(:,i), JDAHEP(:,i), hepevt_pol(i)
        write (u, "(5(1x,ES17.10))") PHEP(:,i)
        write (u, "(5(1x,ES17.10))") VHEP(:,i), 0.d0
     end do
   end subroutine hepevt_write_hepevt
 
-  subroutine hepevt_write_ascii (unit, long)
+  module subroutine hepevt_write_ascii (unit, long)
     integer, intent(in), optional :: unit
     logical, intent(in) :: long
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(3(1x,I0),(1x,ES17.10))") &
          NHEP, hepevt_n_out, hepevt_n_remnants, hepevt_weight
     do i = 1, NHEP
        if (ISTHEP(i) /= 1)  cycle
        write (u, "(2(1x,I0))") IDHEP(i), hepevt_pol(i)
        write (u, "(5(1x,ES17.10))") PHEP(:,i)
     end do
     if (long) then
        write (u, "(2(1x,ES17.10))") &
             hepevt_function_value, hepevt_function_ratio
     end if
   end subroutine hepevt_write_ascii
 
-  subroutine hepevt_write_athena (unit)
+  module subroutine hepevt_write_athena (unit)
     integer, intent(in), optional :: unit
     integer :: u, i, num_event
     num_event = 0
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(2(1x,I0))") NEVHEP, NHEP
     do i = 1, NHEP
        write (u, "(7(1x,I0))") &
             i, ISTHEP(i), IDHEP(i), JMOHEP(:,i), JDAHEP(:,i)
        write (u, "(5(1x,ES17.10))") PHEP(:,i)
        write (u, "(5(1x,ES17.10))") VHEP(1:4,i)
     end do
   end subroutine hepevt_write_athena
 
-  subroutine hepevt_write_mokka (unit)
+  module subroutine hepevt_write_mokka (unit)
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit);  if (u < 0)  return
     write (u, "(3(1x,I0),(1x,ES17.10))") &
          NHEP, hepevt_n_out, hepevt_n_remnants, hepevt_weight
     do i = 1, NHEP
        write (u, "(4(1x,I0),4(1x,ES17.10))") &
             ISTHEP(i), IDHEP(i), JDAHEP(1,i), JDAHEP(2,i), &
             PHEP(1:3,i), PHEP(5,i)
     end do
   end subroutine hepevt_write_mokka
 
 @ %def hepevt_write_hepevt hepevt_write_ascii
 @ %def hepevt_write_athena
 @
 \subsection{Event input in various formats}
 This routine writes event output according to the LHEF standard.  It
 uses the current contents of the HEPEUP block.
 <<HEP common: public>>=
   public :: hepeup_read_lhef
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_read_lhef (u)
+      integer, intent(in) :: u
+    end subroutine hepeup_read_lhef
 <<HEP common: procedures>>=
-  subroutine hepeup_read_lhef (u)
+  module subroutine hepeup_read_lhef (u)
     integer, intent(in) :: u
     integer :: i
     read (u, *) &
          NUP, IDPRUP, XWGTUP, SCALUP, AQEDUP, AQCDUP
     do i = 1, NUP
        read (u, *) &
             IDUP(i), ISTUP(i), MOTHUP(:,i), ICOLUP(:,i), &
             PUP(:,i), VTIMUP(i), SPINUP(i)
     end do
   end subroutine hepeup_read_lhef
 
 @ %def hepeup_read_lhef
 @
 \subsection{Data Transfer: particle sets}
 The \whizard\ format for handling particle data in events is
 [[particle_set_t]].  We have to interface this to the common blocks.
 
 We first create a new particle set that contains only the particles
 that are supported by the LHEF format.  These are: beam, incoming,
 resonant, outgoing.  We drop particles with unknown, virtual or
 beam-remnant status.
 
 From this set we fill the common block.  Event information such as
 process ID and weight is not transferred here; this has to be done by
 the caller.  The spin information is set only if the particle has a
 unique mother, and if its polarization is fully defined.
 
 We use this routine also to hand over information to Pythia which lets
 Tauola access SPINUP. Tauola expects in SPINUP the helicity and not the
 LHA convention. We switch to this mode with [[tauola_convention]].
 <<HEP common: public>>=
   public :: hepeup_from_particle_set
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_from_particle_set (pset_in, &
+       keep_beams, keep_remnants, tauola_convention)
+      type(particle_set_t), intent(in) :: pset_in
+      type(particle_set_t), target :: pset
+      logical, intent(in), optional :: keep_beams
+      logical, intent(in), optional :: keep_remnants
+      logical, intent(in), optional :: tauola_convention
+    end subroutine hepeup_from_particle_set
 <<HEP common: procedures>>=
-  subroutine hepeup_from_particle_set (pset_in, &
+  module subroutine hepeup_from_particle_set (pset_in, &
      keep_beams, keep_remnants, tauola_convention)
     type(particle_set_t), intent(in) :: pset_in
     type(particle_set_t), target :: pset
     logical, intent(in), optional :: keep_beams
     logical, intent(in), optional :: keep_remnants
     logical, intent(in), optional :: tauola_convention
     integer :: i, n_parents, status, n_tot
     integer, dimension(1) :: i_mother
     logical :: kr, tc
     kr = .true.;  if (present (keep_remnants))  kr = keep_remnants
     tc = .false.;  if (present (tauola_convention))  tc = tauola_convention
     call pset_in%filter_particles (pset, real_parents = .true. , &
        keep_beams = keep_beams, keep_virtuals = .false.)
     n_tot = pset%get_n_tot ()
     call hepeup_init (n_tot)
     do i = 1, n_tot
        associate (prt => pset%prt(i))
          status = prt%get_status ()
          if (kr .and. status == PRT_BEAM_REMNANT &
                 .and. prt%get_n_children () == 0) &
               status = PRT_OUTGOING
          call hepeup_set_particle (i, &
               prt%get_pdg (), &
               status, &
               prt%get_parents (), &
               prt%get_color (), &
               prt%get_momentum (), &
               prt%get_p2 ())
          n_parents = prt%get_n_parents ()
          call hepeup_set_particle_lifetime (i, &
               prt%get_lifetime ())
          if (.not. tc) then
             if (n_parents == 1) then
                i_mother = prt%get_parents ()
                select case (prt%get_polarization_status ())
                case (PRT_GENERIC_POLARIZATION)
                   call hepeup_set_particle_spin (i, &
                        prt%get_momentum (), &
                        prt%get_polarization (), &
                        pset%prt(i_mother(1))%get_momentum ())
                end select
             end if
          else
             select case (prt%get_polarization_status ())
             case (PRT_DEFINITE_HELICITY)
               SPINUP(i) = prt%get_helicity()
             end select
          end if
        end associate
     end do
   end subroutine hepeup_from_particle_set
 
 @ %def hepeup_from_particle_set
 @ Input.  The particle set should be allocated properly, but we
 replace the particle contents.
 
 If there are no beam particles in the event, we try to reconstruct beam
 particles and beam remnants.  We assume for simplicity that the beam
 particles, if any, are the first two particles.  If they are absent, the first
 two particles should be the incoming partons.
 <<HEP common: public>>=
   public :: hepeup_to_particle_set
+<<HEP common: sub interfaces>>=
+    module subroutine hepeup_to_particle_set &
+         (particle_set, recover_beams, model, alt_model)
+      type(particle_set_t), intent(inout), target :: particle_set
+      logical, intent(in), optional :: recover_beams
+      class(model_data_t), intent(in), target :: model, alt_model
+    end subroutine hepeup_to_particle_set
 <<HEP common: procedures>>=
-  subroutine hepeup_to_particle_set &
+  module subroutine hepeup_to_particle_set &
        (particle_set, recover_beams, model, alt_model)
     type(particle_set_t), intent(inout), target :: particle_set
     logical, intent(in), optional :: recover_beams
     class(model_data_t), intent(in), target :: model, alt_model
     type(particle_t), dimension(:), allocatable :: prt
     integer, dimension(2) :: parent
     integer, dimension(:), allocatable :: child
     integer :: i, j, k, pdg, status
     type(flavor_t) :: flv
     type(color_t) :: col
     integer, dimension(2) :: c
     type(vector4_t) :: p
     real(default) :: p2
     logical :: reconstruct
     integer :: off
     if (present (recover_beams)) then
        reconstruct = recover_beams .and. .not. all (ISTUP(1:2) == PRT_BEAM)
     else
        reconstruct = .false.
     end if
     if (reconstruct) then
        off = 4
     else
        off = 0
     end if
     allocate (prt (NUP + off), child (NUP + off))
     do i = 1, NUP
        k = i + off
        call hepeup_get_particle (i, pdg, status, col = c, p = p, m2 = p2)
        call flv%init (pdg, model, alt_model)
        call prt(k)%set_flavor (flv)
        call prt(k)%reset_status (status)
        call col%init (c)
        call prt(k)%set_color (col)
        call prt(k)%set_momentum (p, p2)
        where (MOTHUP(:,i) /= 0)
           parent = MOTHUP(:,i) + off
        elsewhere
           parent = 0
        end where
        call prt(k)%set_parents (parent)
        child = [(j, j = 1 + off, NUP + off)]
        where (MOTHUP(1,:NUP) /= i .and. MOTHUP(2,:NUP) /= i)  child = 0
        call prt(k)%set_children (child)
     end do
     if (reconstruct) then
        do k = 1, 2
           call prt(k)%reset_status (PRT_BEAM)
           call prt(k)%set_children ([k+2,k+4])
        end do
        do k = 3, 4
           call prt(k)%reset_status (PRT_BEAM_REMNANT)
           call prt(k)%set_parents ([k-2])
        end do
        do k = 5, 6
           call prt(k)%set_parents ([k-4])
        end do
     end if
     call particle_set%replace (prt)
   end subroutine hepeup_to_particle_set
 
 @ %def hepeup_to_particle_set
 @
 The HEPEVT common block is quite similar, but does contain less
 information, e.g. no color flows (it was LEP time). The spin
 information is set only if the particle has a unique mother, and if
 its polarization is fully defined.
 <<HEP common: public>>=
   public :: hepevt_from_particle_set
+<<HEP common: sub interfaces>>=
+    module subroutine hepevt_from_particle_set &
+         (particle_set, keep_beams, keep_remnants, ensure_order, fill_hepev4)
+      type(particle_set_t), intent(in) :: particle_set
+      type(particle_set_t), target :: pset_hepevt, pset_tmp
+      logical, intent(in), optional :: keep_beams
+      logical, intent(in), optional :: keep_remnants
+      logical, intent(in), optional :: ensure_order
+      logical, intent(in), optional :: fill_hepev4
+    end subroutine hepevt_from_particle_set
 <<HEP common: procedures>>=
-  subroutine hepevt_from_particle_set &
+  module subroutine hepevt_from_particle_set &
        (particle_set, keep_beams, keep_remnants, ensure_order, fill_hepev4)
     type(particle_set_t), intent(in) :: particle_set
     type(particle_set_t), target :: pset_hepevt, pset_tmp
     logical, intent(in), optional :: keep_beams
     logical, intent(in), optional :: keep_remnants
     logical, intent(in), optional :: ensure_order
     logical, intent(in), optional :: fill_hepev4
     integer :: i, status, n_tot
     logical :: activate_remnants, ensure
     activate_remnants = .true.
     if (present (keep_remnants))  activate_remnants = keep_remnants
     ensure = .false.
     if (present (ensure_order))  ensure = ensure_order
     call particle_set%filter_particles (pset_tmp, real_parents = .true., &
        keep_virtuals = .false., keep_beams = keep_beams)
     if (ensure) then
        call pset_tmp%to_hepevt_form (pset_hepevt)
     else
        pset_hepevt = pset_tmp
     end if
     n_tot = pset_hepevt%get_n_tot ()
     call hepevt_init (n_tot, pset_hepevt%get_n_out ())
     do i = 1, n_tot
        associate (prt => pset_hepevt%prt(i))
          status = prt%get_status ()
          if (activate_remnants &
               .and. status == PRT_BEAM_REMNANT &
               .and. prt%get_n_children () == 0) &
               status = PRT_OUTGOING
          select case (prt%get_polarization_status ())
          case (PRT_GENERIC_POLARIZATION)
             call hepevt_set_particle (i, &
                  prt%get_pdg (), status, &
                  prt%get_parents (), &
                  prt%get_children (), &
                  prt%get_momentum (), &
                  prt%get_p2 (), &
                  prt%get_helicity (), &
                  prt%get_vertex (), &
                  prt%get_color (), &
                  prt%get_polarization_status (), &
                  pol = prt%get_polarization (), &
                  fill_hepev4 = fill_hepev4)
          case default
             call hepevt_set_particle (i, &
                  prt%get_pdg (), status, &
                  prt%get_parents (), &
                  prt%get_children (), &
                  prt%get_momentum (), &
                  prt%get_p2 (), &
                  prt%get_helicity (), &
                  prt%get_vertex (), &
                  prt%get_color (), &
                  prt%get_polarization_status (), &
                  fill_hepev4 = fill_hepev4)
          end select
        end associate
     end do
     call pset_hepevt%final ()
   end subroutine hepevt_from_particle_set
 
 @ %def hepevt_from_particle_set
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{HepMC events}
 This section provides the interface to the HepMC C++ library for handling
 Monte-Carlo events.
 
 Each C++ class of HepMC that we use is mirrored by a Fortran type,
 which contains as its only component the C pointer to the C++ object.
 
 Each C++ method of HepMC that we use has a C wrapper function.  This
 function takes a pointer to the host object as its first argument.
 Further arguments are either C pointers, or in the case of simple
 types (integer, real), interoperable C/Fortran objects.
 
 The C wrapper functions have explicit interfaces in the Fortran
 module.  They are called by Fortran wrapper procedures.  These are
 treated as methods of the corresponding Fortran type.
 <<[[hepmc_interface.f90]]>>=
 <<File header>>
 
 module hepmc_interface
 
   use, intrinsic :: iso_c_binding !NODEP!
 
 <<Use kinds>>
 <<Use strings>>
-  use constants, only: PI
-  use physics_defs, only: pb_per_fb
-  use system_dependencies, only: HEPMC2_AVAILABLE
-  use system_dependencies, only: HEPMC3_AVAILABLE
-  use diagnostics
   use lorentz
   use flavors
   use colors
   use helicities
   use polarizations
   use event_handles, only: event_handle_t
 
 <<Standard module head>>
 
 <<HepMC interface: public>>
 
 <<HepMC interface: types>>
 
 <<HepMC interface: parameters>>
 
 <<HepMC interface: interfaces>>
 
+  interface
+<<HepMC interface: sub interfaces>>
+  end interface
+
+end module hepmc_interface
+@ %def hepmc_interface
+@
+<<[[hepmc_interface_sub.f90]]>>=
+<<File header>>
+
+submodule (hepmc_interface) hepmc_interface_s
+
+  use constants, only: PI
+  use physics_defs, only: pb_per_fb
+  use system_dependencies, only: HEPMC2_AVAILABLE
+  use system_dependencies, only: HEPMC3_AVAILABLE
+  use diagnostics
+
+  implicit none
+
 contains
 
 <<HepMC interface: procedures>>
 
-end module hepmc_interface
-@ %def hepmc_interface
+end submodule hepmc_interface_s
+
+@ %def hepmc_interface_s
 @
 \subsection{Interface check}
 This function can be called in order to verify that we are using the
 actual HepMC library, and not the dummy version.
 <<HepMC interface: interfaces>>=
   interface
      logical(c_bool) function hepmc_available () bind(C)
        import
      end function hepmc_available
   end interface
 <<HepMC interface: public>>=
   public :: hepmc_is_available
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_is_available () result (flag)
+      logical :: flag
+    end function hepmc_is_available
 <<HepMC interface: procedures>>=
-  function hepmc_is_available () result (flag)
+  module function hepmc_is_available () result (flag)
     logical :: flag
     flag = hepmc_available ()
   end function hepmc_is_available
 
 @ %def hepmc_is_available
 @
 \subsection{FourVector}
 The C version of four-vectors is often transferred by value, and the
 associated procedures are all inlined.  The wrapper needs to transfer
 by reference, so we create FourVector objects on the heap which have
 to be deleted explicitly.  The input is a [[vector4_t]] or
 [[vector3_t]] object from the [[lorentz]] module.
 <<HepMC interface: public>>=
   public :: hepmc_four_vector_t
 <<HepMC interface: types>>=
   type :: hepmc_four_vector_t
      private
      type(c_ptr) :: obj
   end type hepmc_four_vector_t
 
 @ %def hepmc_four_vector_t
 @ In the C constructor, the zero-component (fourth argument) is
 optional; if missing, it is set to zero.  The Fortran version has
 initializer form and takes either a three-vector or a four-vector.
 A further version extracts the four-vector from a HepMC particle
 object.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_four_vector_xyz (x, y, z) bind(C)
        import
        real(c_double), value :: x, y, z
      end function new_four_vector_xyz
   end interface
   interface
      type(c_ptr) function new_four_vector_xyzt (x, y, z, t) bind(C)
        import
        real(c_double), value :: x, y, z, t
      end function new_four_vector_xyzt
   end interface
 @ %def new_four_vector_xyz new_four_vector_xyzt
 <<HepMC interface: public>>=
   public :: hepmc_four_vector_init
 <<HepMC interface: interfaces>>=
   interface hepmc_four_vector_init
      module procedure hepmc_four_vector_init_v4
      module procedure hepmc_four_vector_init_v3
      module procedure hepmc_four_vector_init_hepmc_prt
   end interface
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_four_vector_init_v4 (pp, p)
+      type(hepmc_four_vector_t), intent(out) :: pp
+      type(vector4_t), intent(in) :: p
+    end subroutine hepmc_four_vector_init_v4
+    module subroutine hepmc_four_vector_init_v3 (pp, p)
+      type(hepmc_four_vector_t), intent(out) :: pp
+      type(vector3_t), intent(in) :: p
+    end subroutine hepmc_four_vector_init_v3
+    module subroutine hepmc_four_vector_init_hepmc_prt (pp, prt)
+      type(hepmc_four_vector_t), intent(out) :: pp
+      type(hepmc_particle_t), intent(in) :: prt
+    end subroutine hepmc_four_vector_init_hepmc_prt
 <<HepMC interface: procedures>>=
-  subroutine hepmc_four_vector_init_v4 (pp, p)
+  module subroutine hepmc_four_vector_init_v4 (pp, p)
     type(hepmc_four_vector_t), intent(out) :: pp
     type(vector4_t), intent(in) :: p
     real(default), dimension(0:3) :: pa
     pa = vector4_get_components (p)
     pp%obj = new_four_vector_xyzt &
          (real (pa(1), c_double), &
           real (pa(2), c_double), &
           real (pa(3), c_double), &
           real (pa(0), c_double))
   end subroutine hepmc_four_vector_init_v4
 
-  subroutine hepmc_four_vector_init_v3 (pp, p)
+  module subroutine hepmc_four_vector_init_v3 (pp, p)
     type(hepmc_four_vector_t), intent(out) :: pp
     type(vector3_t), intent(in) :: p
     real(default), dimension(3) :: pa
     pa = vector3_get_components (p)
     pp%obj = new_four_vector_xyz &
          (real (pa(1), c_double), &
           real (pa(2), c_double), &
           real (pa(3), c_double))
   end subroutine hepmc_four_vector_init_v3
 
-  subroutine hepmc_four_vector_init_hepmc_prt (pp, prt)
+  module subroutine hepmc_four_vector_init_hepmc_prt (pp, prt)
     type(hepmc_four_vector_t), intent(out) :: pp
     type(hepmc_particle_t), intent(in) :: prt
     pp%obj = gen_particle_momentum (prt%obj)
   end subroutine hepmc_four_vector_init_hepmc_prt
 
 @ %def hepmc_four_vector_init
 @ Here, the destructor is explicitly needed.
 <<HepMC interface: interfaces>>=
   interface
      subroutine four_vector_delete (p_obj) bind(C)
        import
        type(c_ptr), value :: p_obj
      end subroutine four_vector_delete
   end interface
 @ %def four_vector_delete
 <<HepMC interface: public>>=
   public :: hepmc_four_vector_final
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_four_vector_final (p)
+      type(hepmc_four_vector_t), intent(inout) :: p
+    end subroutine hepmc_four_vector_final
 <<HepMC interface: procedures>>=
-  subroutine hepmc_four_vector_final (p)
+  module subroutine hepmc_four_vector_final (p)
     type(hepmc_four_vector_t), intent(inout) :: p
     call four_vector_delete (p%obj)
   end subroutine hepmc_four_vector_final
 
 @ %def hepmc_four_vector_final
 @ Convert to a Lorentz vector.
 <<HepMC interface: interfaces>>=
   interface
      function four_vector_px (p_obj) result (px) bind(C)
        import
        real(c_double) :: px
        type(c_ptr), value :: p_obj
      end function four_vector_px
   end interface
   interface
      function four_vector_py (p_obj) result (py) bind(C)
        import
        real(c_double) :: py
        type(c_ptr), value :: p_obj
      end function four_vector_py
   end interface
   interface
      function four_vector_pz (p_obj) result (pz) bind(C)
        import
        real(c_double) :: pz
        type(c_ptr), value :: p_obj
      end function four_vector_pz
   end interface
   interface
      function four_vector_e (p_obj) result (e) bind(C)
        import
        real(c_double) :: e
        type(c_ptr), value :: p_obj
      end function four_vector_e
   end interface
 @ %def four_vector_px four_vector_py four_vector_pz four_vector_e
 <<HepMC interface: public>>=
   public :: hepmc_four_vector_to_vector4
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_four_vector_to_vector4 (pp, p)
+      type(hepmc_four_vector_t), intent(in) :: pp
+      type(vector4_t), intent(out) :: p
+    end subroutine hepmc_four_vector_to_vector4
 <<HepMC interface: procedures>>=
-  subroutine hepmc_four_vector_to_vector4 (pp, p)
+  module subroutine hepmc_four_vector_to_vector4 (pp, p)
     type(hepmc_four_vector_t), intent(in) :: pp
     type(vector4_t), intent(out) :: p
     real(default) :: E
     real(default), dimension(3) :: p3
     E = four_vector_e (pp%obj)
     p3(1) = four_vector_px (pp%obj)
     p3(2) = four_vector_py (pp%obj)
     p3(3) = four_vector_pz (pp%obj)
     p = vector4_moving (E, vector3_moving (p3))
   end subroutine hepmc_four_vector_to_vector4
 
 @ %def hepmc_four_vector_to_vector4
 @
 \subsection{Polarization}
 Polarization objects are temporarily used for assigning particle
 polarization.  We add a flag [[polarized]].  If this is false, the
 polarization is not set and should not be transferred to
 [[hepmc_particle]] objects.
 <<HepMC interface: public>>=
   public :: hepmc_polarization_t
 <<HepMC interface: types>>=
   type :: hepmc_polarization_t
      private
      logical :: polarized = .false.
      type(c_ptr) :: obj
   end type hepmc_polarization_t
 
 @ %def hepmc_polarization_t
 @ Constructor.  The C wrapper takes polar and azimuthal angle as
 arguments.  The Fortran version allows for either a complete
 polarization density matrix, or for a definite (diagonal) helicity.
 
 \emph{HepMC does not allow to specify the degree of polarization,
   therefore we have to map it to either 0 or 1.  We choose 0 for
   polarization less than $0.5$ and 1 for polarization greater than
   $0.5$.  Even this simplification works only for spin-1/2 and for
   massless particles; massive vector bosons cannot be treated this
   way.  In particular, zero helicity is always translated as
   unpolarized.}
 
 \emph{For massive vector bosons, we arbitrarily choose the convention
   that the longitudinal (zero) helicity state is mapped to the theta
   angle $\pi/2$.  This works under the condition that helicity is
   projected onto one of the basis states.}
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_polarization (theta, phi) bind(C)
        import
        real(c_double), value :: theta, phi
      end function new_polarization
   end interface
 @ %def new_polarization
 <<HepMC interface: public>>=
   public :: hepmc_polarization_init
 <<HepMC interface: interfaces>>=
   interface hepmc_polarization_init
      module procedure hepmc_polarization_init_pol
      module procedure hepmc_polarization_init_hel
      module procedure hepmc_polarization_init_int
   end interface
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_polarization_init_pol (hpol, pol)
+      type(hepmc_polarization_t), intent(out) :: hpol
+      type(polarization_t), intent(in) :: pol
+    end subroutine hepmc_polarization_init_pol
+    module subroutine hepmc_polarization_init_hel (hpol, hel)
+      type(hepmc_polarization_t), intent(out) :: hpol
+      type(helicity_t), intent(in) :: hel
+    end subroutine hepmc_polarization_init_hel
+    module subroutine hepmc_polarization_init_int (hpol, hel)
+      type(hepmc_polarization_t), intent(out) :: hpol
+      integer, intent(in) :: hel
+    end subroutine hepmc_polarization_init_int
 <<HepMC interface: procedures>>=
-  subroutine hepmc_polarization_init_pol (hpol, pol)
+  module subroutine hepmc_polarization_init_pol (hpol, pol)
     type(hepmc_polarization_t), intent(out) :: hpol
     type(polarization_t), intent(in) :: pol
     real(default) :: r, theta, phi
     if (pol%is_polarized ()) then
        call pol%to_angles (r, theta, phi)
        if (r >= 0.5) then
           hpol%polarized = .true.
           hpol%obj = new_polarization &
                (real (theta, c_double), real (phi, c_double))
        end if
     end if
   end subroutine hepmc_polarization_init_pol
 
-  subroutine hepmc_polarization_init_hel (hpol, hel)
+  module subroutine hepmc_polarization_init_hel (hpol, hel)
     type(hepmc_polarization_t), intent(out) :: hpol
     type(helicity_t), intent(in) :: hel
     integer, dimension(2) :: h
     if (hel%is_defined ()) then
        h = hel%to_pair ()
        select case (h(1))
        case (1:)
           hpol%polarized = .true.
           hpol%obj = new_polarization (0._c_double, 0._c_double)
        case (:-1)
           hpol%polarized = .true.
           hpol%obj = new_polarization (real (pi, c_double), 0._c_double)
        case (0)
           hpol%polarized = .true.
           hpol%obj = new_polarization (real (pi/2, c_double), 0._c_double)
        end select
     end if
   end subroutine hepmc_polarization_init_hel
 
-  subroutine hepmc_polarization_init_int (hpol, hel)
+  module subroutine hepmc_polarization_init_int (hpol, hel)
     type(hepmc_polarization_t), intent(out) :: hpol
     integer, intent(in) :: hel
     select case (hel)
     case (1:)
        hpol%polarized = .true.
        hpol%obj = new_polarization (0._c_double, 0._c_double)
     case (:-1)
        hpol%polarized = .true.
        hpol%obj = new_polarization (real (pi, c_double), 0._c_double)
     case (0)
        hpol%polarized = .true.
        hpol%obj = new_polarization (real (pi/2, c_double), 0._c_double)
     end select
   end subroutine hepmc_polarization_init_int
 
 @ %def hepmc_polarization_init
 @ Destructor.  The C object is deallocated only if the [[polarized]]
 flag is set.
 <<HepMC interface: interfaces>>=
   interface
      subroutine polarization_delete (pol_obj) bind(C)
        import
        type(c_ptr), value :: pol_obj
      end subroutine polarization_delete
   end interface
 @ %def polarization_delete
 <<HepMC interface: public>>=
   public :: hepmc_polarization_final
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_polarization_final (hpol)
+      type(hepmc_polarization_t), intent(inout) :: hpol
+    end subroutine hepmc_polarization_final
 <<HepMC interface: procedures>>=
-  subroutine hepmc_polarization_final (hpol)
+  module subroutine hepmc_polarization_final (hpol)
     type(hepmc_polarization_t), intent(inout) :: hpol
     if (hpol%polarized)  call polarization_delete (hpol%obj)
   end subroutine hepmc_polarization_final
 
 @ %def hepmc_polarization_final
 @ Recover polarization from HepMC polarization object (with the
 abovementioned deficiencies).
 <<HepMC interface: interfaces>>=
   interface
      function polarization_theta (pol_obj) result (theta) bind(C)
        import
        real(c_double) :: theta
        type(c_ptr), value :: pol_obj
      end function polarization_theta
   end interface
   interface
      function polarization_phi (pol_obj) result (phi) bind(C)
        import
        real(c_double) :: phi
        type(c_ptr), value :: pol_obj
      end function polarization_phi
   end interface
 @ %def polarization_theta polarization_phi
 <<HepMC interface: public>>=
   public :: hepmc_polarization_to_pol
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_polarization_to_pol (hpol, flv, pol)
+      type(hepmc_polarization_t), intent(in) :: hpol
+      type(flavor_t), intent(in) :: flv
+      type(polarization_t), intent(out) :: pol
+    end subroutine hepmc_polarization_to_pol
 <<HepMC interface: procedures>>=
-  subroutine hepmc_polarization_to_pol (hpol, flv, pol)
+  module subroutine hepmc_polarization_to_pol (hpol, flv, pol)
     type(hepmc_polarization_t), intent(in) :: hpol
     type(flavor_t), intent(in) :: flv
     type(polarization_t), intent(out) :: pol
     real(default) :: theta, phi
     theta = polarization_theta (hpol%obj)
     phi = polarization_phi (hpol%obj)
     call pol%init_angles (flv, 1._default, theta, phi)
   end subroutine hepmc_polarization_to_pol
 
 @ %def hepmc_polarization_to_pol
 @ Recover helicity.  Here, $\phi$ is ignored and only the sign of
 $\cos\theta$ is relevant, mapped to positive/negative helicity.
 <<HepMC interface: public>>=
   public :: hepmc_polarization_to_hel
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_polarization_to_hel (hpol, flv, hel)
+      type(hepmc_polarization_t), intent(in) :: hpol
+      type(flavor_t), intent(in) :: flv
+      type(helicity_t), intent(out) :: hel
+    end subroutine hepmc_polarization_to_hel
 <<HepMC interface: procedures>>=
-  subroutine hepmc_polarization_to_hel (hpol, flv, hel)
+  module subroutine hepmc_polarization_to_hel (hpol, flv, hel)
     type(hepmc_polarization_t), intent(in) :: hpol
     type(flavor_t), intent(in) :: flv
     type(helicity_t), intent(out) :: hel
     real(default) :: theta
     integer :: hmax
     theta = polarization_theta (hpol%obj)
     hmax = flv%get_spin_type () / 2
     call hel%init (sign (hmax, nint (cos (theta))))
   end subroutine hepmc_polarization_to_hel
 
 @ %def hepmc_polarization_to_hel
 @
 \subsection{GenParticle}
 Particle objects have the obvious meaning.
 <<HepMC interface: public>>=
   public :: hepmc_particle_t
 <<HepMC interface: types>>=
   type :: hepmc_particle_t
      private
      type(c_ptr) :: obj
   end type hepmc_particle_t
 
 @ %def hepmc_particle_t
 @ Constructor.  The C version takes a FourVector object, which in the
 Fortran wrapper is created on the fly from a [[vector4]] Lorentz
 vector.
 
 No destructor is needed as long as all particles are entered into
 vertex containers.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_gen_particle (prt_obj, pdg_id, status) bind(C)
        import
        type(c_ptr), value :: prt_obj
        integer(c_int), value :: pdg_id, status
      end function new_gen_particle
   end interface
 @ %def new_gen_particle
 <<HepMC interface: public>>=
   public :: hepmc_particle_init
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_particle_init (prt, p, pdg, status)
+      type(hepmc_particle_t), intent(out) :: prt
+      type(vector4_t), intent(in) :: p
+      integer, intent(in) :: pdg, status
+    end subroutine hepmc_particle_init
 <<HepMC interface: procedures>>=
-  subroutine hepmc_particle_init (prt, p, pdg, status)
+  module subroutine hepmc_particle_init (prt, p, pdg, status)
     type(hepmc_particle_t), intent(out) :: prt
     type(vector4_t), intent(in) :: p
     integer, intent(in) :: pdg, status
     type(hepmc_four_vector_t) :: pp
     call hepmc_four_vector_init (pp, p)
     prt%obj = new_gen_particle (pp%obj, int (pdg, c_int), int (status, c_int))
     call hepmc_four_vector_final (pp)
   end subroutine hepmc_particle_init
 
 @ %def hepmc_particle_init
 @ Set the particle color flow.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_particle_set_flow (prt_obj, code_index, code) bind(C)
        import
        type(c_ptr), value :: prt_obj
        integer(c_int), value :: code_index, code
      end subroutine gen_particle_set_flow
   end interface
 @ %def gen_particle_set_flow
 @ Set the particle color.  Either from a [[color_t]] object or
 directly from a pair of integers.
 <<HepMC interface: interfaces>>=
   interface hepmc_particle_set_color
      module procedure hepmc_particle_set_color_col
      module procedure hepmc_particle_set_color_int
   end interface hepmc_particle_set_color
 <<HepMC interface: public>>=
   public :: hepmc_particle_set_color
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_particle_set_color_col (prt, col)
+      type(hepmc_particle_t), intent(inout) :: prt
+      type(color_t), intent(in) :: col
+    end subroutine hepmc_particle_set_color_col
+    module subroutine hepmc_particle_set_color_int (prt, col)
+      type(hepmc_particle_t), intent(inout) :: prt
+      integer, dimension(2), intent(in) :: col
+    end subroutine hepmc_particle_set_color_int
 <<HepMC interface: procedures>>=
-  subroutine hepmc_particle_set_color_col (prt, col)
+  module subroutine hepmc_particle_set_color_col (prt, col)
     type(hepmc_particle_t), intent(inout) :: prt
     type(color_t), intent(in) :: col
     integer(c_int) :: c
     c = col%get_col ()
     if (c /= 0)  call gen_particle_set_flow (prt%obj, 1_c_int, c)
     c = col%get_acl ()
     if (c /= 0)  call gen_particle_set_flow (prt%obj, 2_c_int, c)
   end subroutine hepmc_particle_set_color_col
 
-  subroutine hepmc_particle_set_color_int (prt, col)
+  module subroutine hepmc_particle_set_color_int (prt, col)
     type(hepmc_particle_t), intent(inout) :: prt
     integer, dimension(2), intent(in) :: col
     integer(c_int) :: c
     c = col(1)
     if (c /= 0)  call gen_particle_set_flow (prt%obj, 1_c_int, c)
     c = col(2)
     if (c /= 0)  call gen_particle_set_flow (prt%obj, 2_c_int, c)
   end subroutine hepmc_particle_set_color_int
 
 @ %def hepmc_particle_set_color
 @ Set the particle polarization.  For the restrictions on particle
 polarization in HepMC, see above [[hepmc_polarization_init]].
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_particle_set_polarization (prt_obj, pol_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj, pol_obj
      end subroutine gen_particle_set_polarization
   end interface
 @ %def gen_particle_set_polarization
 <<HepMC interface: public>>=
   public :: hepmc_particle_set_polarization
 <<HepMC interface: interfaces>>=
   interface hepmc_particle_set_polarization
      module procedure hepmc_particle_set_polarization_pol
      module procedure hepmc_particle_set_polarization_hel
      module procedure hepmc_particle_set_polarization_int
   end interface
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_particle_set_polarization_pol (prt, pol)
+      type(hepmc_particle_t), intent(inout) :: prt
+      type(polarization_t), intent(in) :: pol
+    end subroutine hepmc_particle_set_polarization_pol
+    module subroutine hepmc_particle_set_polarization_hel (prt, hel)
+      type(hepmc_particle_t), intent(inout) :: prt
+      type(helicity_t), intent(in) :: hel
+    end subroutine hepmc_particle_set_polarization_hel
+    module subroutine hepmc_particle_set_polarization_int (prt, hel)
+      type(hepmc_particle_t), intent(inout) :: prt
+      integer, intent(in) :: hel
+    end subroutine hepmc_particle_set_polarization_int
 <<HepMC interface: procedures>>=
-  subroutine hepmc_particle_set_polarization_pol (prt, pol)
+  module subroutine hepmc_particle_set_polarization_pol (prt, pol)
     type(hepmc_particle_t), intent(inout) :: prt
     type(polarization_t), intent(in) :: pol
     type(hepmc_polarization_t) :: hpol
     call hepmc_polarization_init (hpol, pol)
     if (hpol%polarized)  call gen_particle_set_polarization (prt%obj, hpol%obj)
     call hepmc_polarization_final (hpol)
   end subroutine hepmc_particle_set_polarization_pol
 
-  subroutine hepmc_particle_set_polarization_hel (prt, hel)
+  module subroutine hepmc_particle_set_polarization_hel (prt, hel)
     type(hepmc_particle_t), intent(inout) :: prt
     type(helicity_t), intent(in) :: hel
     type(hepmc_polarization_t) :: hpol
     call hepmc_polarization_init (hpol, hel)
     if (hpol%polarized)  call gen_particle_set_polarization (prt%obj, hpol%obj)
     call hepmc_polarization_final (hpol)
   end subroutine hepmc_particle_set_polarization_hel
 
-  subroutine hepmc_particle_set_polarization_int (prt, hel)
+  module subroutine hepmc_particle_set_polarization_int (prt, hel)
     type(hepmc_particle_t), intent(inout) :: prt
     integer, intent(in) :: hel
     type(hepmc_polarization_t) :: hpol
     call hepmc_polarization_init (hpol, hel)
     if (hpol%polarized)  call gen_particle_set_polarization (prt%obj, hpol%obj)
     call hepmc_polarization_final (hpol)
   end subroutine hepmc_particle_set_polarization_int
 
 @ %def hepmc_particle_set_polarization
 @ Return the HepMC barcode (unique integer ID) of the particle.
 <<HepMC interface: interfaces>>=
   interface
      function gen_particle_barcode (prt_obj) result (barcode) bind(C)
        import
        integer(c_int) :: barcode
        type(c_ptr), value :: prt_obj
      end function gen_particle_barcode
   end interface
 @ %def gen_particle_barcode
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_barcode
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_barcode (prt) result (barcode)
+      integer :: barcode
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_barcode
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_barcode (prt) result (barcode)
+  module function hepmc_particle_get_barcode (prt) result (barcode)
     integer :: barcode
     type(hepmc_particle_t), intent(in) :: prt
     barcode = gen_particle_barcode (prt%obj)
   end function hepmc_particle_get_barcode
 
 @ %def hepmc_particle_get_barcode
 @ Return the four-vector component of the particle object as a [[vector4_t]] Lorentz vector.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function gen_particle_momentum (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function gen_particle_momentum
   end interface
 @ %def gen_particle_momentum
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_momentum
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_momentum (prt) result (p)
+      type(vector4_t) :: p
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_momentum
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_momentum (prt) result (p)
+  module function hepmc_particle_get_momentum (prt) result (p)
     type(vector4_t) :: p
     type(hepmc_particle_t), intent(in) :: prt
     type(hepmc_four_vector_t) :: pp
     call hepmc_four_vector_init (pp, prt)
     call hepmc_four_vector_to_vector4 (pp, p)
     call hepmc_four_vector_final (pp)
   end function hepmc_particle_get_momentum
 
 @ %def hepmc_particle_get_momentum
 @ Return the invariant mass squared of the particle object.  HepMC
 stores the signed invariant mass (no squaring).
 <<HepMC interface: interfaces>>=
   interface
      function gen_particle_generated_mass (prt_obj) result (mass) bind(C)
        import
        real(c_double) :: mass
        type(c_ptr), value :: prt_obj
      end function gen_particle_generated_mass
   end interface
 @ %def gen_particle_generated_mass
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_mass_squared
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_mass_squared (prt) result (m2)
+      real(default) :: m2
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_mass_squared
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_mass_squared (prt) result (m2)
+  module function hepmc_particle_get_mass_squared (prt) result (m2)
     real(default) :: m2
     type(hepmc_particle_t), intent(in) :: prt
     real(default) :: m
     m = gen_particle_generated_mass (prt%obj)
     m2 = sign (m**2, m)
   end function hepmc_particle_get_mass_squared
 
 @ %def hepmc_particle_get_mass_squared
 @ Return the PDG ID:
 <<HepMC interface: interfaces>>=
   interface
      function gen_particle_pdg_id (prt_obj) result (pdg_id) bind(C)
        import
        integer(c_int) :: pdg_id
        type(c_ptr), value :: prt_obj
      end function gen_particle_pdg_id
   end interface
 @ %def gen_particle_pdg_id
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_pdg
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_pdg (prt) result (pdg)
+      integer :: pdg
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_pdg
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_pdg (prt) result (pdg)
+  module function hepmc_particle_get_pdg (prt) result (pdg)
     integer :: pdg
     type(hepmc_particle_t), intent(in) :: prt
     pdg = gen_particle_pdg_id (prt%obj)
   end function hepmc_particle_get_pdg
 
 @ %def hepmc_particle_get_pdg
 @ Return the status code:
 <<HepMC interface: interfaces>>=
   interface
      function gen_particle_status (prt_obj) result (status) bind(C)
        import
        integer(c_int) :: status
        type(c_ptr), value :: prt_obj
      end function gen_particle_status
   end interface
 @ %def gen_particle_status
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_status
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_status (prt) result (status)
+      integer :: status
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_status
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_status (prt) result (status)
+  module function hepmc_particle_get_status (prt) result (status)
     integer :: status
     type(hepmc_particle_t), intent(in) :: prt
     status = gen_particle_status (prt%obj)
   end function hepmc_particle_get_status
 
 @ %def hepmc_particle_get_status
 <<HepMC interface: interfaces>>=
   interface
      function gen_particle_is_beam (prt_obj) result (is_beam) bind(C)
        import
        logical(c_bool) :: is_beam
        type(c_ptr), value :: prt_obj
      end function gen_particle_is_beam
   end interface
 @ %def gen_particle_is_beam
 @ Determine whether a particle is a beam particle.
 <<HepMC interface: public>>=
   public :: hepmc_particle_is_beam
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_is_beam (prt) result (is_beam)
+      logical :: is_beam
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_is_beam
 <<HepMC interface: procedures>>=
-  function hepmc_particle_is_beam (prt) result (is_beam)
+  module function hepmc_particle_is_beam (prt) result (is_beam)
     logical :: is_beam
     type(hepmc_particle_t), intent(in) :: prt
     is_beam = gen_particle_is_beam (prt%obj)
   end function hepmc_particle_is_beam
 
 @ %def hepmc_particle_is_beam
 @ Return the production/decay vertex (as a pointer, no finalization
 necessary).
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function gen_particle_production_vertex (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function gen_particle_production_vertex
   end interface
   interface
      type(c_ptr) function gen_particle_end_vertex (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function gen_particle_end_vertex
   end interface
 @ %def gen_particle_production_vertex gen_particle_end_vertex
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_production_vertex
   public :: hepmc_particle_get_decay_vertex
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_production_vertex (prt) result (v)
+      type(hepmc_vertex_t) :: v
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_production_vertex
+    module function hepmc_particle_get_decay_vertex (prt) result (v)
+      type(hepmc_vertex_t) :: v
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_decay_vertex
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_production_vertex (prt) result (v)
+  module function hepmc_particle_get_production_vertex (prt) result (v)
     type(hepmc_vertex_t) :: v
     type(hepmc_particle_t), intent(in) :: prt
     v%obj = gen_particle_production_vertex (prt%obj)
   end function hepmc_particle_get_production_vertex
 
-  function hepmc_particle_get_decay_vertex (prt) result (v)
+  module function hepmc_particle_get_decay_vertex (prt) result (v)
     type(hepmc_vertex_t) :: v
     type(hepmc_particle_t), intent(in) :: prt
     v%obj = gen_particle_end_vertex (prt%obj)
   end function hepmc_particle_get_decay_vertex
 
 @ %def hepmc_particle_get_production_vertex hepmc_particle_get_decay_vertex
 @ Convenience function: Return the array of parent particles for a
 given HepMC particle.  The contents are HepMC barcodes that still have
 to be mapped to the particle indices.
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_parent_barcodes
   public :: hepmc_particle_get_child_barcodes
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_parent_barcodes &
+         (prt) result (parent_barcode)
+      type(hepmc_particle_t), intent(in) :: prt
+      integer, dimension(:), allocatable :: parent_barcode
+    end function hepmc_particle_get_parent_barcodes
+    module function hepmc_particle_get_child_barcodes &
+         (prt) result (child_barcode)
+      type(hepmc_particle_t), intent(in) :: prt
+      integer, dimension(:), allocatable :: child_barcode
+    end function hepmc_particle_get_child_barcodes
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_parent_barcodes (prt) result (parent_barcode)
+  module function hepmc_particle_get_parent_barcodes &
+       (prt) result (parent_barcode)
     type(hepmc_particle_t), intent(in) :: prt
     integer, dimension(:), allocatable :: parent_barcode
     type(hepmc_vertex_t) :: v
     type(hepmc_vertex_particle_in_iterator_t) :: it
     integer :: i
     v = hepmc_particle_get_production_vertex (prt)
     if (hepmc_vertex_is_valid (v)) then
        allocate (parent_barcode (hepmc_vertex_get_n_in (v)))
        if (size (parent_barcode) /= 0) then
           if (HEPMC2_AVAILABLE) then
              call hepmc_vertex_particle_in_iterator_init (it, v)
              do i = 1, size (parent_barcode)
                 parent_barcode(i) = hepmc_particle_get_barcode &
                      (hepmc_vertex_particle_in_iterator_get (it))
                 call hepmc_vertex_particle_in_iterator_advance (it)
              end do
              call hepmc_vertex_particle_in_iterator_final (it)
           else if (HEPMC3_AVAILABLE) then
              do i = 1, size (parent_barcode)
                 parent_barcode(i) = hepmc_particle_get_barcode &
                      (hepmc_vertex_get_nth_particle_in (v, i))
              end do
           end if
        end if
     else
        allocate (parent_barcode (0))
     end if
   end function hepmc_particle_get_parent_barcodes
 
-  function hepmc_particle_get_child_barcodes (prt) result (child_barcode)
+  module function hepmc_particle_get_child_barcodes &
+       (prt) result (child_barcode)
     type(hepmc_particle_t), intent(in) :: prt
     integer, dimension(:), allocatable :: child_barcode
     type(hepmc_vertex_t) :: v
     type(hepmc_vertex_particle_out_iterator_t) :: it
     integer :: i
     v = hepmc_particle_get_decay_vertex (prt)
     if (hepmc_vertex_is_valid (v)) then
        allocate (child_barcode (hepmc_vertex_get_n_out (v)))
        if (size (child_barcode) /= 0) then
           if (HEPMC2_AVAILABLE) then
              call hepmc_vertex_particle_out_iterator_init (it, v)
              do i = 1, size (child_barcode)
                 child_barcode(i) = hepmc_particle_get_barcode &
                      (hepmc_vertex_particle_out_iterator_get (it))
                 call hepmc_vertex_particle_out_iterator_advance (it)
              end do
              call hepmc_vertex_particle_out_iterator_final (it)
           else if (HEPMC3_AVAILABLE) then
              do i = 1, size (child_barcode)
                 child_barcode(i) = hepmc_particle_get_barcode &
                      (hepmc_vertex_get_nth_particle_out (v, i))
              end do
           end if
        end if
     else
        allocate (child_barcode (0))
     end if
   end function hepmc_particle_get_child_barcodes
 
 @ %def hepmc_particle_get_parent_barcodes hepmc_particle_get_child_barcodes
 @ Return the polarization (assuming that the particle is completely
 polarized).  Note that the generated polarization object needs finalization.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function gen_particle_polarization (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function gen_particle_polarization
   end interface
 @ %def gen_particle_polarization
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_polarization
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_polarization (prt) result (pol)
+      type(hepmc_polarization_t) :: pol
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_polarization
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_polarization (prt) result (pol)
+  module function hepmc_particle_get_polarization (prt) result (pol)
     type(hepmc_polarization_t) :: pol
     type(hepmc_particle_t), intent(in) :: prt
     pol%obj = gen_particle_polarization (prt%obj)
   end function hepmc_particle_get_polarization
 
 @ %def hepmc_particle_get_polarization
 @ Return the particle color as a two-dimensional array (color, anticolor).
 <<HepMC interface: interfaces>>=
   interface
      function gen_particle_flow (prt_obj, code_index) result (code) bind(C)
        import
        integer(c_int) :: code
        type(c_ptr), value :: prt_obj
        integer(c_int), value :: code_index
      end function gen_particle_flow
   end interface
 @ %def gen_particle_flow
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_color
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_color (prt) result (col)
+      integer, dimension(2) :: col
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_color
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_color (prt) result (col)
+  module function hepmc_particle_get_color (prt) result (col)
     integer, dimension(2) :: col
     type(hepmc_particle_t), intent(in) :: prt
     col(1) = gen_particle_flow (prt%obj, 1)
     col(2) = - gen_particle_flow (prt%obj, 2)
   end function hepmc_particle_get_color
 
 @ %def hepmc_particle_get_color
 @
 <<HepMC interface: interfaces>>=
   interface
      function gen_vertex_pos_x (v_obj) result (x) bind(C)
        import
        type(c_ptr), value :: v_obj
        real(c_double) :: x
      end function gen_vertex_pos_x
   end interface
   interface
      function gen_vertex_pos_y (v_obj) result (y) bind(C)
        import
        type(c_ptr), value :: v_obj
        real(c_double) :: y
      end function gen_vertex_pos_y
   end interface
   interface
      function gen_vertex_pos_z (v_obj) result (z) bind(C)
        import
        type(c_ptr), value :: v_obj
        real(c_double) :: z
      end function gen_vertex_pos_z
   end interface
   interface
      function gen_vertex_time (v_obj) result (t) bind(C)
        import
        type(c_ptr), value :: v_obj
        real(c_double) :: t
      end function gen_vertex_time
   end interface
 @
 <<HepMC interface: public>>=
   public :: hepmc_vertex_to_vertex
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_to_vertex (vtx) result (v)
+      type(hepmc_vertex_t), intent(in) :: vtx
+      type(vector4_t) :: v
+    end function hepmc_vertex_to_vertex
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_to_vertex (vtx) result (v)
+  module function hepmc_vertex_to_vertex (vtx) result (v)
     type(hepmc_vertex_t), intent(in) :: vtx
     type(vector4_t) :: v
     real(default) :: t, vx, vy, vz
     if (hepmc_vertex_is_valid (vtx)) then
        t = gen_vertex_time (vtx%obj)
        vx = gen_vertex_pos_x (vtx%obj)
        vy = gen_vertex_pos_y (vtx%obj)
        vz = gen_vertex_pos_z (vtx%obj)
        v = vector4_moving (t, &
             vector3_moving ([vx, vy, vz]))
     end if
   end function hepmc_vertex_to_vertex
 
 @ %def hepmc_vertex_to_vertex
 @
 \subsection{GenVertex}
 Vertices are made of particles (incoming and outgoing).
 <<HepMC interface: public>>=
   public :: hepmc_vertex_t
 <<HepMC interface: types>>=
   type :: hepmc_vertex_t
      private
      type(c_ptr) :: obj
   end type hepmc_vertex_t
 
 @ %def hepmc_vertex_t
 @ Constructor.  Two versions, one plain, one with the position in
 space and time (measured in mm) as argument.  The Fortran version has
 initializer form, and the vertex position is an optional argument.
 
 A destructor is unnecessary as long as all vertices are entered into
 an event container.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_gen_vertex () bind(C)
        import
      end function new_gen_vertex
   end interface
   interface
      type(c_ptr) function new_gen_vertex_pos (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function new_gen_vertex_pos
   end interface
 @ %def new_gen_vertex new_gen_vertex_pos
 <<HepMC interface: public>>=
   public :: hepmc_vertex_init
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_init (v, x)
+      type(hepmc_vertex_t), intent(out) :: v
+      type(vector4_t), intent(in), optional :: x
+    end subroutine hepmc_vertex_init
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_init (v, x)
+  module subroutine hepmc_vertex_init (v, x)
     type(hepmc_vertex_t), intent(out) :: v
     type(vector4_t), intent(in), optional :: x
     type(hepmc_four_vector_t) :: pos
     if (present (x)) then
        call hepmc_four_vector_init (pos, x)
        v%obj = new_gen_vertex_pos (pos%obj)
        call hepmc_four_vector_final (pos)
     else
        v%obj = new_gen_vertex ()
     end if
   end subroutine hepmc_vertex_init
 
 @ %def hepmc_vertex_init
 @ Return true if the vertex pointer is non-null:
 <<HepMC interface: interfaces>>=
   interface
      function gen_vertex_is_valid (v_obj) result (flag) bind(C)
        import
        logical(c_bool) :: flag
        type(c_ptr), value :: v_obj
      end function gen_vertex_is_valid
   end interface
 @ %def gen_vertex_is_valid
 <<HepMC interface: public>>=
   public :: hepmc_vertex_is_valid
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_is_valid (v) result (flag)
+      logical :: flag
+      type(hepmc_vertex_t), intent(in) :: v
+    end function hepmc_vertex_is_valid
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_is_valid (v) result (flag)
+  module function hepmc_vertex_is_valid (v) result (flag)
     logical :: flag
     type(hepmc_vertex_t), intent(in) :: v
     flag = gen_vertex_is_valid (v%obj)
   end function hepmc_vertex_is_valid
 
 @ %def hepmc_vertex_is_valid
 @ Add a particle to a vertex, incoming or outgoing.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_vertex_add_particle_in (v_obj, prt_obj) bind(C)
        import
        type(c_ptr), value :: v_obj, prt_obj
      end subroutine gen_vertex_add_particle_in
   end interface
   interface
      subroutine gen_vertex_add_particle_out (v_obj, prt_obj) bind(C)
        import
        type(c_ptr), value :: v_obj, prt_obj
      end subroutine gen_vertex_add_particle_out
   end interface
 <<HepMC interface: public>>=
   public :: hepmc_vertex_add_particle_in
   public :: hepmc_vertex_add_particle_out
 @ %def gen_vertex_add_particle_in gen_vertex_add_particle_out
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_add_particle_in (v, prt)
+      type(hepmc_vertex_t), intent(inout) :: v
+      type(hepmc_particle_t), intent(in) :: prt
+    end subroutine hepmc_vertex_add_particle_in
+    module subroutine hepmc_vertex_add_particle_out (v, prt)
+      type(hepmc_vertex_t), intent(inout) :: v
+      type(hepmc_particle_t), intent(in) :: prt
+    end subroutine hepmc_vertex_add_particle_out
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_add_particle_in (v, prt)
+  module subroutine hepmc_vertex_add_particle_in (v, prt)
     type(hepmc_vertex_t), intent(inout) :: v
     type(hepmc_particle_t), intent(in) :: prt
     call gen_vertex_add_particle_in (v%obj, prt%obj)
   end subroutine hepmc_vertex_add_particle_in
 
-  subroutine hepmc_vertex_add_particle_out (v, prt)
+  module subroutine hepmc_vertex_add_particle_out (v, prt)
     type(hepmc_vertex_t), intent(inout) :: v
     type(hepmc_particle_t), intent(in) :: prt
     call gen_vertex_add_particle_out (v%obj, prt%obj)
   end subroutine hepmc_vertex_add_particle_out
 
 @ %def hepmc_vertex_add_particle_in hepmc_vertex_add_particle_out
 @ Return the number of incoming/outgoing particles.
 <<HepMC interface: interfaces>>=
   interface
      function gen_vertex_particles_in_size (v_obj) result (size) bind(C)
        import
        integer(c_int) :: size
        type(c_ptr), value :: v_obj
      end function gen_vertex_particles_in_size
   end interface
   interface
      function gen_vertex_particles_out_size (v_obj) result (size) bind(C)
        import
        integer(c_int) :: size
        type(c_ptr), value :: v_obj
      end function gen_vertex_particles_out_size
   end interface
   interface
      function gen_particle_get_n_parents (p_obj) result (size) bind(C)
        import
        integer(c_int) :: size
        type(c_ptr), value :: p_obj
      end function gen_particle_get_n_parents
   end interface
   interface
      function gen_particle_get_n_children (p_obj) result (size) bind(C)
        import
        integer(c_int) :: size
        type(c_ptr), value :: p_obj
      end function gen_particle_get_n_children
   end interface
 @ %def gen_vertex_particles_in_size gen_vertex_particles_out_size
 @ %def gen_particle_get_n_parents get_particle_get_n_children
 <<HepMC interface: public>>=
   public :: hepmc_vertex_get_n_in
   public :: hepmc_vertex_get_n_out
   public :: hepmc_particle_get_parents
   public :: hepmc_particle_get_children
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_get_n_in (v) result (n_in)
+      integer :: n_in
+      type(hepmc_vertex_t), intent(in) :: v
+    end function hepmc_vertex_get_n_in
+    module function hepmc_vertex_get_n_out (v) result (n_out)
+      integer :: n_out
+      type(hepmc_vertex_t), intent(in) :: v
+    end function hepmc_vertex_get_n_out
+    module function hepmc_particle_get_parents (p) result (n_p)
+      integer :: n_p
+      type(hepmc_particle_t), intent(in) :: p
+    end function hepmc_particle_get_parents
+    module function hepmc_particle_get_children (p) result (n_ch)
+      integer :: n_ch
+      type(hepmc_particle_t), intent(in) :: p
+    end function hepmc_particle_get_children
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_get_n_in (v) result (n_in)
+  module function hepmc_vertex_get_n_in (v) result (n_in)
     integer :: n_in
     type(hepmc_vertex_t), intent(in) :: v
     n_in = gen_vertex_particles_in_size (v%obj)
   end function hepmc_vertex_get_n_in
 
-  function hepmc_vertex_get_n_out (v) result (n_out)
+  module function hepmc_vertex_get_n_out (v) result (n_out)
     integer :: n_out
     type(hepmc_vertex_t), intent(in) :: v
     n_out = gen_vertex_particles_out_size (v%obj)
   end function hepmc_vertex_get_n_out
 
-  function hepmc_particle_get_parents (p) result (n_p)
+  module function hepmc_particle_get_parents (p) result (n_p)
     integer :: n_p
     type(hepmc_particle_t), intent(in) :: p
     n_p = gen_particle_get_n_parents (p%obj)
   end function hepmc_particle_get_parents
 
-  function hepmc_particle_get_children (p) result (n_ch)
+  module function hepmc_particle_get_children (p) result (n_ch)
     integer :: n_ch
     type(hepmc_particle_t), intent(in) :: p
     n_ch = gen_particle_get_n_children (p%obj)
   end function hepmc_particle_get_children
 
 @ %def hepmc_vertex_n_in hepmc_vertex_n_out
 @ %def hepmc_particle_get_parents hepmc_particle_get_children
 @ Return the number of parents/children.
 <<HepMC interface: public>>=
   public :: hepmc_particle_get_n_parents
   public :: hepmc_particle_get_n_children
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_particle_get_n_parents (prt) result (n_parents)
+      integer :: n_parents
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_n_parents
+    module function hepmc_particle_get_n_children (prt) result (n_children)
+      integer :: n_children
+      type(hepmc_particle_t), intent(in) :: prt
+    end function hepmc_particle_get_n_children
 <<HepMC interface: procedures>>=
-  function hepmc_particle_get_n_parents (prt) result (n_parents)
+  module function hepmc_particle_get_n_parents (prt) result (n_parents)
     integer :: n_parents
     type(hepmc_particle_t), intent(in) :: prt
     type(hepmc_vertex_t) :: v
     if (HEPMC2_AVAILABLE) then
        v = hepmc_particle_get_production_vertex (prt)
        if (hepmc_vertex_is_valid (v)) then
           n_parents = hepmc_vertex_get_n_in (v)
        else
           n_parents = 0
        end if
     else if (HEPMC3_AVAILABLE) then
        n_parents = hepmc_particle_get_parents (prt)
     end if
   end function hepmc_particle_get_n_parents
 
-  function hepmc_particle_get_n_children (prt) result (n_children)
+  module function hepmc_particle_get_n_children (prt) result (n_children)
     integer :: n_children
     type(hepmc_particle_t), intent(in) :: prt
     type(hepmc_vertex_t) :: v
     if (HEPMC2_AVAILABLE) then
        v = hepmc_particle_get_decay_vertex (prt)
        if (hepmc_vertex_is_valid (v)) then
           n_children = hepmc_vertex_get_n_out (v)
        else
           n_children = 0
        end if
     else if (HEPMC3_AVAILABLE) then
        n_children = hepmc_particle_get_children (prt)
     end if
   end function hepmc_particle_get_n_children
 
 @ %def hepmc_particle_get_n_parents
 @ %def hepmc_particle_get_n_children
 \subsection{Vertex-particle-in iterator}
 This iterator iterates over all incoming particles in an vertex.  We store a
 pointer to the vertex in addition to the iterator.  This allows for
 simple end checking.
 
 The iterator is actually a constant iterator; it can only read.
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_in_iterator_t
 <<HepMC interface: types>>=
   type :: hepmc_vertex_particle_in_iterator_t
      private
      type(c_ptr) :: obj
      type(c_ptr) :: v_obj
   end type hepmc_vertex_particle_in_iterator_t
 
 @ %def hepmc_vertex_particle_in_iterator_t
 @ Constructor.  The iterator is initialized at the first particle in
 the vertex.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function &
           new_vertex_particles_in_const_iterator (v_obj) bind(C)
        import
        type(c_ptr), value :: v_obj
      end function new_vertex_particles_in_const_iterator
   end interface
 @ %def new_vertex_particles_in_const_iterator
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_in_iterator_init
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_in_iterator_init (it, v)
+      type(hepmc_vertex_particle_in_iterator_t), intent(out) :: it
+      type(hepmc_vertex_t), intent(in) :: v
+    end subroutine hepmc_vertex_particle_in_iterator_init
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_in_iterator_init (it, v)
+  module subroutine hepmc_vertex_particle_in_iterator_init (it, v)
     type(hepmc_vertex_particle_in_iterator_t), intent(out) :: it
     type(hepmc_vertex_t), intent(in) :: v
     it%obj = new_vertex_particles_in_const_iterator (v%obj)
     it%v_obj = v%obj
   end subroutine hepmc_vertex_particle_in_iterator_init
 
 @ %def hepmc_vertex_particle_in_iterator_init
 @ Destructor.  Necessary because the iterator is allocated on the
 heap.
 <<HepMC interface: interfaces>>=
   interface
      subroutine vertex_particles_in_const_iterator_delete (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end subroutine vertex_particles_in_const_iterator_delete
   end interface
 @ %def vertex_particles_in_const_iterator_delete
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_in_iterator_final
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_in_iterator_final (it)
+      type(hepmc_vertex_particle_in_iterator_t), intent(inout) :: it
+    end subroutine hepmc_vertex_particle_in_iterator_final
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_in_iterator_final (it)
+  module subroutine hepmc_vertex_particle_in_iterator_final (it)
     type(hepmc_vertex_particle_in_iterator_t), intent(inout) :: it
     call vertex_particles_in_const_iterator_delete (it%obj)
   end subroutine hepmc_vertex_particle_in_iterator_final
 
 @ %def hepmc_vertex_particle_in_iterator_final
 @ Increment
 <<HepMC interface: interfaces>>=
   interface
      subroutine vertex_particles_in_const_iterator_advance (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end subroutine vertex_particles_in_const_iterator_advance
   end interface
 @ %def vertex_particles_in_const_iterator_advance
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_in_iterator_advance
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_in_iterator_advance (it)
+      type(hepmc_vertex_particle_in_iterator_t), intent(inout) :: it
+    end subroutine hepmc_vertex_particle_in_iterator_advance
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_in_iterator_advance (it)
+  module subroutine hepmc_vertex_particle_in_iterator_advance (it)
     type(hepmc_vertex_particle_in_iterator_t), intent(inout) :: it
     call vertex_particles_in_const_iterator_advance (it%obj)
   end subroutine hepmc_vertex_particle_in_iterator_advance
 
 @ %def hepmc_vertex_particle_in_iterator_advance
 @ Reset to the beginning
 <<HepMC interface: interfaces>>=
   interface
      subroutine vertex_particles_in_const_iterator_reset &
           (it_obj, v_obj) bind(C)
        import
        type(c_ptr), value :: it_obj, v_obj
      end subroutine vertex_particles_in_const_iterator_reset
   end interface
 @ %def vertex_particles_in_const_iterator_reset
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_in_iterator_reset
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_in_iterator_reset (it)
+      type(hepmc_vertex_particle_in_iterator_t), intent(inout) :: it
+    end subroutine hepmc_vertex_particle_in_iterator_reset
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_in_iterator_reset (it)
+  module subroutine hepmc_vertex_particle_in_iterator_reset (it)
     type(hepmc_vertex_particle_in_iterator_t), intent(inout) :: it
     call vertex_particles_in_const_iterator_reset (it%obj, it%v_obj)
   end subroutine hepmc_vertex_particle_in_iterator_reset
 
 @ %def hepmc_vertex_particle_in_iterator_reset
 @ Test: return true as long as we are not past the end.
 <<HepMC interface: interfaces>>=
   interface
      function vertex_particles_in_const_iterator_is_valid &
           (it_obj, v_obj) result (flag) bind(C)
        import
        logical(c_bool) :: flag
        type(c_ptr), value :: it_obj, v_obj
      end function vertex_particles_in_const_iterator_is_valid
   end interface
 @ %def vertex_particles_in_const_iterator_is_valid
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_in_iterator_is_valid
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_particle_in_iterator_is_valid &
+         (it) result (flag)
+      logical :: flag
+      type(hepmc_vertex_particle_in_iterator_t), intent(in) :: it
+    end function hepmc_vertex_particle_in_iterator_is_valid
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_particle_in_iterator_is_valid (it) result (flag)
+  module function hepmc_vertex_particle_in_iterator_is_valid &
+       (it) result (flag)
     logical :: flag
     type(hepmc_vertex_particle_in_iterator_t), intent(in) :: it
     flag = vertex_particles_in_const_iterator_is_valid (it%obj, it%v_obj)
   end function hepmc_vertex_particle_in_iterator_is_valid
 
 @ %def hepmc_vertex_particle_in_iterator_is_valid
 @ Return the particle pointed to by the iterator.  (The particle
 object should not be finalized, since it contains merely a pointer to
 the particle which is owned by the vertex.)
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function &
           vertex_particles_in_const_iterator_get (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end function vertex_particles_in_const_iterator_get
   end interface
 @ %def vertex_particles_in_const_iterator_get
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_in_iterator_get
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_particle_in_iterator_get (it) result (prt)
+      type(hepmc_particle_t) :: prt
+      type(hepmc_vertex_particle_in_iterator_t), intent(in) :: it
+    end function hepmc_vertex_particle_in_iterator_get
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_particle_in_iterator_get (it) result (prt)
+  module function hepmc_vertex_particle_in_iterator_get (it) result (prt)
     type(hepmc_particle_t) :: prt
     type(hepmc_vertex_particle_in_iterator_t), intent(in) :: it
     prt%obj = vertex_particles_in_const_iterator_get (it%obj)
   end function hepmc_vertex_particle_in_iterator_get
 
 @ %def hepmc_vertex_particle_in_iterator_get
 @
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function vertex_get_nth_particle_in (vtx_obj, n) bind(C)
        import
        type(c_ptr), value :: vtx_obj
        integer(c_int), value :: n
      end function vertex_get_nth_particle_in
   end interface
   interface
      type(c_ptr) function vertex_get_nth_particle_out (vtx_obj, n) bind(C)
        import
        type(c_ptr), value :: vtx_obj
        integer(c_int), value :: n
      end function vertex_get_nth_particle_out
   end interface
 @ %def vertex_get_nth_particle_in
 <<HepMC interface: public>>=
   public :: hepmc_vertex_get_nth_particle_in
   public :: hepmc_vertex_get_nth_particle_out
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_get_nth_particle_in (vtx, n) result (prt)
+      type(hepmc_particle_t) :: prt
+      type(hepmc_vertex_t), intent(in) :: vtx
+      integer, intent(in) :: n
+    end function hepmc_vertex_get_nth_particle_in
+    module function hepmc_vertex_get_nth_particle_out (vtx, n) result (prt)
+      type(hepmc_particle_t) :: prt
+      type(hepmc_vertex_t), intent(in) :: vtx
+      integer, intent(in) :: n
+    end function hepmc_vertex_get_nth_particle_out
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_get_nth_particle_in (vtx, n) result (prt)
+  module function hepmc_vertex_get_nth_particle_in (vtx, n) result (prt)
     type(hepmc_particle_t) :: prt
     type(hepmc_vertex_t), intent(in) :: vtx
     integer, intent(in) :: n
     integer(c_int) :: nth
     nth = n
     prt%obj = vertex_get_nth_particle_in (vtx%obj, nth)
   end function hepmc_vertex_get_nth_particle_in
 
-  function hepmc_vertex_get_nth_particle_out (vtx, n) result (prt)
+  module function hepmc_vertex_get_nth_particle_out (vtx, n) result (prt)
     type(hepmc_particle_t) :: prt
     type(hepmc_vertex_t), intent(in) :: vtx
     integer, intent(in) :: n
     integer(c_int) :: nth
     nth = n
     prt%obj = vertex_get_nth_particle_out (vtx%obj, nth)
   end function hepmc_vertex_get_nth_particle_out
 
 @ %def hepmc_vertex_get_nth_particle_in
 @ %def hepmc_vertex_get_nth_particle_out
 @
 \subsection{Vertex-particle-out iterator}
 This iterator iterates over all incoming particles in an vertex.  We store a
 pointer to the vertex in addition to the iterator.  This allows for
 simple end checking.
 
 The iterator is actually a constant iterator; it can only read.
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_out_iterator_t
 <<HepMC interface: types>>=
   type :: hepmc_vertex_particle_out_iterator_t
      private
      type(c_ptr) :: obj
      type(c_ptr) :: v_obj
   end type hepmc_vertex_particle_out_iterator_t
 
 @ %def hepmc_vertex_particle_out_iterator_t
 @ Constructor.  The iterator is initialized at the first particle in
 the vertex.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function &
           new_vertex_particles_out_const_iterator (v_obj) bind(C)
        import
        type(c_ptr), value :: v_obj
      end function new_vertex_particles_out_const_iterator
   end interface
 @ %def new_vertex_particles_out_const_iterator
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_out_iterator_init
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_out_iterator_init (it, v)
+      type(hepmc_vertex_particle_out_iterator_t), intent(out) :: it
+      type(hepmc_vertex_t), intent(in) :: v
+    end subroutine hepmc_vertex_particle_out_iterator_init
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_out_iterator_init (it, v)
+  module subroutine hepmc_vertex_particle_out_iterator_init (it, v)
     type(hepmc_vertex_particle_out_iterator_t), intent(out) :: it
     type(hepmc_vertex_t), intent(in) :: v
     it%obj = new_vertex_particles_out_const_iterator (v%obj)
     it%v_obj = v%obj
   end subroutine hepmc_vertex_particle_out_iterator_init
 
 @ %def hepmc_vertex_particle_out_iterator_init
 @ Destructor.  Necessary because the iterator is allocated on the
 heap.
 <<HepMC interface: interfaces>>=
   interface
      subroutine vertex_particles_out_const_iterator_delete (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end subroutine vertex_particles_out_const_iterator_delete
   end interface
 @ %def vertex_particles_out_const_iterator_delete
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_out_iterator_final
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_out_iterator_final (it)
+      type(hepmc_vertex_particle_out_iterator_t), intent(inout) :: it
+    end subroutine hepmc_vertex_particle_out_iterator_final
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_out_iterator_final (it)
+  module subroutine hepmc_vertex_particle_out_iterator_final (it)
     type(hepmc_vertex_particle_out_iterator_t), intent(inout) :: it
     call vertex_particles_out_const_iterator_delete (it%obj)
   end subroutine hepmc_vertex_particle_out_iterator_final
 
 @ %def hepmc_vertex_particle_out_iterator_final
 @ Increment
 <<HepMC interface: interfaces>>=
   interface
      subroutine vertex_particles_out_const_iterator_advance (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end subroutine vertex_particles_out_const_iterator_advance
   end interface
 @ %def vertex_particles_out_const_iterator_advance
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_out_iterator_advance
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_out_iterator_advance (it)
+      type(hepmc_vertex_particle_out_iterator_t), intent(inout) :: it
+    end subroutine hepmc_vertex_particle_out_iterator_advance
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_out_iterator_advance (it)
+  module subroutine hepmc_vertex_particle_out_iterator_advance (it)
     type(hepmc_vertex_particle_out_iterator_t), intent(inout) :: it
     call vertex_particles_out_const_iterator_advance (it%obj)
   end subroutine hepmc_vertex_particle_out_iterator_advance
 
 @ %def hepmc_vertex_particle_out_iterator_advance
 @ Reset to the beginning
 <<HepMC interface: interfaces>>=
   interface
      subroutine vertex_particles_out_const_iterator_reset &
           (it_obj, v_obj) bind(C)
        import
        type(c_ptr), value :: it_obj, v_obj
      end subroutine vertex_particles_out_const_iterator_reset
   end interface
 @ %def vertex_particles_out_const_iterator_reset
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_out_iterator_reset
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_vertex_particle_out_iterator_reset (it)
+      type(hepmc_vertex_particle_out_iterator_t), intent(inout) :: it
+    end subroutine hepmc_vertex_particle_out_iterator_reset
 <<HepMC interface: procedures>>=
-  subroutine hepmc_vertex_particle_out_iterator_reset (it)
+  module subroutine hepmc_vertex_particle_out_iterator_reset (it)
     type(hepmc_vertex_particle_out_iterator_t), intent(inout) :: it
     call vertex_particles_out_const_iterator_reset (it%obj, it%v_obj)
   end subroutine hepmc_vertex_particle_out_iterator_reset
 
 @ %def hepmc_vertex_particle_out_iterator_reset
 @ Test: return true as long as we are not past the end.
 <<HepMC interface: interfaces>>=
   interface
      function vertex_particles_out_const_iterator_is_valid &
           (it_obj, v_obj) result (flag) bind(C)
        import
        logical(c_bool) :: flag
        type(c_ptr), value :: it_obj, v_obj
      end function vertex_particles_out_const_iterator_is_valid
   end interface
 @ %def vertex_particles_out_const_iterator_is_valid
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_out_iterator_is_valid
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_particle_out_iterator_is_valid &
+         (it) result (flag)
+      logical :: flag
+      type(hepmc_vertex_particle_out_iterator_t), intent(in) :: it
+    end function hepmc_vertex_particle_out_iterator_is_valid
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_particle_out_iterator_is_valid (it) result (flag)
+  module function hepmc_vertex_particle_out_iterator_is_valid &
+       (it) result (flag)
     logical :: flag
     type(hepmc_vertex_particle_out_iterator_t), intent(in) :: it
     flag = vertex_particles_out_const_iterator_is_valid (it%obj, it%v_obj)
   end function hepmc_vertex_particle_out_iterator_is_valid
 
 @ %def hepmc_vertex_particle_out_iterator_is_valid
 @ Return the particle pointed to by the iterator.  (The particle
 object should not be finalized, since it contains merely a pointer to
 the particle which is owned by the vertex.)
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function &
           vertex_particles_out_const_iterator_get (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end function vertex_particles_out_const_iterator_get
   end interface
 @ %def vertex_particles_out_const_iterator_get
 <<HepMC interface: public>>=
   public :: hepmc_vertex_particle_out_iterator_get
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_vertex_particle_out_iterator_get (it) result (prt)
+      type(hepmc_particle_t) :: prt
+      type(hepmc_vertex_particle_out_iterator_t), intent(in) :: it
+    end function hepmc_vertex_particle_out_iterator_get
 <<HepMC interface: procedures>>=
-  function hepmc_vertex_particle_out_iterator_get (it) result (prt)
+  module function hepmc_vertex_particle_out_iterator_get (it) result (prt)
     type(hepmc_particle_t) :: prt
     type(hepmc_vertex_particle_out_iterator_t), intent(in) :: it
     prt%obj = vertex_particles_out_const_iterator_get (it%obj)
   end function hepmc_vertex_particle_out_iterator_get
 
 @ %def hepmc_vertex_particle_out_iterator_get
 @
 \subsection{GenEvent}
 The main object of HepMC is a GenEvent.  The object is filled by
 GenVertex objects, which in turn contain GenParticle objects.
 
 This is an extension of the abstract [[event_handle_t]], so we can use the
 according communicator features.
 <<HepMC interface: public>>=
   public :: hepmc_event_t
 <<HepMC interface: types>>=
   type, extends (event_handle_t) :: hepmc_event_t
      private
      type(c_ptr) :: obj = c_null_ptr
   end type hepmc_event_t
 
 @ %def hepmc_event_t
 @ Constructor.  Arguments are process ID (integer) and event ID
 (integer).
 
 The Fortran version has initializer form.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_gen_event (proc_id, event_id) bind(C)
        import
        integer(c_int), value :: proc_id, event_id
      end function new_gen_event
   end interface
 @ %def new_gen_event
 <<HepMC interface: public>>=
   public :: hepmc_event_init
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_init (evt, proc_id, event_id)
+      type(hepmc_event_t), intent(out) :: evt
+      integer, intent(in), optional :: proc_id, event_id
+    end subroutine hepmc_event_init
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_init (evt, proc_id, event_id)
+  module subroutine hepmc_event_init (evt, proc_id, event_id)
     type(hepmc_event_t), intent(out) :: evt
     integer, intent(in), optional :: proc_id, event_id
     integer(c_int) :: pid, eid
     pid = 0;  if (present (proc_id))  pid = proc_id
     eid = 0;  if (present (event_id)) eid = event_id
     evt%obj = new_gen_event (pid, eid)
   end subroutine hepmc_event_init
 
 @ %def hepmc_event_init
 @ Destructor.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_delete (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end subroutine gen_event_delete
   end interface
 @ %def gen_event_delete
 @ Finalize: use the HepMC destructor.  Also nullify the pointer explicitly, to
 be on the safe side.
 <<HepMC interface: public>>=
   public :: hepmc_event_final
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_final (evt)
+      type(hepmc_event_t), intent(inout) :: evt
+    end subroutine hepmc_event_final
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_final (evt)
+  module subroutine hepmc_event_final (evt)
     type(hepmc_event_t), intent(inout) :: evt
     if (c_associated (evt%obj)) then
        call gen_event_delete (evt%obj)
        evt%obj = c_null_ptr
     end if
   end subroutine hepmc_event_final
 
 @ %def hepmc_event_final
 @ Nullify: do not call the destructor, just nullify the C pointer.  There
 should be another pointer associated with the object.
 <<HepMC interface: public>>=
   public :: hepmc_event_nullify
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_nullify (evt)
+      type(hepmc_event_t), intent(inout) :: evt
+    end subroutine hepmc_event_nullify
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_nullify (evt)
+  module subroutine hepmc_event_nullify (evt)
     type(hepmc_event_t), intent(inout) :: evt
     evt%obj = c_null_ptr
   end subroutine hepmc_event_nullify
 
 @ %def hepmc_event_nullify
 @ Return the actual object as a C pointer.  For use in the native C++
 interface only.
 <<HepMC interface: public>>=
   public :: hepmc_event_get_c_ptr
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_c_ptr (evt) result (p)
+      type(hepmc_event_t), intent(in) :: evt
+      type(c_ptr) :: p
+    end function hepmc_event_get_c_ptr
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_c_ptr (evt) result (p)
+  module function hepmc_event_get_c_ptr (evt) result (p)
     type(hepmc_event_t), intent(in) :: evt
     type(c_ptr) :: p
     p = evt%obj
   end function hepmc_event_get_c_ptr
   
 @ %def hepmc_event_get_c_ptr
 @ Screen output.  Printing to file is possible in principle (using a
 C++ output channel), by allowing an argument.  Printing to an open
 Fortran unit is obviously not possible.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_print (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end subroutine gen_event_print
   end interface
 @ %def gen_event_print
 <<HepMC interface: public>>=
   public :: hepmc_event_print
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_print (evt)
+      type(hepmc_event_t), intent(in) :: evt
+    end subroutine hepmc_event_print
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_print (evt)
+  module subroutine hepmc_event_print (evt)
     type(hepmc_event_t), intent(in) :: evt
     call gen_event_print (evt%obj)
   end subroutine hepmc_event_print
 
 @ %def hepmc_event_print
 @ Get the event number.
 <<HepMC interface: interfaces>>=
   interface
      integer(c_int) function gen_event_event_number (evt_obj) bind(C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: evt_obj
      end function gen_event_event_number
   end interface
 @ %def gen_event_event_number
 <<HepMC interface: public>>=
   public :: hepmc_event_get_event_index
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_event_index (evt) result (i_proc)
+      integer :: i_proc
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_event_index
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_event_index (evt) result (i_proc)
+  module function hepmc_event_get_event_index (evt) result (i_proc)
     integer :: i_proc
     type(hepmc_event_t), intent(in) :: evt
     i_proc = gen_event_event_number (evt%obj)
   end function hepmc_event_get_event_index
 
 @ %def hepmc_event_get_event_index
 <<HepMC interface: interfaces>>=
   interface
      integer(c_int) function gen_event_get_n_particles &
           (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function gen_event_get_n_particles
   end interface
     interface
      integer(c_int) function gen_event_get_n_beams &
           (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function gen_event_get_n_beams
   end interface
 @ %def gen_event_get_n_particles gen_event_get_n_beams
 <<HepMC interface: public>>=
   public :: hepmc_event_get_n_particles
   public :: hepmc_event_get_n_beams
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_n_particles (evt) result (n_tot)
+      integer :: n_tot
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_n_particles
+    module function hepmc_event_get_n_beams (evt) result (n_tot)
+      integer :: n_tot
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_n_beams
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_n_particles (evt) result (n_tot)
+  module function hepmc_event_get_n_particles (evt) result (n_tot)
     integer :: n_tot
     type(hepmc_event_t), intent(in) :: evt
     n_tot = gen_event_get_n_particles (evt%obj)
   end function hepmc_event_get_n_particles
 
-  function hepmc_event_get_n_beams (evt) result (n_tot)
+  module function hepmc_event_get_n_beams (evt) result (n_tot)
     integer :: n_tot
     type(hepmc_event_t), intent(in) :: evt
     n_tot = gen_event_get_n_beams (evt%obj)
   end function hepmc_event_get_n_beams
 
 @ %def hepmc_event_get_n_particles
 @ %def hepmc_event_get_n_beams
 @ Set the numeric signal process ID
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_set_signal_process_id (evt_obj, proc_id) bind(C)
        import
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: proc_id
      end subroutine gen_event_set_signal_process_id
   end interface
 @ %def gen_event_set_signal_process_id
 <<HepMC interface: public>>=
   public :: hepmc_event_set_process_id
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_set_process_id (evt, proc)
+      type(hepmc_event_t), intent(in) :: evt
+      integer, intent(in) :: proc
+    end subroutine hepmc_event_set_process_id
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_set_process_id (evt, proc)
+  module subroutine hepmc_event_set_process_id (evt, proc)
     type(hepmc_event_t), intent(in) :: evt
     integer, intent(in) :: proc
     integer(c_int) :: i_proc
     i_proc = proc
     call gen_event_set_signal_process_id (evt%obj, i_proc)
   end subroutine hepmc_event_set_process_id
 
 @ %def hepmc_event_set_process_id
 @ Get the numeric signal process ID
 <<HepMC interface: interfaces>>=
   interface
      integer(c_int) function gen_event_signal_process_id (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function gen_event_signal_process_id
   end interface
 @ %def gen_event_signal_process_id
 <<HepMC interface: public>>=
   public :: hepmc_event_get_process_id
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_process_id (evt) result (i_proc)
+      integer :: i_proc
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_process_id
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_process_id (evt) result (i_proc)
+  module function hepmc_event_get_process_id (evt) result (i_proc)
     integer :: i_proc
     type(hepmc_event_t), intent(in) :: evt
     i_proc = gen_event_signal_process_id (evt%obj)
   end function hepmc_event_get_process_id
 
 @ %def hepmc_event_get_process_id
 @ Set the event energy scale
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_set_event_scale (evt_obj, scale) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: scale
      end subroutine gen_event_set_event_scale
   end interface
 @ %def gen_event_set_event_scale
 <<HepMC interface: public>>=
   public :: hepmc_event_set_scale
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_set_scale (evt, scale)
+      type(hepmc_event_t), intent(in) :: evt
+      real(default), intent(in) :: scale
+    end subroutine hepmc_event_set_scale
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_set_scale (evt, scale)
+  module subroutine hepmc_event_set_scale (evt, scale)
     type(hepmc_event_t), intent(in) :: evt
     real(default), intent(in) :: scale
     real(c_double) :: cscale
     cscale = scale
     call gen_event_set_event_scale (evt%obj, cscale)
   end subroutine hepmc_event_set_scale
 
 @ %def hepmc_event_set_scale
 @ Get the event energy scale
 <<HepMC interface: interfaces>>=
   interface
      real(c_double) function gen_event_event_scale (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function gen_event_event_scale
   end interface
 @ %def gen_event_event_scale
 <<HepMC interface: public>>=
   public :: hepmc_event_get_scale
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_scale (evt) result (scale)
+      real(default) :: scale
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_scale
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_scale (evt) result (scale)
+  module function hepmc_event_get_scale (evt) result (scale)
     real(default) :: scale
     type(hepmc_event_t), intent(in) :: evt
     scale = gen_event_event_scale (evt%obj)
   end function hepmc_event_get_scale
 
 @ %def hepmc_event_set_scale
 @ Set the value of $\alpha_{\rm QCD}$.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_set_alpha_qcd (evt_obj, a) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: a
      end subroutine gen_event_set_alpha_qcd
   end interface
 @ %def gen_event_set_alpha_qcd
 <<HepMC interface: public>>=
   public :: hepmc_event_set_alpha_qcd
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_set_alpha_qcd (evt, alpha)
+      type(hepmc_event_t), intent(in) :: evt
+      real(default), intent(in) :: alpha
+    end subroutine hepmc_event_set_alpha_qcd
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_set_alpha_qcd (evt, alpha)
+  module subroutine hepmc_event_set_alpha_qcd (evt, alpha)
     type(hepmc_event_t), intent(in) :: evt
     real(default), intent(in) :: alpha
     real(c_double) :: a
     a = alpha
     call gen_event_set_alpha_qcd (evt%obj, a)
   end subroutine hepmc_event_set_alpha_qcd
 
 @ %def hepmc_event_set_alpha_qcd
 @ Get the value of $\alpha_{\rm QCD}$.
 <<HepMC interface: interfaces>>=
   interface
      real(c_double) function gen_event_alpha_qcd (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function gen_event_alpha_qcd
   end interface
 @ %def gen_event_get_alpha_qcd
 <<HepMC interface: public>>=
   public :: hepmc_event_get_alpha_qcd
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_alpha_qcd (evt) result (alpha)
+      real(default) :: alpha
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_alpha_qcd
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_alpha_qcd (evt) result (alpha)
+  module function hepmc_event_get_alpha_qcd (evt) result (alpha)
     real(default) :: alpha
     type(hepmc_event_t), intent(in) :: evt
     alpha = gen_event_alpha_qcd (evt%obj)
   end function hepmc_event_get_alpha_qcd
 
 @ %def hepmc_event_get_alpha_qcd
 @ Set the value of $\alpha_{\rm QED}$.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_set_alpha_qed (evt_obj, a) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: a
      end subroutine gen_event_set_alpha_qed
   end interface
 @ %def gen_event_set_alpha_qed
 <<HepMC interface: public>>=
   public :: hepmc_event_set_alpha_qed
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_set_alpha_qed (evt, alpha)
+      type(hepmc_event_t), intent(in) :: evt
+      real(default), intent(in) :: alpha
+    end subroutine hepmc_event_set_alpha_qed
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_set_alpha_qed (evt, alpha)
+  module subroutine hepmc_event_set_alpha_qed (evt, alpha)
     type(hepmc_event_t), intent(in) :: evt
     real(default), intent(in) :: alpha
     real(c_double) :: a
     a = alpha
     call gen_event_set_alpha_qed (evt%obj, a)
   end subroutine hepmc_event_set_alpha_qed
 
 @ %def hepmc_event_set_alpha_qed
 @ Get the value of $\alpha_{\rm QED}$.
 <<HepMC interface: interfaces>>=
   interface
      real(c_double) function gen_event_alpha_qed (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function gen_event_alpha_qed
   end interface
 @ %def gen_event_get_alpha_qed
 <<HepMC interface: public>>=
   public :: hepmc_event_get_alpha_qed
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_alpha_qed (evt) result (alpha)
+      real(default) :: alpha
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_alpha_qed
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_alpha_qed (evt) result (alpha)
+  module function hepmc_event_get_alpha_qed (evt) result (alpha)
     real(default) :: alpha
     type(hepmc_event_t), intent(in) :: evt
     alpha = gen_event_alpha_qed (evt%obj)
   end function hepmc_event_get_alpha_qed
 
 @ %def hepmc_event_get_alpha_qed
 @ Clear a weight value to the end of the weight container.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_clear_weights (evt_obj) bind(C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: evt_obj
      end subroutine gen_event_clear_weights
   end interface
 @ %def gen_event_set_alpha_qed
 @ The HepMC weights are measured in pb.
 <<HepMC interface: parameters>>=
   integer, parameter, public :: HEPMC3_MODE_HEPMC2 = 1
   integer, parameter, public :: HEPMC3_MODE_HEPMC3 = 2
   integer, parameter, public :: HEPMC3_MODE_ROOT = 3
   integer, parameter, public :: HEPMC3_MODE_ROOTTREE = 4
   integer, parameter, public :: HEPMC3_MODE_HEPEVT = 5
 @ %def HEPMC3_MODE_HEPMC2 HEPMC3_MODE_HEPMC3
 @ %def HEPMC3_MODE_ROOT   HEPMC3_MODE_ROOTTREE
 @ %def HEPMC3_MODE_HEPEVT
 @
 <<HepMC interface: public>>=
   public :: hepmc_event_clear_weights
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_clear_weights (evt)
+      type(hepmc_event_t), intent(in) :: evt
+    end subroutine hepmc_event_clear_weights
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_clear_weights (evt)
+  module subroutine hepmc_event_clear_weights (evt)
     type(hepmc_event_t), intent(in) :: evt
     call gen_event_clear_weights (evt%obj)
   end subroutine hepmc_event_clear_weights
 
 @ %def hepmc_event_clear_weights
 @ Add a weight value to the end of the weight container.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_add_weight (evt_obj, w) bind(C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: evt_obj
        real(c_double), value :: w
      end subroutine gen_event_add_weight
   end interface
 @ %def gen_event_add_weight
 @
 <<HepMC interface: public>>=
   public :: hepmc_event_add_weight
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_add_weight (evt, weight, rescale)
+      type(hepmc_event_t), intent(in) :: evt
+      real(default), intent(in) :: weight
+      logical, intent(in) :: rescale
+    end subroutine hepmc_event_add_weight
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_add_weight (evt, weight, rescale)
+  module subroutine hepmc_event_add_weight (evt, weight, rescale)
     type(hepmc_event_t), intent(in) :: evt
     real(default), intent(in) :: weight
     logical, intent(in) :: rescale
     real(c_double) :: w
     if (rescale) then
        w = weight * pb_per_fb
     else
        w = weight
     end if
     call gen_event_add_weight (evt%obj, w)
   end subroutine hepmc_event_add_weight
 
 @ %def hepmc_event_add_weight
 @ Get the size of the weight container (the number of valid elements).
 <<HepMC interface: interfaces>>=
   interface
      integer(c_int) function gen_event_weights_size (evt_obj) bind(C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: evt_obj
      end function gen_event_weights_size
   end interface
 @ %def gen_event_get_weight
 <<HepMC interface: public>>=
   public :: hepmc_event_get_weights_size
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_weights_size (evt) result (n)
+      integer :: n
+      type(hepmc_event_t), intent(in) :: evt
+    end function hepmc_event_get_weights_size
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_weights_size (evt) result (n)
+  module function hepmc_event_get_weights_size (evt) result (n)
     integer :: n
     type(hepmc_event_t), intent(in) :: evt
     n = gen_event_weights_size (evt%obj)
   end function hepmc_event_get_weights_size
 
 @ %def hepmc_event_get_weights_size
 @ Get the value of the weight with index [[i]].  (Count from 1, while C counts
 from zero.)
 <<HepMC interface: interfaces>>=
   interface
      real(c_double) function gen_event_weight (evt_obj, i) bind(C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: i
      end function gen_event_weight
   end interface
 @ %def gen_event_get_weight
 <<HepMC interface: public>>=
   public :: hepmc_event_get_weight
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_weight (evt, index, rescale) result (weight)
+      real(default) :: weight
+      type(hepmc_event_t), intent(in) :: evt
+      integer, intent(in) :: index
+      logical, intent(in) :: rescale
+    end function hepmc_event_get_weight
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_weight (evt, index, rescale) result (weight)
+  module function hepmc_event_get_weight (evt, index, rescale) result (weight)
     real(default) :: weight
     type(hepmc_event_t), intent(in) :: evt
     integer, intent(in) :: index
     logical, intent(in) :: rescale
     integer(c_int) :: i
     i = index - 1
     if (rescale) then
        weight = gen_event_weight (evt%obj, i) / pb_per_fb
     else
        weight = gen_event_weight (evt%obj, i)
     end if
   end function hepmc_event_get_weight
 
 @ %def hepmc_event_get_weight
 @ Add a vertex to the event container.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_add_vertex (evt_obj, v_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
        type(c_ptr), value :: v_obj
      end subroutine gen_event_add_vertex
   end interface
 @ %def gen_event_add_vertex
 <<HepMC interface: public>>=
   public :: hepmc_event_add_vertex
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_add_vertex (evt, v)
+      type(hepmc_event_t), intent(inout) :: evt
+      type(hepmc_vertex_t), intent(in) :: v
+    end subroutine hepmc_event_add_vertex
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_add_vertex (evt, v)
+  module subroutine hepmc_event_add_vertex (evt, v)
     type(hepmc_event_t), intent(inout) :: evt
     type(hepmc_vertex_t), intent(in) :: v
     call gen_event_add_vertex (evt%obj, v%obj)
   end subroutine hepmc_event_add_vertex
 
 @ %def hepmc_event_add_vertex
 @ Mark a particular vertex as the signal process (hard interaction).
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_set_signal_process_vertex (evt_obj, v_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
        type(c_ptr), value :: v_obj
      end subroutine gen_event_set_signal_process_vertex
   end interface
 @ %def gen_event_set_signal_process_vertex
 <<HepMC interface: public>>=
   public :: hepmc_event_set_signal_process_vertex
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_set_signal_process_vertex (evt, v)
+      type(hepmc_event_t), intent(inout) :: evt
+      type(hepmc_vertex_t), intent(in) :: v
+    end subroutine hepmc_event_set_signal_process_vertex
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_set_signal_process_vertex (evt, v)
+  module subroutine hepmc_event_set_signal_process_vertex (evt, v)
     type(hepmc_event_t), intent(inout) :: evt
     type(hepmc_vertex_t), intent(in) :: v
     call gen_event_set_signal_process_vertex (evt%obj, v%obj)
   end subroutine hepmc_event_set_signal_process_vertex
 
 @ %def hepmc_event_set_signal_process_vertex
 @ Return the the signal process (hard interaction).
 <<HepMC interface: interfaces>>=
   interface
      function gen_event_get_signal_process_vertex (evt_obj) &
           result (v_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
        type(c_ptr) :: v_obj
      end function gen_event_get_signal_process_vertex
   end interface
 @ %def gen_event_get_signal_process_vertex
 <<HepMC interface: public>>=
   public :: hepmc_event_get_signal_process_vertex
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_signal_process_vertex (evt) result (v)
+      type(hepmc_event_t), intent(in) :: evt
+      type(hepmc_vertex_t) :: v
+    end function hepmc_event_get_signal_process_vertex
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_signal_process_vertex (evt) result (v)
+  module function hepmc_event_get_signal_process_vertex (evt) result (v)
     type(hepmc_event_t), intent(in) :: evt
     type(hepmc_vertex_t) :: v
     v%obj = gen_event_get_signal_process_vertex (evt%obj)
   end function hepmc_event_get_signal_process_vertex
 
 @ %def hepmc_event_get_signal_process_vertex
 @ Set the beam particles explicitly.
 <<HepMC interface: public>>=
   public :: hepmc_event_set_beam_particles
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_set_beam_particles (evt, prt1, prt2)
+      type(hepmc_event_t), intent(inout) :: evt
+      type(hepmc_particle_t), intent(in) :: prt1, prt2
+      logical(c_bool) :: flag
+    end subroutine hepmc_event_set_beam_particles
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_set_beam_particles (evt, prt1, prt2)
+  module subroutine hepmc_event_set_beam_particles (evt, prt1, prt2)
     type(hepmc_event_t), intent(inout) :: evt
     type(hepmc_particle_t), intent(in) :: prt1, prt2
     logical(c_bool) :: flag
     flag = gen_event_set_beam_particles (evt%obj, prt1%obj, prt2%obj)
   end subroutine hepmc_event_set_beam_particles
 
 @ %def hepmc_event_set_beam_particles
 @ The C function returns a boolean which we do not use.
 <<HepMC interface: interfaces>>=
   interface
      logical(c_bool) function gen_event_set_beam_particles &
           (evt_obj, prt1_obj, prt2_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj, prt1_obj, prt2_obj
      end function gen_event_set_beam_particles
   end interface
 
 @ %def gen_event_set_beam_particles
 @ Set the cross section and error explicitly.  Note that HepMC uses
 pb, while WHIZARD uses fb.
 <<HepMC interface: public>>=
   public :: hepmc_event_set_cross_section
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_set_cross_section (evt, xsec, xsec_err)
+      type(hepmc_event_t), intent(inout) :: evt
+      real(default), intent(in) :: xsec, xsec_err
+    end subroutine hepmc_event_set_cross_section
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_set_cross_section (evt, xsec, xsec_err)
+  module subroutine hepmc_event_set_cross_section (evt, xsec, xsec_err)
     type(hepmc_event_t), intent(inout) :: evt
     real(default), intent(in) :: xsec, xsec_err
     call gen_event_set_cross_section &
          (evt%obj, &
          real (xsec * 1e-3_default, c_double), &
          real (xsec_err * 1e-3_default, c_double))
   end subroutine hepmc_event_set_cross_section
 
 @ %def hepmc_event_set_cross_section
 @ The C function returns a boolean which we do not use.
 <<HepMC interface: interfaces>>=
   interface
      subroutine gen_event_set_cross_section (evt_obj, xs, xs_err) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: xs, xs_err
      end subroutine gen_event_set_cross_section
   end interface
 
 @ %def gen_event_set_cross_section
 @
 \subsection{Event-particle iterator}
 This iterator iterates over all particles in an event.  We store a
 pointer to the event in addition to the iterator.  This allows for
 simple end checking.
 
 The iterator is actually a constant iterator; it can only read.
 <<HepMC interface: public>>=
   public :: hepmc_event_particle_iterator_t
 <<HepMC interface: types>>=
   type :: hepmc_event_particle_iterator_t
      private
      type(c_ptr) :: obj
      type(c_ptr) :: evt_obj
   end type hepmc_event_particle_iterator_t
 
 @ %def hepmc_event_particle_iterator_t
 @ Constructor.  The iterator is initialized at the first particle in
 the event.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_event_particle_const_iterator (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function new_event_particle_const_iterator
   end interface
 @ %def new_event_particle_const_iterator
 <<HepMC interface: public>>=
   public :: hepmc_event_particle_iterator_init
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_particle_iterator_init (it, evt)
+      type(hepmc_event_particle_iterator_t), intent(out) :: it
+      type(hepmc_event_t), intent(in) :: evt
+    end subroutine hepmc_event_particle_iterator_init
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_particle_iterator_init (it, evt)
+  module subroutine hepmc_event_particle_iterator_init (it, evt)
     type(hepmc_event_particle_iterator_t), intent(out) :: it
     type(hepmc_event_t), intent(in) :: evt
     it%obj = new_event_particle_const_iterator (evt%obj)
     it%evt_obj = evt%obj
   end subroutine hepmc_event_particle_iterator_init
 
 @ %def hepmc_event_particle_iterator_init
 @ Destructor.  Necessary because the iterator is allocated on the
 heap.
 <<HepMC interface: interfaces>>=
   interface
      subroutine event_particle_const_iterator_delete (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end subroutine event_particle_const_iterator_delete
   end interface
 @ %def event_particle_const_iterator_delete
 <<HepMC interface: public>>=
   public :: hepmc_event_particle_iterator_final
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_particle_iterator_final (it)
+      type(hepmc_event_particle_iterator_t), intent(inout) :: it
+    end subroutine hepmc_event_particle_iterator_final
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_particle_iterator_final (it)
+  module subroutine hepmc_event_particle_iterator_final (it)
     type(hepmc_event_particle_iterator_t), intent(inout) :: it
     call event_particle_const_iterator_delete (it%obj)
   end subroutine hepmc_event_particle_iterator_final
 
 @ %def hepmc_event_particle_iterator_final
 @ Increment
 <<HepMC interface: interfaces>>=
   interface
      subroutine event_particle_const_iterator_advance (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end subroutine event_particle_const_iterator_advance
   end interface
 @ %def event_particle_const_iterator_advance
 <<HepMC interface: public>>=
   public :: hepmc_event_particle_iterator_advance
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_particle_iterator_advance (it)
+      type(hepmc_event_particle_iterator_t), intent(inout) :: it
+    end subroutine hepmc_event_particle_iterator_advance
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_particle_iterator_advance (it)
+  module subroutine hepmc_event_particle_iterator_advance (it)
     type(hepmc_event_particle_iterator_t), intent(inout) :: it
     call event_particle_const_iterator_advance (it%obj)
   end subroutine hepmc_event_particle_iterator_advance
 
 @ %def hepmc_event_particle_iterator_advance
 @ Reset to the beginning
 <<HepMC interface: interfaces>>=
   interface
      subroutine event_particle_const_iterator_reset (it_obj, evt_obj) bind(C)
        import
        type(c_ptr), value :: it_obj, evt_obj
      end subroutine event_particle_const_iterator_reset
   end interface
 @ %def event_particle_const_iterator_reset
 <<HepMC interface: public>>=
   public :: hepmc_event_particle_iterator_reset
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_event_particle_iterator_reset (it)
+      type(hepmc_event_particle_iterator_t), intent(inout) :: it
+    end subroutine hepmc_event_particle_iterator_reset
 <<HepMC interface: procedures>>=
-  subroutine hepmc_event_particle_iterator_reset (it)
+  module subroutine hepmc_event_particle_iterator_reset (it)
     type(hepmc_event_particle_iterator_t), intent(inout) :: it
     call event_particle_const_iterator_reset (it%obj, it%evt_obj)
   end subroutine hepmc_event_particle_iterator_reset
 
 @ %def hepmc_event_particle_iterator_reset
 @ Test: return true as long as we are not past the end.
 <<HepMC interface: interfaces>>=
   interface
      function event_particle_const_iterator_is_valid &
           (it_obj, evt_obj) result (flag) bind(C)
        import
        logical(c_bool) :: flag
        type(c_ptr), value :: it_obj, evt_obj
      end function event_particle_const_iterator_is_valid
   end interface
 @ %def event_particle_const_iterator_is_valid
 <<HepMC interface: public>>=
   public :: hepmc_event_particle_iterator_is_valid
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_particle_iterator_is_valid (it) result (flag)
+      logical :: flag
+      type(hepmc_event_particle_iterator_t), intent(in) :: it
+    end function hepmc_event_particle_iterator_is_valid
 <<HepMC interface: procedures>>=
-  function hepmc_event_particle_iterator_is_valid (it) result (flag)
+  module function hepmc_event_particle_iterator_is_valid (it) result (flag)
     logical :: flag
     type(hepmc_event_particle_iterator_t), intent(in) :: it
     flag = event_particle_const_iterator_is_valid (it%obj, it%evt_obj)
   end function hepmc_event_particle_iterator_is_valid
 
 @ %def hepmc_event_particle_iterator_is_valid
 @ Return the particle pointed to by the iterator.  (The particle
 object should not be finalized, since it contains merely a pointer to
 the particle which is owned by the vertex.)
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function event_particle_const_iterator_get (it_obj) bind(C)
        import
        type(c_ptr), value :: it_obj
      end function event_particle_const_iterator_get
   end interface
 @ %def event_particle_const_iterator_get
 <<HepMC interface: public>>=
   public :: hepmc_event_particle_iterator_get
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_particle_iterator_get (it) result (prt)
+      type(hepmc_particle_t) :: prt
+      type(hepmc_event_particle_iterator_t), intent(in) :: it
+    end function hepmc_event_particle_iterator_get
 <<HepMC interface: procedures>>=
-  function hepmc_event_particle_iterator_get (it) result (prt)
+  module function hepmc_event_particle_iterator_get (it) result (prt)
     type(hepmc_particle_t) :: prt
     type(hepmc_event_particle_iterator_t), intent(in) :: it
     prt%obj = event_particle_const_iterator_get (it%obj)
   end function hepmc_event_particle_iterator_get
 
 @ %def hepmc_event_particle_iterator_get
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function gen_event_get_nth_particle (evt_obj, n) bind(C)
        import
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: n
      end function gen_event_get_nth_particle
   end interface
     interface
      integer(c_int) function gen_event_get_nth_beam (evt_obj, n) bind(C)
        import
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: n
      end function gen_event_get_nth_beam
   end interface
 @ %def gen_event_get_nth_particle
 @ %def gen_event_get_nth_beam
 <<HepMC interface: public>>=
   public :: hepmc_event_get_nth_particle
   public :: hepmc_event_get_nth_beam
+<<HepMC interface: sub interfaces>>=
+    module function hepmc_event_get_nth_particle (evt, n) result (prt)
+      type(hepmc_particle_t) :: prt
+      type(hepmc_event_t), intent(in) :: evt
+      integer, intent(in) :: n
+    end function hepmc_event_get_nth_particle
+    module function hepmc_event_get_nth_beam (evt, n) result (beam_barcode)
+      integer :: beam_barcode
+      type(hepmc_event_t), intent(in) :: evt
+      integer, intent(in) :: n
+    end function hepmc_event_get_nth_beam
 <<HepMC interface: procedures>>=
-  function hepmc_event_get_nth_particle (evt, n) result (prt)
+  module function hepmc_event_get_nth_particle (evt, n) result (prt)
     type(hepmc_particle_t) :: prt
     type(hepmc_event_t), intent(in) :: evt
     integer, intent(in) :: n
     integer :: n_tot
     integer(c_int) :: nth
     nth = n
     n_tot = gen_event_get_n_particles (evt%obj)
     if (n > n_tot .or. n < 1) then
        prt%obj = c_null_ptr
        call msg_error ("HepMC interface called for wrong particle ID.")
     else
        prt%obj = gen_event_get_nth_particle (evt%obj, nth)
     end if
   end function hepmc_event_get_nth_particle
 
-  function hepmc_event_get_nth_beam (evt, n) result (beam_barcode)
+  module function hepmc_event_get_nth_beam (evt, n) result (beam_barcode)
     integer :: beam_barcode
     type(hepmc_event_t), intent(in) :: evt
     integer, intent(in) :: n
     integer(c_int) :: bc
     bc = gen_event_get_nth_beam (evt%obj, n)
     beam_barcode = bc
   end function hepmc_event_get_nth_beam
 
 @ %def hepmc_event_get_nth_particle
 @ %def hepmc_event_get_nth_beam
 @
 \subsection{I/O streams}
 There is a specific I/O stream type for handling the output of
 GenEvent objects (i.e., Monte Carlo event samples) to file.  Opening
 the file is done by the constructor, closing by the destructor.
 <<HepMC interface: public>>=
   public :: hepmc_iostream_t
 <<HepMC interface: types>>=
   type :: hepmc_iostream_t
      private
      type(c_ptr) :: obj
   end type hepmc_iostream_t
 
 @ %def hepmc_iostream_t
 @ Constructor for an output stream associated to a file.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_io_gen_event_out (hepmc3_mode, filename) bind(C)
        import
        integer(c_int), intent(in) :: hepmc3_mode
        character(c_char), dimension(*), intent(in) :: filename
      end function new_io_gen_event_out
   end interface
 @ %def new_io_gen_event_out
 <<HepMC interface: public>>=
   public :: hepmc_iostream_open_out
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_iostream_open_out (iostream, filename, hepmc3_mode)
+      type(hepmc_iostream_t), intent(out) :: iostream
+      type(string_t), intent(in) :: filename
+      integer, intent(in) :: hepmc3_mode
+    end subroutine hepmc_iostream_open_out
 <<HepMC interface: procedures>>=
-  subroutine hepmc_iostream_open_out (iostream, filename, hepmc3_mode)
+  module subroutine hepmc_iostream_open_out (iostream, filename, hepmc3_mode)
     type(hepmc_iostream_t), intent(out) :: iostream
     type(string_t), intent(in) :: filename
     integer, intent(in) :: hepmc3_mode
     integer(c_int) :: mode
     mode = hepmc3_mode
     iostream%obj = &
          new_io_gen_event_out (mode, char (filename) // c_null_char)
   end subroutine hepmc_iostream_open_out
 
 @ %def hepmc_iostream_open_out
 @ Constructor for an input stream associated to a file.
 <<HepMC interface: interfaces>>=
   interface
      type(c_ptr) function new_io_gen_event_in (hepmc3_mode, filename) bind(C)
        import
        integer(c_int), intent(in) :: hepmc3_mode
        character(c_char), dimension(*), intent(in) :: filename
      end function new_io_gen_event_in
   end interface
 @ %def new_io_gen_event_in
 <<HepMC interface: public>>=
   public :: hepmc_iostream_open_in
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_iostream_open_in (iostream, filename, hepmc3_mode)
+      type(hepmc_iostream_t), intent(out) :: iostream
+      type(string_t), intent(in) :: filename
+      integer, intent(in) :: hepmc3_mode
+    end subroutine hepmc_iostream_open_in
 <<HepMC interface: procedures>>=
-  subroutine hepmc_iostream_open_in (iostream, filename, hepmc3_mode)
+  module subroutine hepmc_iostream_open_in (iostream, filename, hepmc3_mode)
     type(hepmc_iostream_t), intent(out) :: iostream
     type(string_t), intent(in) :: filename
     integer, intent(in) :: hepmc3_mode
     integer(c_int) :: mode
     mode = hepmc3_mode
     iostream%obj = &
             new_io_gen_event_in (mode, char (filename) // c_null_char)
   end subroutine hepmc_iostream_open_in
 
 @ %def hepmc_iostream_open_in
 @ Destructor:
 <<HepMC interface: interfaces>>=
   interface
      subroutine io_gen_event_delete (io_obj) bind(C)
        import
        type(c_ptr), value :: io_obj
      end subroutine io_gen_event_delete
   end interface
 @ %def io_gen_event_delete
 <<HepMC interface: public>>=
   public :: hepmc_iostream_close
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_iostream_close (iostream)
+      type(hepmc_iostream_t), intent(inout) :: iostream
+    end subroutine hepmc_iostream_close
 <<HepMC interface: procedures>>=
-  subroutine hepmc_iostream_close (iostream)
+  module subroutine hepmc_iostream_close (iostream)
     type(hepmc_iostream_t), intent(inout) :: iostream
     call io_gen_event_delete (iostream%obj)
   end subroutine hepmc_iostream_close
 
 @ %def hepmc_iostream_close
 @ Write a single event to the I/O stream.
 <<HepMC interface: interfaces>>=
   interface
      subroutine io_gen_event_write_event (io_obj, evt_obj) bind(C)
        import
        type(c_ptr), value :: io_obj, evt_obj
      end subroutine io_gen_event_write_event
   end interface
   interface
      subroutine io_gen_event_write_event_hepmc2 (io_obj, evt_obj) bind(C)
        import
        type(c_ptr), value :: io_obj, evt_obj
      end subroutine io_gen_event_write_event_hepmc2
   end interface
 @ %def io_gen_event_write_event io_gen_event_write_event_hepmc2
 <<HepMC interface: public>>=
   public :: hepmc_iostream_write_event
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_iostream_write_event (iostream, evt, hepmc3_mode)
+      type(hepmc_iostream_t), intent(inout) :: iostream
+      type(hepmc_event_t), intent(in) :: evt
+      integer, intent(in), optional :: hepmc3_mode
+    end subroutine hepmc_iostream_write_event
 <<HepMC interface: procedures>>=
-  subroutine hepmc_iostream_write_event (iostream, evt, hepmc3_mode)
+  module subroutine hepmc_iostream_write_event (iostream, evt, hepmc3_mode)
     type(hepmc_iostream_t), intent(inout) :: iostream
     type(hepmc_event_t), intent(in) :: evt
     integer, intent(in), optional :: hepmc3_mode
     integer :: mode
     mode = HEPMC3_MODE_HEPMC3
     if (present (hepmc3_mode))  mode = hepmc3_mode
     call io_gen_event_write_event (iostream%obj, evt%obj)
   end subroutine hepmc_iostream_write_event
 
 @ %def hepmc_iostream_write_event
 @ Read a single event from the I/O stream.  Return true if successful.
 <<HepMC interface: interfaces>>=
   interface
      logical(c_bool) function io_gen_event_read_event (io_obj, evt_obj) bind(C)
        import
        type(c_ptr), value :: io_obj, evt_obj
      end function io_gen_event_read_event
   end interface
 @ %def io_gen_event_read_event
 <<HepMC interface: public>>=
   public :: hepmc_iostream_read_event
+<<HepMC interface: sub interfaces>>=
+    module subroutine hepmc_iostream_read_event (iostream, evt, ok)
+      type(hepmc_iostream_t), intent(inout) :: iostream
+      type(hepmc_event_t), intent(inout) :: evt
+      logical, intent(out) :: ok
+    end subroutine hepmc_iostream_read_event
 <<HepMC interface: procedures>>=
-  subroutine hepmc_iostream_read_event (iostream, evt, ok)
+  module subroutine hepmc_iostream_read_event (iostream, evt, ok)
     type(hepmc_iostream_t), intent(inout) :: iostream
     type(hepmc_event_t), intent(inout) :: evt
     logical, intent(out) :: ok
     ok = io_gen_event_read_event (iostream%obj, evt%obj)
   end subroutine hepmc_iostream_read_event
 
 @ %def hepmc_iostream_read_event
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[hepmc_interface_ut.f90]]>>=
 <<File header>>
 
 module hepmc_interface_ut
   use unit_tests
   use system_dependencies, only: HEPMC2_AVAILABLE
   use system_dependencies, only: HEPMC3_AVAILABLE
   use hepmc_interface_uti
 
 <<Standard module head>>
 
 <<HepMC interface: public test>>
 
 contains
 
 <<HepMC interface: test driver>>
 
 end module hepmc_interface_ut
 @ %def hepmc_interface_ut
 @
 <<[[hepmc_interface_uti.f90]]>>=
 <<File header>>
 
 module hepmc_interface_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use lorentz
   use flavors
   use colors
   use polarizations
 
   use hepmc_interface
 
 <<Standard module head>>
 
 <<HepMC interface: test declarations>>
 
 contains
 
 <<HepMC interface: tests>>
 
 end module hepmc_interface_uti
 @ %def hepmc_interface_ut
 @ API: driver for the unit tests below.
 <<HepMC interface: public test>>=
   public :: hepmc_interface_test
 <<HepMC interface: test driver>>=
   subroutine hepmc_interface_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<HepMC interface: execute tests>>
   end subroutine hepmc_interface_test
 
 @  %def hepmc_test
 @
 This test example is an abridged version from the build-from-scratch
 example in the HepMC distribution.  We create two vertices for $p\to
 q$ PDF splitting, then a vertex for a $qq\to W^-g$ hard-interaction
 process, and finally a vertex for $W^-\to qq$ decay.  The setup is for
 LHC kinematics.
 
 Extending the original example, we set color flow for the incoming
 quarks and polarization for the outgoing photon.  For the latter, we
 have to define a particle-data object for the photon, so a flavor
 object can be correctly initialized.
 <<HepMC interface: execute tests>>=
   if (HEPMC2_AVAILABLE) then
      call test (hepmc_interface_1, "hepmc2_interface_1", &
           "check HepMC2 interface", &
           u, results)
   else if (HEPMC3_AVAILABLE) then
      call test (hepmc_interface_1, "hepmc3_interface_1", &
           "check HepMC3 interface", &
           u, results)
   end if
 <<HepMC interface: test declarations>>=
   public :: hepmc_interface_1
 <<HepMC interface: tests>>=
   subroutine hepmc_interface_1 (u)
     use physics_defs, only: VECTOR
     use model_data, only: field_data_t
     integer, intent(in) :: u
     integer :: u_file, iostat
     type(hepmc_event_t) :: evt
     type(hepmc_vertex_t) :: v1, v2, v3, v4
     type(hepmc_particle_t) :: prt1, prt2, prt3, prt4, prt5, prt6, prt7, prt8
     type(hepmc_iostream_t) :: iostream
     type(flavor_t) :: flv
     type(color_t) :: col
     type(polarization_t) :: pol
     type(field_data_t), target :: photon_data
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: HepMC interface"
     write (u, "(A)")  "*   Purpose: test HepMC interface"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialization"
     write (u, "(A)")
 
     ! Initialize a photon flavor object and some polarization
     call photon_data%init (var_str ("PHOTON"), 22)
     call photon_data%set (spin_type=VECTOR)
     call photon_data%freeze ()
     call flv%init (photon_data)
     call pol%init_angles &
          (flv, 0.6_default, 1._default, 0.5_default)
 
     ! Event initialization
     call hepmc_event_init (evt, 20, 1)
 
     write (u, "(A)")  "* p -> q splitting"
     write (u, "(A)")
 
     ! $p\to q$ splittings
     call hepmc_vertex_init (v1)
     call hepmc_event_add_vertex (evt, v1)
     call hepmc_vertex_init (v2)
     call hepmc_event_add_vertex (evt, v2)
     call particle_init (prt1, &
          0._default, 0._default, 7000._default, 7000._default, &
          2212, 3)
     call hepmc_vertex_add_particle_in (v1, prt1)
     call particle_init (prt2, &
          0._default, 0._default,-7000._default, 7000._default, &
          2212, 3)
     call hepmc_vertex_add_particle_in (v2, prt2)
     call particle_init (prt3, &
          .750_default, -1.569_default, 32.191_default, 32.238_default, &
          1, 3)
     call color_init_from_array (col, [501])
     call hepmc_particle_set_color (prt3, col)
     call hepmc_vertex_add_particle_out (v1, prt3)
     call particle_init (prt4, &
          -3.047_default, -19._default, -54.629_default, 57.920_default, &
          -2, 3)
     call color_init_from_array (col, [-501])
     call hepmc_particle_set_color (prt4, col)
     call hepmc_vertex_add_particle_out (v2, prt4)
 
     write (u, "(A)")  "* Hard interaction"
     write (u, "(A)")
 
     ! Hard interaction
     call hepmc_vertex_init (v3)
     call hepmc_event_add_vertex (evt, v3)
     call hepmc_vertex_add_particle_in (v3, prt3)
     call hepmc_vertex_add_particle_in (v3, prt4)
     call particle_init (prt6, &
          -3.813_default, 0.113_default, -1.833_default, 4.233_default, &
          22, 1)
     call hepmc_particle_set_polarization (prt6, pol)
     call hepmc_vertex_add_particle_out (v3, prt6)
     call particle_init (prt5, &
          1.517_default, -20.68_default, -20.605_default, 85.925_default, &
          -24, 3)
     call hepmc_vertex_add_particle_out (v3, prt5)
     call hepmc_event_set_signal_process_vertex (evt, v3)
 
     ! $W^-$ decay
     call vertex_init_pos (v4, &
          0.12_default, -0.3_default, 0.05_default, 0.004_default)
     call hepmc_event_add_vertex (evt, v4)
     call hepmc_vertex_add_particle_in (v4, prt5)
     call particle_init (prt7, &
          -2.445_default, 28.816_default, 6.082_default, 29.552_default, &
          1, 1)
     call hepmc_vertex_add_particle_out (v4, prt7)
     call particle_init (prt8, &
          3.962_default, -49.498_default, -26.687_default, 56.373_default, &
          -2, 1)
     call hepmc_vertex_add_particle_out (v4, prt8)
 
     ! Event output
     call hepmc_event_print (evt)
     write (u, "(A)")  "Writing to file 'hepmc_test.hepmc'"
     write (u, "(A)")
 
     call hepmc_iostream_open_out (iostream , var_str ("hepmc_test.hepmc"), 2)
     call hepmc_iostream_write_event (iostream, evt)
     call hepmc_iostream_close (iostream)
 
     write (u, "(A)")  "Writing completed"
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "hepmc_test.hepmc", &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:14) == "HepMC::Version")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
     write (u, "(A)")
 
     ! Wrapup
     ! call pol%final ()
     call hepmc_event_final (evt)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: hepmc_interface_1"
 
   contains
 
     subroutine vertex_init_pos (v, x, y, z, t)
       type(hepmc_vertex_t), intent(out) :: v
       real(default), intent(in) :: x, y, z, t
       type(vector4_t) :: xx
       xx = vector4_moving (t, vector3_moving ([x, y, z]))
       call hepmc_vertex_init (v, xx)
     end subroutine vertex_init_pos
 
     subroutine particle_init (prt, px, py, pz, E, pdg, status)
       type(hepmc_particle_t), intent(out) :: prt
       real(default), intent(in) :: px, py, pz, E
       integer, intent(in) :: pdg, status
       type(vector4_t) :: p
       p = vector4_moving (E, vector3_moving ([px, py, pz]))
       call hepmc_particle_init (prt, p, pdg, status)
     end subroutine particle_init
 
   end subroutine hepmc_interface_1
 
 @ %def hepmc_interface_1
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{LCIO events}
 This section provides the interface to the LCIO C++ library for handling
 Monte-Carlo events.
 
 Each C++ class of LCIO that we use is mirrored by a Fortran type,
 which contains as its only component the C pointer to the C++ object.
 
 Each C++ method of LCIO that we use has a C wrapper function.  This
 function takes a pointer to the host object as its first argument.
 Further arguments are either C pointers, or in the case of simple
 types (integer, real), interoperable C/Fortran objects.
 
 The C wrapper functions have explicit interfaces in the Fortran
 module.  They are called by Fortran wrapper procedures.  These are
 treated as methods of the corresponding Fortran type.
 <<[[lcio_interface.f90]]>>=
 <<File header>>
 
 module lcio_interface
 
   use, intrinsic :: iso_c_binding !NODEP!
 
 <<Use kinds>>
 <<Use strings>>
-  use constants, only: PI
-  use physics_defs, only: ns_per_mm
-  use diagnostics
   use lorentz
   use flavors
   use colors
   use helicities
   use polarizations
   use event_handles, only: event_handle_t
 
 <<Standard module head>>
 
 <<LCIO interface: public>>
 
 <<LCIO interface: types>>
 
 <<LCIO interface: interfaces>>
 
+  interface
+<<LCIO interface: sub interfaces>>
+  end interface
+
+end module lcio_interface
+@ %def lcio_interface
+@
+<<[[lcio_interface_sub.f90]]>>=
+<<File header>>
+
+submodule (lcio_interface) lcio_interface_s
+
+  use constants, only: PI
+  use physics_defs, only: ns_per_mm
+  use diagnostics
+
+  implicit none
+
 contains
 
 <<LCIO interface: procedures>>
 
-end module lcio_interface
-@ %def lcio_interface
+end submodule lcio_interface_s
+
+@ %def lcio_interface_s
 @
 \subsection{Interface check}
 This function can be called in order to verify that we are using the
 actual LCIO library, and not the dummy version.
 <<LCIO interface: interfaces>>=
   interface
      logical(c_bool) function lcio_available () bind(C)
        import
      end function lcio_available
   end interface
 <<LCIO interface: public>>=
   public :: lcio_is_available
+<<LCIO interface: sub interfaces>>=
+    module function lcio_is_available () result (flag)
+      logical :: flag
+    end function lcio_is_available
 <<LCIO interface: procedures>>=
-  function lcio_is_available () result (flag)
+  module function lcio_is_available () result (flag)
     logical :: flag
     flag = lcio_available ()
   end function lcio_is_available
 
 @ %def lcio_is_available
 @
 \subsection{LCIO Run Header}
 This is a type for the run header of the LCIO file.
 <<LCIO interface: public>>=
   public :: lcio_run_header_t
 <<LCIO interface: types>>=
   type :: lcio_run_header_t
      private
      type(c_ptr) :: obj
   end type lcio_run_header_t
 
 @ %def lcio_run_header_t
 The Fortran version has initializer form.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function new_lcio_run_header (proc_id) bind(C)
        import
        integer(c_int), value :: proc_id
      end function new_lcio_run_header
   end interface
 @ %def new_lcio_run_header
 <<LCIO interface: interfaces>>=
   interface
      subroutine run_header_set_simstring &
           (runhdr_obj, simstring) bind(C)
        import
        type(c_ptr), value :: runhdr_obj
        character(c_char), dimension(*), intent(in) :: simstring
      end subroutine run_header_set_simstring
   end interface
 @ %def run_header_set_simstring
 <<LCIO interface: public>>=
   public :: lcio_run_header_init
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_run_header_init (runhdr, proc_id, run_id)
+      type(lcio_run_header_t), intent(out) :: runhdr
+      integer, intent(in), optional :: proc_id, run_id
+    end subroutine lcio_run_header_init
 <<LCIO interface: procedures>>=
-  subroutine lcio_run_header_init (runhdr, proc_id, run_id)
+  module subroutine lcio_run_header_init (runhdr, proc_id, run_id)
     type(lcio_run_header_t), intent(out) :: runhdr
     integer, intent(in), optional :: proc_id, run_id
     integer(c_int) :: rid
     rid = 0; if (present (run_id))  rid = run_id
     runhdr%obj = new_lcio_run_header (rid)
     call run_header_set_simstring (runhdr%obj, &
          "WHIZARD version:" // "<<Version>>")
   end subroutine lcio_run_header_init
 
 @ %def lcio_run_header_init
 @
 <<LCIO interface: interfaces>>=
   interface
      subroutine write_run_header (lcwrt_obj, runhdr_obj) bind(C)
        import
        type(c_ptr), value :: lcwrt_obj
        type(c_ptr), value :: runhdr_obj
      end subroutine write_run_header
   end interface
 @ %def write_run_header
 <<LCIO interface: public>>=
   public :: lcio_run_header_write
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_run_header_write (wrt, hdr)
+      type(lcio_writer_t), intent(inout) :: wrt
+      type(lcio_run_header_t), intent(inout) :: hdr
+    end subroutine lcio_run_header_write
 <<LCIO interface: procedures>>=
-  subroutine lcio_run_header_write (wrt, hdr)
+  module subroutine lcio_run_header_write (wrt, hdr)
     type(lcio_writer_t), intent(inout) :: wrt
     type(lcio_run_header_t), intent(inout) :: hdr
     call write_run_header (wrt%obj, hdr%obj)
   end subroutine lcio_run_header_write
 
 @ %def lcio_run_header_write
 @
 \subsection{LCIO Event and LC Collection}
 The main object of LCIO is a LCEventImpl.  The object is filled by
 MCParticle objects, which are set as LCCollection.
 <<LCIO interface: public>>=
   public :: lccollection_t
 <<LCIO interface: types>>=
   type :: lccollection_t
      private
      type(c_ptr) :: obj = c_null_ptr
   end type lccollection_t
 
 @ %def lccollection_t
 @ Initializer.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function new_lccollection () bind(C)
        import
      end function new_lccollection
   end interface
 @ %def new_lccollection
 <<LCIO interface: public>>=
   public :: lcio_event_t
 <<LCIO interface: types>>=
   type, extends (event_handle_t) :: lcio_event_t
      private
      type(c_ptr) :: obj = c_null_ptr
      type(lccollection_t) :: lccoll
   end type lcio_event_t
 
 @ %def lcio_event_t
 @ Constructor.  Arguments are process ID (integer) and event ID
 (integer).
 
 The Fortran version has initializer form.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function new_lcio_event (proc_id, event_id, run_id) bind(C)
        import
        integer(c_int), value :: proc_id, event_id, run_id
      end function new_lcio_event
   end interface
 @ %def new_lcio_event
 @
 <<LCIO interface: public>>=
   public :: lcio_event_init
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_init (evt, proc_id, event_id, run_id)
+      type(lcio_event_t), intent(out) :: evt
+      integer, intent(in), optional :: proc_id, event_id, run_id
+    end subroutine lcio_event_init
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_init (evt, proc_id, event_id, run_id)
+  module subroutine lcio_event_init (evt, proc_id, event_id, run_id)
     type(lcio_event_t), intent(out) :: evt
     integer, intent(in), optional :: proc_id, event_id, run_id
     integer(c_int) :: pid, eid, rid
     pid = 0;  if (present (proc_id))  pid = proc_id
     eid = 0;  if (present (event_id)) eid = event_id
     rid = 0;  if (present (run_id))   rid = run_id
     evt%obj = new_lcio_event (pid, eid, rid)
     evt%lccoll%obj = new_lccollection ()
   end subroutine lcio_event_init
 
 @ %def lcio_event_init
 @ Destructor.
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_event_delete (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end subroutine lcio_event_delete
   end interface
 @ %def lcio_event_delete
 @ Show event on screen.
 <<LCIO interface: interfaces>>=
   interface
      subroutine dump_lcio_event (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end subroutine dump_lcio_event
   end interface
 @ %def dump_lcio_event
 <<LCIO interface: public>>=
   public :: show_lcio_event
+<<LCIO interface: sub interfaces>>=
+    module subroutine show_lcio_event (evt)
+      type(lcio_event_t), intent(in) :: evt
+    end subroutine show_lcio_event
 <<LCIO interface: procedures>>=
-  subroutine show_lcio_event (evt)
+  module subroutine show_lcio_event (evt)
     type(lcio_event_t), intent(in) :: evt
     if (c_associated (evt%obj)) then
        call dump_lcio_event (evt%obj)
     else
        call msg_error ("LCIO event is not allocated.")
     end if
   end subroutine show_lcio_event
 
 @ %def show_lcio_event
 @ Put a single event to file.
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_event_to_file (evt_obj, filename) bind(C)
        import
        type(c_ptr), value :: evt_obj
        character(c_char), dimension(*), intent(in) :: filename
      end subroutine lcio_event_to_file
   end interface
 @ %def lcio_event_to_file
 <<LCIO interface: public>>=
   public :: write_lcio_event
+<<LCIO interface: sub interfaces>>=
+    module subroutine write_lcio_event (evt, filename)
+      type(lcio_event_t), intent(in) :: evt
+      type(string_t), intent(in) :: filename
+    end subroutine write_lcio_event
 <<LCIO interface: procedures>>=
-  subroutine write_lcio_event (evt, filename)
+  module subroutine write_lcio_event (evt, filename)
     type(lcio_event_t), intent(in) :: evt
     type(string_t), intent(in) :: filename
     call lcio_event_to_file (evt%obj, char (filename) // c_null_char)
   end subroutine write_lcio_event
 
 @ %def write_lcio_event
 @ Finalize: use the LCIO destructor.  Also nullify the pointer explicitly, to
 be on the safe side.
 <<LCIO interface: public>>=
   public :: lcio_event_final
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_final (evt, delete)
+      type(lcio_event_t), intent(inout) :: evt
+      logical, intent(in) :: delete
+    end subroutine lcio_event_final
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_final (evt, delete)
+  module subroutine lcio_event_final (evt, delete)
     type(lcio_event_t), intent(inout) :: evt
     logical, intent(in) :: delete
     if (c_associated (evt%obj)) then
        if (delete)  call lcio_event_delete (evt%obj)
        evt%obj = c_null_ptr
        evt%lccoll%obj = c_null_ptr
     end if
   end subroutine lcio_event_final
 
 @ %def lcio_event_final
 @ Nullify: do not call the destructor, just nullify the C pointer.  There
 should be another pointer associated with the object.
 <<LCIO interface: public>>=
   public :: lcio_event_nullify
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_nullify (evt)
+      type(lcio_event_t), intent(inout) :: evt
+    end subroutine lcio_event_nullify
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_nullify (evt)
+  module subroutine lcio_event_nullify (evt)
     type(lcio_event_t), intent(inout) :: evt
     evt%obj = c_null_ptr
     evt%lccoll%obj = c_null_ptr
   end subroutine lcio_event_nullify
 
 @ %def lcio_event_nullify
 @ Return the actual object as a C pointer.  For use in the native C++
 interface only.
 <<LCIO interface: public>>=
   public :: lcio_event_get_c_ptr
+<<LCIO interface: sub interfaces>>=
+    module function lcio_event_get_c_ptr (evt) result (p)
+      type(lcio_event_t), intent(in) :: evt
+      type(c_ptr) :: p
+    end function lcio_event_get_c_ptr
 <<LCIO interface: procedures>>=
-  function lcio_event_get_c_ptr (evt) result (p)
+  module function lcio_event_get_c_ptr (evt) result (p)
     type(lcio_event_t), intent(in) :: evt
     type(c_ptr) :: p
     p = evt%obj
   end function lcio_event_get_c_ptr
   
 @ %def lcio_event_get_c_ptr
 @
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_set_weight (evt_obj, weight) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: weight
      end subroutine lcio_set_weight
   end interface
   interface
      subroutine lcio_set_alpha_qcd (evt_obj, alphas) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: alphas
      end subroutine lcio_set_alpha_qcd
   end interface
   interface
      subroutine lcio_set_scale (evt_obj, scale) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: scale
      end subroutine lcio_set_scale
   end interface
   interface
      subroutine lcio_set_sqrts (evt_obj, sqrts) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: sqrts
      end subroutine lcio_set_sqrts
   end interface
   interface
      subroutine lcio_set_xsec (evt_obj, xsec, xsec_err) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: xsec, xsec_err
      end subroutine lcio_set_xsec
   end interface
   interface
      subroutine lcio_set_beam (evt_obj, pdg, beam) bind(C)
        import
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: pdg, beam
      end subroutine lcio_set_beam
   end interface
   interface
      subroutine lcio_set_pol (evt_obj, pol, beam) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: pol
        integer(c_int), value :: beam
      end subroutine lcio_set_pol
   end interface
   interface
      subroutine lcio_set_beam_file (evt_obj, file) bind(C)
        import
        type(c_ptr), value :: evt_obj
        character(len=1, kind=c_char), dimension(*), intent(in) :: file
      end subroutine lcio_set_beam_file
   end interface
   interface
      subroutine lcio_set_process_name (evt_obj, name) bind(C)
        import
        type(c_ptr), value :: evt_obj
        character(len=1, kind=c_char), dimension(*), intent(in) :: name
      end subroutine lcio_set_process_name
   end interface
   interface
      subroutine lcio_set_sqme (evt_obj, sqme) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: sqme
      end subroutine lcio_set_sqme
   end interface
   interface
      subroutine lcio_set_alt_sqme (evt_obj, sqme, index) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: sqme
        integer(c_int), value :: index
      end subroutine lcio_set_alt_sqme
   end interface
   interface
      subroutine lcio_set_alt_weight (evt_obj, weight, index) bind(C)
        import
        type(c_ptr), value :: evt_obj
        real(c_double), value :: weight
        integer(c_int), value :: index
      end subroutine lcio_set_alt_weight
   end interface
 @ %def lcio_set_weight lcio_set_alpha_qcd lcio_set_scale lcio_set_sqrts
 @ %def lcio_set_xsec lcio_set_beam lcio_set_pol
 @ %def lcio_set_beam_file lcio_set_process_name
 @ %def lcio_set_sqme lcio_set_alt_sqme lcio_set_alt_weight
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_weight
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_weight (evt, weight)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: weight
+    end subroutine lcio_event_set_weight
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_weight (evt, weight)
+  module subroutine lcio_event_set_weight (evt, weight)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: weight
     call lcio_set_weight (evt%obj, real (weight, c_double))
   end subroutine lcio_event_set_weight
 
 @ %def lcio_event_set_weight
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_alpha_qcd
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_alpha_qcd (evt, alphas)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: alphas
+    end subroutine lcio_event_set_alpha_qcd
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_alpha_qcd (evt, alphas)
+  module subroutine lcio_event_set_alpha_qcd (evt, alphas)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: alphas
     call lcio_set_alpha_qcd (evt%obj, real (alphas, c_double))
   end subroutine lcio_event_set_alpha_qcd
 
 @ %def lcio_event_set_alpha_qcd
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_scale
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_scale (evt, scale)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: scale
+    end subroutine lcio_event_set_scale
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_scale (evt, scale)
+  module subroutine lcio_event_set_scale (evt, scale)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: scale
     call lcio_set_scale (evt%obj, real (scale, c_double))
   end subroutine lcio_event_set_scale
 
 @ %def lcio_event_set_scale
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_sqrts
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_sqrts (evt, sqrts)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: sqrts
+    end subroutine lcio_event_set_sqrts
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_sqrts (evt, sqrts)
+  module subroutine lcio_event_set_sqrts (evt, sqrts)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: sqrts
     call lcio_set_sqrts (evt%obj, real (sqrts, c_double))
   end subroutine lcio_event_set_sqrts
 
 @ %def lcio_event_set_sqrts
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_xsec
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_xsec (evt, xsec, xsec_err)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: xsec, xsec_err
+    end subroutine lcio_event_set_xsec
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_xsec (evt, xsec, xsec_err)
+  module subroutine lcio_event_set_xsec (evt, xsec, xsec_err)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: xsec, xsec_err
     call lcio_set_xsec (evt%obj, &
          real (xsec, c_double), real (xsec_err, c_double))
   end subroutine lcio_event_set_xsec
 
 @ %def lcio_event_set_xsec
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_beam
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_beam (evt, pdg, beam)
+      type(lcio_event_t), intent(inout) :: evt
+      integer, intent(in) :: pdg, beam
+    end subroutine lcio_event_set_beam
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_beam (evt, pdg, beam)
+  module subroutine lcio_event_set_beam (evt, pdg, beam)
     type(lcio_event_t), intent(inout) :: evt
     integer, intent(in) :: pdg, beam
     call lcio_set_beam (evt%obj, &
          int (pdg, c_int), int (beam, c_int))
   end subroutine lcio_event_set_beam
 
 @ %def lcio_event_set_beam
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_polarization
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_polarization (evt, pol, beam)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: pol
+      integer, intent(in) :: beam
+    end subroutine lcio_event_set_polarization
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_polarization (evt, pol, beam)
+  module subroutine lcio_event_set_polarization (evt, pol, beam)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: pol
     integer, intent(in) :: beam
     call lcio_set_pol (evt%obj, real (pol, c_double), &
          int (beam, c_int))
   end subroutine lcio_event_set_polarization
 
 @ %def lcio_event_set_polarization
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_beam_file
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_beam_file (evt, file)
+      type(lcio_event_t), intent(inout) :: evt
+      type(string_t), intent(in) :: file
+    end subroutine lcio_event_set_beam_file
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_beam_file (evt, file)
+  module subroutine lcio_event_set_beam_file (evt, file)
     type(lcio_event_t), intent(inout) :: evt
     type(string_t), intent(in) :: file
     call lcio_set_beam_file (evt%obj, &
          char (file) // c_null_char)
   end subroutine lcio_event_set_beam_file
 
 @ %def lcio_event_set_beam_file
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_process_name
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_process_name (evt, name)
+      type(lcio_event_t), intent(inout) :: evt
+      type(string_t), intent(in) :: name
+    end subroutine lcio_event_set_process_name
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_process_name (evt, name)
+  module subroutine lcio_event_set_process_name (evt, name)
     type(lcio_event_t), intent(inout) :: evt
     type(string_t), intent(in) :: name
     call lcio_set_process_name (evt%obj, &
          char (name) // c_null_char)
   end subroutine lcio_event_set_process_name
 
 @ %def lcio_event_set_process_name
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_alt_sqme
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_alt_sqme (evt, sqme, index)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: sqme
+      integer, intent(in) :: index
+    end subroutine lcio_event_set_alt_sqme
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_alt_sqme (evt, sqme, index)
+  module subroutine lcio_event_set_alt_sqme (evt, sqme, index)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: sqme
     integer, intent(in) :: index
     call lcio_set_alt_sqme (evt%obj, real (sqme, c_double), &
          int (index, c_int))
   end subroutine lcio_event_set_alt_sqme
 
 @ %def lcio_event_set_alt_sqme
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_sqme
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_sqme (evt, sqme)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: sqme
+    end subroutine lcio_event_set_sqme
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_sqme (evt, sqme)
+  module subroutine lcio_event_set_sqme (evt, sqme)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: sqme
     call lcio_set_sqme (evt%obj, real (sqme, c_double))
   end subroutine lcio_event_set_sqme
 
 @ %def lcio_event_set_sqme
 @
 <<LCIO interface: public>>=
   public :: lcio_event_set_alt_weight
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_set_alt_weight (evt, weight, index)
+      type(lcio_event_t), intent(inout) :: evt
+      real(default), intent(in) :: weight
+      integer, intent(in) :: index
+    end subroutine lcio_event_set_alt_weight
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_set_alt_weight (evt, weight, index)
+  module subroutine lcio_event_set_alt_weight (evt, weight, index)
     type(lcio_event_t), intent(inout) :: evt
     real(default), intent(in) :: weight
     integer, intent(in) :: index
     call lcio_set_alt_weight (evt%obj, real (weight, c_double), &
          int (index, c_int))
   end subroutine lcio_event_set_alt_weight
 
 @ %def lcio_event_set_alt_weight
 @
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_event_add_collection &
           (evt_obj, lccoll_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj, lccoll_obj
      end subroutine lcio_event_add_collection
   end interface
 @ %def lcio_event_add_collection
 <<LCIO interface: public>>=
   public :: lcio_event_add_coll
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_add_coll (evt)
+      type(lcio_event_t), intent(inout) :: evt
+    end subroutine lcio_event_add_coll
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_add_coll (evt)
+  module subroutine lcio_event_add_coll (evt)
     type(lcio_event_t), intent(inout) :: evt
     call lcio_event_add_collection (evt%obj, &
          evt%lccoll%obj)
   end subroutine lcio_event_add_coll
 
 @ %def lcio_event_add_coll
 @
 \subsection{LCIO Particle}
 Particle objects have the obvious meaning.
 <<LCIO interface: public>>=
   public :: lcio_particle_t
 <<LCIO interface: types>>=
   type :: lcio_particle_t
      private
      type(c_ptr) :: obj
   end type lcio_particle_t
 
 @ %def lcio_particle_t
 @ Constructor.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function new_lcio_particle &
           (px, py, pz, pdg_id, mass, charge, status) bind(C)
        import
        integer(c_int), value :: pdg_id, status
        real(c_double), value :: px, py, pz, mass, charge
      end function new_lcio_particle
   end interface
 @ %def new_lcio_particle
 @
 <<LCIO interface: interfaces>>=
   interface
      subroutine add_particle_to_collection &
           (prt_obj, lccoll_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj, lccoll_obj
      end subroutine add_particle_to_collection
   end interface
 @ %def add_particle_to_collection
 <<LCIO interface: public>>=
   public :: lcio_particle_add_to_evt_coll
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_add_to_evt_coll &
+         (lprt, evt)
+      type(lcio_particle_t), intent(in) :: lprt
+      type(lcio_event_t), intent(inout) :: evt
+    end subroutine lcio_particle_add_to_evt_coll
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_add_to_evt_coll &
+  module subroutine lcio_particle_add_to_evt_coll &
        (lprt, evt)
     type(lcio_particle_t), intent(in) :: lprt
     type(lcio_event_t), intent(inout) :: evt
     call add_particle_to_collection (lprt%obj, evt%lccoll%obj)
   end subroutine lcio_particle_add_to_evt_coll
 
 @ %def lcio_particle_to_collection
 @
 <<LCIO interface: public>>=
   public :: lcio_particle_init
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_init (prt, p, pdg, charge, status)
+      type(lcio_particle_t), intent(out) :: prt
+      type(vector4_t), intent(in) :: p
+      real(default), intent(in) :: charge
+      integer, intent(in) :: pdg, status
+    end subroutine lcio_particle_init
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_init (prt, p, pdg, charge, status)
+  module subroutine lcio_particle_init (prt, p, pdg, charge, status)
     type(lcio_particle_t), intent(out) :: prt
     type(vector4_t), intent(in) :: p
     real(default), intent(in) :: charge
     real(default) :: mass
     real(default) :: px, py, pz
     integer, intent(in) :: pdg, status
     px = vector4_get_component (p, 1)
     py = vector4_get_component (p, 2)
     pz = vector4_get_component (p, 3)
     mass = p**1
     prt%obj = new_lcio_particle (real (px, c_double), real (py, c_double), &
          real (pz, c_double), int (pdg, c_int), &
          real (mass, c_double), real (charge, c_double), int (status, c_int))
   end subroutine lcio_particle_init
 
 @ %def lcio_particle_init
 @ Set the particle color flow.
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_set_color_flow (prt_obj, col1, col2) bind(C)
        import
        type(c_ptr), value :: prt_obj
        integer(c_int), value :: col1, col2
      end subroutine lcio_set_color_flow
   end interface
 @ %def lcio_set_color_flow
 @ Set the particle color.  Either from a [[color_t]] object or
 directly from a pair of integers.
 <<LCIO interface: interfaces>>=
   interface lcio_particle_set_color
      module procedure lcio_particle_set_color_col
      module procedure lcio_particle_set_color_int
   end interface lcio_particle_set_color
 <<LCIO interface: public>>=
   public :: lcio_particle_set_color
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_set_color_col (prt, col)
+      type(lcio_particle_t), intent(inout) :: prt
+      type(color_t), intent(in) :: col
+    end subroutine lcio_particle_set_color_col
+    module subroutine lcio_particle_set_color_int (prt, col)
+      type(lcio_particle_t), intent(inout) :: prt
+      integer, dimension(2), intent(in) :: col
+    end subroutine lcio_particle_set_color_int
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_set_color_col (prt, col)
+  module subroutine lcio_particle_set_color_col (prt, col)
     type(lcio_particle_t), intent(inout) :: prt
     type(color_t), intent(in) :: col
     integer(c_int), dimension(2) :: c
     c(1) = col%get_col ()
     c(2) = col%get_acl ()
     if (c(1) /= 0 .or. c(2) /= 0)  then
        call lcio_set_color_flow (prt%obj, c(1), c(2))
     end  if
   end subroutine lcio_particle_set_color_col
 
-  subroutine lcio_particle_set_color_int (prt, col)
+  module subroutine lcio_particle_set_color_int (prt, col)
     type(lcio_particle_t), intent(inout) :: prt
     integer, dimension(2), intent(in) :: col
     integer(c_int), dimension(2) :: c
     c = col
     if (c(1) /= 0 .or. c(2) /= 0) then
        call lcio_set_color_flow (prt%obj, c(1), c(2))
     end if
   end subroutine lcio_particle_set_color_int
 
 @ %def lcio_particle_set_color
 @ Return the particle color as a two-dimensional array (color, anticolor).
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_particle_flow (prt_obj, col_index) bind(C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: prt_obj
        integer(c_int), value :: col_index
      end function lcio_particle_flow
   end interface
 @ %def lcio_particle_flow
 <<LCIO interface: public>>=
   public :: lcio_particle_get_flow
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_flow (prt) result (col)
+      integer, dimension(2) :: col
+      type(lcio_particle_t), intent(in) :: prt
+    end function lcio_particle_get_flow
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_flow (prt) result (col)
+  module function lcio_particle_get_flow (prt) result (col)
     integer, dimension(2) :: col
     type(lcio_particle_t), intent(in) :: prt
     col(1) = lcio_particle_flow (prt%obj, 0_c_int)
     col(2) = - lcio_particle_flow (prt%obj, 1_c_int)
   end function lcio_particle_get_flow
 
 @ %def lcio_particle_get_flow
 @ Return the four-momentum of a LCIO particle.
 <<LCIO interface: interfaces>>=
   interface
      real(c_double) function lcio_three_momentum (prt_obj, p_index) bind(C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: prt_obj
        integer(c_int), value :: p_index
      end function lcio_three_momentum
   end interface
 @ %def lcio_three_momentum
 <<LCIO interface: interfaces>>=
   interface
      real(c_double) function lcio_energy (prt_obj) bind(C)
        import
        type(c_ptr), intent(in), value :: prt_obj
      end function lcio_energy
   end interface
 @ %def lcio_energy
 <<LCIO interface: public>>=
   public :: lcio_particle_get_momentum
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_momentum (prt) result (p)
+      type(vector4_t) :: p
+      type(lcio_particle_t), intent(in) :: prt
+    end function lcio_particle_get_momentum
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_momentum (prt) result (p)
+  module function lcio_particle_get_momentum (prt) result (p)
     type(vector4_t) :: p
     type(lcio_particle_t), intent(in) :: prt
     real(default) :: E, px, py, pz
     E = lcio_energy (prt%obj)
     px = lcio_three_momentum (prt%obj, 0_c_int)
     py = lcio_three_momentum (prt%obj, 1_c_int)
     pz = lcio_three_momentum (prt%obj, 2_c_int)
     p = vector4_moving ( E, vector3_moving ([ px, py, pz ]))
   end function lcio_particle_get_momentum
 
 @ %def lcio_particle_get_momentum
 @ Return the invariant mass squared of the particle object.  LCIO
 stores the signed invariant mass (no squaring).
 <<LCIO interface: interfaces>>=
   interface
      function lcio_mass (prt_obj) result (mass) bind(C)
        import
        real(c_double) :: mass
        type(c_ptr), value :: prt_obj
      end function lcio_mass
   end interface
 @ %def lcio_mass
 <<LCIO interface: public>>=
   public :: lcio_particle_get_mass_squared
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_mass_squared (prt) result (m2)
+      real(default) :: m2
+      type(lcio_particle_t), intent(in) :: prt
+    end function lcio_particle_get_mass_squared
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_mass_squared (prt) result (m2)
+  module function lcio_particle_get_mass_squared (prt) result (m2)
     real(default) :: m2
     type(lcio_particle_t), intent(in) :: prt
     real(default) :: m
     m = lcio_mass (prt%obj)
     m2 = sign (m**2, m)
   end function lcio_particle_get_mass_squared
 
 @ %def lcio_particle_get_mass_squared
 @ Return vertex and production time of a LCIO particle.
 <<LCIO interface: interfaces>>=
   interface
      real(c_double) function lcio_vtx_x (prt) bind(C)
        import
        type(c_ptr), value :: prt
      end function lcio_vtx_x
   end interface
   interface
      real(c_double) function lcio_vtx_y (prt) bind(C)
        import
        type(c_ptr), value :: prt
      end function lcio_vtx_y
   end interface
   interface
      real(c_double) function lcio_vtx_z (prt) bind(C)
        import
        type(c_ptr), value :: prt
      end function lcio_vtx_z
   end interface
   interface
      real(c_float) function lcio_prt_time (prt) bind(C)
        import
        type(c_ptr), value :: prt
      end function lcio_prt_time
   end interface
 @
 @
 (Decay) times in LCIO are in nanoseconds, so they need to get
 converted to mm for the internal format.
 <<LCIO interface: public>>=
   public :: lcio_particle_get_vertex
   public :: lcio_particle_get_time
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_vertex (prt) result (vtx)
+      type(vector3_t) :: vtx
+      type(lcio_particle_t), intent(in) :: prt
+    end function lcio_particle_get_vertex
+    module function lcio_particle_get_time (prt) result (time)
+      real(default) :: time
+      type(lcio_particle_t), intent(in) :: prt
+    end function lcio_particle_get_time
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_vertex (prt) result (vtx)
+  module function lcio_particle_get_vertex (prt) result (vtx)
     type(vector3_t) :: vtx
     type(lcio_particle_t), intent(in) :: prt
     real(default) :: vx, vy, vz
     vx = lcio_vtx_x (prt%obj)
     vy = lcio_vtx_y (prt%obj)
     vz = lcio_vtx_z (prt%obj)
     vtx = vector3_moving ([vx, vy, vz])
   end function lcio_particle_get_vertex
 
-  function lcio_particle_get_time (prt) result (time)
+  module function lcio_particle_get_time (prt) result (time)
     real(default) :: time
     type(lcio_particle_t), intent(in) :: prt
     time = lcio_prt_time (prt%obj)
     time = time / ns_per_mm
   end function lcio_particle_get_time
 
 @ %def lcio_particle_get_vertex lcio_particle_get_time
 @
 \subsection{Polarization}
 For polarization there is a three-component float entry foreseen in the LCIO
 format. Completely generic density matrices can in principle be attached to
 events as float vectors added to [[LCCollection]] of the [[LCEvent]]. This is
 not yet implemented currently. Here, we restrict ourselves to the same
 implementation as in HepMC format: we use two entries as the polarization
 angles, while the first entry gives the degree of polarization (something
 not specified in the HepMC format).
 \emph{For massive vector bosons, we arbitrarily choose the convention
   that the longitudinal (zero) helicity state is mapped to the theta
   angle $\pi/2$.  This works under the condition that helicity is
   projected onto one of the basis states.}
 
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_particle_set_spin (prt_obj, s1, s2, s3) bind(C)
        import
        type(c_ptr), value :: prt_obj
        real(c_double), value :: s1, s2, s3
      end subroutine lcio_particle_set_spin
   end interface
 @ %def lcio_particle_set_spin
 @
 <<LCIO interface: public>>=
   public :: lcio_polarization_init
 <<LCIO interface: interfaces>>=
   interface lcio_polarization_init
      module procedure lcio_polarization_init_pol
      module procedure lcio_polarization_init_hel
      module procedure lcio_polarization_init_int
   end interface
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_polarization_init_pol (prt, pol)
+      type(lcio_particle_t), intent(inout) :: prt
+      type(polarization_t), intent(in) :: pol
+    end subroutine lcio_polarization_init_pol
+    module subroutine lcio_polarization_init_hel (prt, hel)
+      type(lcio_particle_t), intent(inout) :: prt
+      type(helicity_t), intent(in) :: hel
+    end subroutine lcio_polarization_init_hel
+    module subroutine lcio_polarization_init_int (prt, hel)
+      type(lcio_particle_t), intent(inout) :: prt
+      integer, intent(in) :: hel
+    end subroutine lcio_polarization_init_int
 <<LCIO interface: procedures>>=
-  subroutine lcio_polarization_init_pol (prt, pol)
+  module subroutine lcio_polarization_init_pol (prt, pol)
     type(lcio_particle_t), intent(inout) :: prt
     type(polarization_t), intent(in) :: pol
     real(default) :: r, theta, phi
     if (pol%is_polarized ()) then
        call pol%to_angles (r, theta, phi)
        call lcio_particle_set_spin (prt%obj, &
             real(r, c_double), real (theta, c_double), real (phi, c_double))
     end if
   end subroutine lcio_polarization_init_pol
 
-  subroutine lcio_polarization_init_hel (prt, hel)
+  module subroutine lcio_polarization_init_hel (prt, hel)
     type(lcio_particle_t), intent(inout) :: prt
     type(helicity_t), intent(in) :: hel
     integer, dimension(2) :: h
     if (hel%is_defined ()) then
        h = hel%to_pair ()
        select case (h(1))
        case (1:)
           call lcio_particle_set_spin (prt%obj, 1._c_double, &
                0._c_double, 0._c_double)
        case (:-1)
           call lcio_particle_set_spin (prt%obj, 1._c_double, &
                real (pi, c_double), 0._c_double)
        case (0)
           call lcio_particle_set_spin (prt%obj, 1._c_double, &
                real (pi/2, c_double), 0._c_double)
        end select
     end if
   end subroutine lcio_polarization_init_hel
 
-  subroutine lcio_polarization_init_int (prt, hel)
+  module subroutine lcio_polarization_init_int (prt, hel)
     type(lcio_particle_t), intent(inout) :: prt
     integer, intent(in) :: hel
     call lcio_particle_set_spin (prt%obj, 0._c_double, &
          0._c_double, real (hel, c_double))
   end subroutine lcio_polarization_init_int
 
 @ %def lcio_polarization_init
 @ Recover polarization from LCIO particle (with the
 abovementioned deficiencies).
 <<LCIO interface: interfaces>>=
   interface
      function lcio_polarization_degree (prt_obj) result (degree) bind(C)
        import
        real(c_double) :: degree
        type(c_ptr), value :: prt_obj
      end function lcio_polarization_degree
   end interface
   interface
      function lcio_polarization_theta (prt_obj) result (theta) bind(C)
        import
        real(c_double) :: theta
        type(c_ptr), value :: prt_obj
      end function lcio_polarization_theta
   end interface
   interface
      function lcio_polarization_phi (prt_obj) result (phi) bind(C)
        import
        real(c_double) :: phi
        type(c_ptr), value :: prt_obj
      end function lcio_polarization_phi
   end interface
 @ %def lcio_polarization_degree lcio_polarization_theta lcio_polarization_phi
 <<LCIO interface: public>>=
   public :: lcio_particle_to_pol
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_to_pol (prt, flv, pol)
+      type(lcio_particle_t), intent(in) :: prt
+      type(flavor_t), intent(in) :: flv
+      type(polarization_t), intent(out) :: pol
+    end subroutine lcio_particle_to_pol
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_to_pol (prt, flv, pol)
+  module subroutine lcio_particle_to_pol (prt, flv, pol)
     type(lcio_particle_t), intent(in) :: prt
     type(flavor_t), intent(in) :: flv
     type(polarization_t), intent(out) :: pol
     real(default) :: degree, theta, phi
     degree = lcio_polarization_degree (prt%obj)
     theta = lcio_polarization_theta (prt%obj)
     phi = lcio_polarization_phi (prt%obj)
     call pol%init_angles (flv, degree, theta, phi)
   end subroutine lcio_particle_to_pol
 
 @ %def lcio_polarization_to_pol
 @ Recover helicity.  Here, $\phi$ and [[degree]] is ignored and only the sign of
 $\cos\theta$ is relevant, mapped to positive/negative helicity.
 <<LCIO interface: public>>=
   public :: lcio_particle_to_hel
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_to_hel (prt, flv, hel)
+      type(lcio_particle_t), intent(in) :: prt
+      type(flavor_t), intent(in) :: flv
+      type(helicity_t), intent(out) :: hel
+    end subroutine lcio_particle_to_hel
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_to_hel (prt, flv, hel)
+  module subroutine lcio_particle_to_hel (prt, flv, hel)
     type(lcio_particle_t), intent(in) :: prt
     type(flavor_t), intent(in) :: flv
     type(helicity_t), intent(out) :: hel
     real(default) :: theta
     integer :: hmax
     theta = lcio_polarization_theta (prt%obj)
     hmax = flv%get_spin_type () / 2
     call hel%init (sign (hmax, nint (cos (theta))))
   end subroutine lcio_particle_to_hel
 
 @ %def lcio_particle_to_hel
 @ Set the vertex of a particle.
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_particle_set_vertex (prt_obj, vx, vy, vz) bind(C)
        import
        type(c_ptr), value :: prt_obj
        real(c_double), value :: vx, vy, vz
      end subroutine lcio_particle_set_vertex
   end interface
   interface
      subroutine lcio_particle_set_time (prt_obj, t) bind(C)
        import
        type(c_ptr), value :: prt_obj
        real(c_float), value :: t
      end subroutine lcio_particle_set_time
   end interface
 
 @ %def lcio_particle_set_vertex lcio_particle_set_time
 @
 <<LCIO interface: public>>=
   public :: lcio_particle_set_vtx
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_set_vtx (prt, vtx)
+      type(lcio_particle_t), intent(inout) :: prt
+      type(vector3_t), intent(in) :: vtx
+    end subroutine lcio_particle_set_vtx
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_set_vtx (prt, vtx)
+  module subroutine lcio_particle_set_vtx (prt, vtx)
     type(lcio_particle_t), intent(inout) :: prt
     type(vector3_t), intent(in) :: vtx
     call lcio_particle_set_vertex (prt%obj, real(vtx%p(1), c_double), &
          real(vtx%p(2), c_double), real(vtx%p(3), c_double))
   end subroutine lcio_particle_set_vtx
 
 @ %def lcio_particle_set_vtx
 @
 Times in LCIO are in nanoseconds, not in mm, so need to be converted.
 <<LCIO interface: public>>=
   public :: lcio_particle_set_t
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_set_t (prt, t)
+      type(lcio_particle_t), intent(inout) :: prt
+      real(default), intent(in) :: t
+    end subroutine lcio_particle_set_t
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_set_t (prt, t)
+  module subroutine lcio_particle_set_t (prt, t)
     type(lcio_particle_t), intent(inout) :: prt
     real(default), intent(in) :: t
     real(default) :: ns_from_t_mm
     ns_from_t_mm = ns_per_mm * t
     call lcio_particle_set_time (prt%obj, real(ns_from_t_mm, c_float))
   end subroutine lcio_particle_set_t
 
 @ %def lcio_particle_set_t
 @
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_particle_add_parent (prt_obj1, prt_obj2) bind(C)
        import
        type(c_ptr), value :: prt_obj1, prt_obj2
      end subroutine lcio_particle_add_parent
   end interface
 @ %def lcio_particle_add_parent
 <<LCIO interface: public>>=
   public :: lcio_particle_set_parent
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_particle_set_parent (daughter, parent)
+      type(lcio_particle_t), intent(inout) :: daughter, parent
+    end subroutine lcio_particle_set_parent
 <<LCIO interface: procedures>>=
-  subroutine lcio_particle_set_parent (daughter, parent)
+  module subroutine lcio_particle_set_parent (daughter, parent)
     type(lcio_particle_t), intent(inout) :: daughter, parent
     call lcio_particle_add_parent (daughter%obj, parent%obj)
   end subroutine lcio_particle_set_parent
 
 @ %def lcio_particle_set_parent
 @
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_particle_get_generator_status &
           (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function lcio_particle_get_generator_status
   end interface
 @ %def lcio_particle_get_generator_status
 <<LCIO interface: public>>=
   public :: lcio_particle_get_status
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_status (lptr) result (status)
+      integer :: status
+      type(lcio_particle_t), intent(in) :: lptr
+    end function lcio_particle_get_status
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_status (lptr) result (status)
+  module function lcio_particle_get_status (lptr) result (status)
     integer :: status
     type(lcio_particle_t), intent(in) :: lptr
     status = lcio_particle_get_generator_status (lptr%obj)
   end function lcio_particle_get_status
 
 @ %def lcio_particle_get_status
 @ Getting the PDG code.
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_particle_get_pdg_code (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function lcio_particle_get_pdg_code
   end interface
 @ %def lcio_particle_get_pdg_code
 @
 <<LCIO interface: public>>=
   public :: lcio_particle_get_pdg
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_pdg (lptr) result (pdg)
+      integer :: pdg
+      type(lcio_particle_t), intent(in) :: lptr
+    end function lcio_particle_get_pdg
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_pdg (lptr) result (pdg)
+  module function lcio_particle_get_pdg (lptr) result (pdg)
     integer :: pdg
     type(lcio_particle_t), intent(in) :: lptr
     pdg = lcio_particle_get_pdg_code (lptr%obj)
   end function lcio_particle_get_pdg
 
 @ %def lcio_particle_get_pdg
 @ Obtaining the number of parents and daughters of an LCIO particle.
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_n_parents (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function lcio_n_parents
   end interface
 @ %def lcio_n_parents
 @
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_n_daughters (prt_obj) bind(C)
        import
        type(c_ptr), value :: prt_obj
      end function lcio_n_daughters
   end interface
 @ %def lcio_n_daughters
 @
 <<LCIO interface: public>>=
   public :: lcio_particle_get_n_parents
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_n_parents (lptr) result (n_parents)
+      integer :: n_parents
+      type(lcio_particle_t), intent(in) :: lptr
+    end function lcio_particle_get_n_parents
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_n_parents (lptr) result (n_parents)
+  module function lcio_particle_get_n_parents (lptr) result (n_parents)
     integer :: n_parents
     type(lcio_particle_t), intent(in) :: lptr
     n_parents = lcio_n_parents (lptr%obj)
   end function lcio_particle_get_n_parents
 
 @ %def lcio_particle_get_n_parents
 @
 <<LCIO interface: public>>=
   public :: lcio_particle_get_n_children
+<<LCIO interface: sub interfaces>>=
+    module function lcio_particle_get_n_children (lptr) result (n_children)
+      integer :: n_children
+      type(lcio_particle_t), intent(in) :: lptr
+    end function lcio_particle_get_n_children
 <<LCIO interface: procedures>>=
-  function lcio_particle_get_n_children (lptr) result (n_children)
+  module function lcio_particle_get_n_children (lptr) result (n_children)
     integer :: n_children
     type(lcio_particle_t), intent(in) :: lptr
     n_children = lcio_n_daughters (lptr%obj)
   end function lcio_particle_get_n_children
 
 @ %def lcio_particle_get_n_children
 @ This provides access from the LCIO event [[lcio_event_t]] to the array entries
 of the parent and daughter arrays of the LCIO particles.
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_event_parent_k &
           (evt_obj, num_part, k_parent) bind (C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: num_part, k_parent
      end function lcio_event_parent_k
   end interface
 @ %def lcio_event_parent_k
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_event_daughter_k &
           (evt_obj, num_part, k_daughter) bind (C)
        use iso_c_binding !NODEP!
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: num_part, k_daughter
      end function lcio_event_daughter_k
   end interface
 @ %def lcio_event_daughter_k
 @
 <<LCIO interface: public>>=
   public :: lcio_get_n_parents
+<<LCIO interface: sub interfaces>>=
+    module function lcio_get_n_parents &
+         (evt, num_part, k_parent) result (index_parent)
+      type(lcio_event_t), intent(in) :: evt
+      integer, intent(in) :: num_part, k_parent
+      integer :: index_parent
+    end function lcio_get_n_parents
 <<LCIO interface: procedures>>=
-  function lcio_get_n_parents (evt, num_part, k_parent) result (index_parent)
+  module function lcio_get_n_parents &
+       (evt, num_part, k_parent) result (index_parent)
     type(lcio_event_t), intent(in) :: evt
     integer, intent(in) :: num_part, k_parent
     integer :: index_parent
     index_parent = lcio_event_parent_k (evt%obj, int (num_part, c_int), &
          int (k_parent, c_int))
   end function lcio_get_n_parents
 
 @ %def lcio_get_n_parents
 @
 <<LCIO interface: public>>=
   public :: lcio_get_n_children
+<<LCIO interface: sub interfaces>>=
+    module function lcio_get_n_children &
+         (evt, num_part, k_daughter) result (index_daughter)
+      type(lcio_event_t), intent(in) :: evt
+      integer, intent(in) :: num_part, k_daughter
+      integer :: index_daughter
+    end function lcio_get_n_children
 <<LCIO interface: procedures>>=
-  function lcio_get_n_children (evt, num_part, k_daughter) result (index_daughter)
+  module function lcio_get_n_children &
+       (evt, num_part, k_daughter) result (index_daughter)
     type(lcio_event_t), intent(in) :: evt
     integer, intent(in) :: num_part, k_daughter
     integer :: index_daughter
     index_daughter = lcio_event_daughter_k (evt%obj, int (num_part, c_int), &
          int (k_daughter, c_int))
   end function lcio_get_n_children
 
 @ %def lcio_get_n_children
 @
 \subsection{LCIO Writer type}
 There is a specific LCIO Writer type for handling the output of
 LCEventImpl objects (i.e., Monte Carlo event samples) to file.  Opening
 the file is done by the constructor, closing by the destructor.
 <<LCIO interface: public>>=
   public :: lcio_writer_t
 <<LCIO interface: types>>=
   type :: lcio_writer_t
      private
      type(c_ptr) :: obj
   end type lcio_writer_t
 
 @ %def lcio_writer_t
 @ Constructor for an output associated to a file.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function open_lcio_writer_new (filename, complevel) bind(C)
        import
        character(c_char), dimension(*), intent(in) :: filename
        integer(c_int), intent(in) :: complevel
      end function open_lcio_writer_new
   end interface
 @ %def open_lcio_writer_now
 <<LCIO interface: public>>=
   public :: lcio_writer_open_out
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_writer_open_out (lcio_writer, filename)
+      type(lcio_writer_t), intent(out) :: lcio_writer
+      type(string_t), intent(in) :: filename
+    end subroutine lcio_writer_open_out
 <<LCIO interface: procedures>>=
-  subroutine lcio_writer_open_out (lcio_writer, filename)
+  module subroutine lcio_writer_open_out (lcio_writer, filename)
     type(lcio_writer_t), intent(out) :: lcio_writer
     type(string_t), intent(in) :: filename
     lcio_writer%obj = open_lcio_writer_new (char (filename) // &
          c_null_char, 9_c_int)
   end subroutine lcio_writer_open_out
 
 @ %def lcio_writer_open_out
 @ Destructor:
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_writer_delete (io_obj) bind(C)
        import
        type(c_ptr), value :: io_obj
      end subroutine lcio_writer_delete
   end interface
 @ %def lcio_writer_delete
 <<LCIO interface: public>>=
   public :: lcio_writer_close
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_writer_close (lciowriter)
+      type(lcio_writer_t), intent(inout) :: lciowriter
+    end subroutine lcio_writer_close
 <<LCIO interface: procedures>>=
-  subroutine lcio_writer_close (lciowriter)
+  module subroutine lcio_writer_close (lciowriter)
     type(lcio_writer_t), intent(inout) :: lciowriter
     call lcio_writer_delete (lciowriter%obj)
   end subroutine lcio_writer_close
 
 @ %def lcio_writer_close
 @ Write a single event to the LCIO writer.
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_write_event (io_obj, evt_obj) bind(C)
        import
        type(c_ptr), value :: io_obj, evt_obj
      end subroutine lcio_write_event
   end interface
 @ %def lcio_write_event
 <<LCIO interface: public>>=
   public :: lcio_event_write
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_event_write (wrt, evt)
+      type(lcio_writer_t), intent(inout) :: wrt
+      type(lcio_event_t), intent(in) :: evt
+    end subroutine lcio_event_write
 <<LCIO interface: procedures>>=
-  subroutine lcio_event_write (wrt, evt)
+  module subroutine lcio_event_write (wrt, evt)
     type(lcio_writer_t), intent(inout) :: wrt
     type(lcio_event_t), intent(in) :: evt
     call lcio_write_event (wrt%obj, evt%obj)
   end subroutine lcio_event_write
 
 @ %def lcio_event_write
 @
 \subsection{LCIO Reader type}
 There is a specific LCIO Reader type for handling the input of
 LCEventImpl objects (i.e., Monte Carlo event samples) from file.  Opening
 the file is done by the constructor, closing by the destructor.
 <<LCIO interface: public>>=
   public :: lcio_reader_t
 <<LCIO interface: types>>=
   type :: lcio_reader_t
      private
      type(c_ptr) :: obj
   end type lcio_reader_t
 
 @ %def lcio_reader_t
 @ Constructor for an output associated to a file.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function open_lcio_reader (filename) bind(C)
        import
        character(c_char), dimension(*), intent(in) :: filename
      end function open_lcio_reader
   end interface
 @ %def open_lcio_reader
 <<LCIO interface: public>>=
   public :: lcio_open_file
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_open_file (lcio_reader, filename)
+      type(lcio_reader_t), intent(out) :: lcio_reader
+      type(string_t), intent(in) :: filename
+    end subroutine lcio_open_file
 <<LCIO interface: procedures>>=
-  subroutine lcio_open_file (lcio_reader, filename)
+  module subroutine lcio_open_file (lcio_reader, filename)
     type(lcio_reader_t), intent(out) :: lcio_reader
     type(string_t), intent(in) :: filename
     lcio_reader%obj = open_lcio_reader (char (filename) // c_null_char)
   end subroutine lcio_open_file
 
 @ %def lcio_open_file
 @ Destructor:
 <<LCIO interface: interfaces>>=
   interface
      subroutine lcio_reader_delete (io_obj) bind(C)
        import
        type(c_ptr), value :: io_obj
      end subroutine lcio_reader_delete
   end interface
 @ %def lcio_reader_delete
 <<LCIO interface: public>>=
   public :: lcio_reader_close
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_reader_close (lcioreader)
+      type(lcio_reader_t), intent(inout) :: lcioreader
+    end subroutine lcio_reader_close
 <<LCIO interface: procedures>>=
-  subroutine lcio_reader_close (lcioreader)
+  module subroutine lcio_reader_close (lcioreader)
     type(lcio_reader_t), intent(inout) :: lcioreader
     call lcio_reader_delete (lcioreader%obj)
   end subroutine lcio_reader_close
 
 @ %def lcio_reader_close
 @
 @ Read a single event from the event file.  Return true if successful.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function read_lcio_event (io_obj) bind(C)
        import
        type(c_ptr), value :: io_obj
      end function read_lcio_event
   end interface
 @ %def read_lcio_event
 <<LCIO interface: public>>=
   public :: lcio_read_event
+<<LCIO interface: sub interfaces>>=
+    module subroutine lcio_read_event (lcrdr, evt, ok)
+      type(lcio_reader_t), intent(inout) :: lcrdr
+      type(lcio_event_t), intent(out) :: evt
+      logical, intent(out) :: ok
+    end subroutine lcio_read_event
 <<LCIO interface: procedures>>=
-  subroutine lcio_read_event (lcrdr, evt, ok)
+  module subroutine lcio_read_event (lcrdr, evt, ok)
     type(lcio_reader_t), intent(inout) :: lcrdr
     type(lcio_event_t), intent(out) :: evt
     logical, intent(out) :: ok
     evt%obj = read_lcio_event (lcrdr%obj)
     ok = c_associated (evt%obj)
   end subroutine lcio_read_event
 
 @ %def lcio_read_event
 @ Get the event index.
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_event_get_event_number (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function lcio_event_get_event_number
   end interface
 
 @ %def lcio_event_get_event_number
 <<LCIO interface: public>>=
   public :: lcio_event_get_event_index
+<<LCIO interface: sub interfaces>>=
+    module function lcio_event_get_event_index (evt) result (i_evt)
+      integer :: i_evt
+      type(lcio_event_t), intent(in) :: evt
+    end function lcio_event_get_event_index
 <<LCIO interface: procedures>>=
-  function lcio_event_get_event_index (evt) result (i_evt)
+  module function lcio_event_get_event_index (evt) result (i_evt)
     integer :: i_evt
     type(lcio_event_t), intent(in) :: evt
     i_evt = lcio_event_get_event_number (evt%obj)
   end function lcio_event_get_event_index
 
 @ %def lcio_event_get_event_index
 @ Extract the process ID. This is stored (at the moment abusively) in the
 RUN ID as well as in an additional event parameter.
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_event_signal_process_id (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function lcio_event_signal_process_id
   end interface
 @ %def lcio_event_signal_process_id
 <<LCIO interface: public>>=
   public :: lcio_event_get_process_id
+<<LCIO interface: sub interfaces>>=
+    module function lcio_event_get_process_id (evt) result (i_proc)
+      integer :: i_proc
+      type(lcio_event_t), intent(in) :: evt
+    end function lcio_event_get_process_id
 <<LCIO interface: procedures>>=
-  function lcio_event_get_process_id (evt) result (i_proc)
+  module function lcio_event_get_process_id (evt) result (i_proc)
     integer :: i_proc
     type(lcio_event_t), intent(in) :: evt
     i_proc = lcio_event_signal_process_id (evt%obj)
   end function lcio_event_get_process_id
 
 @ %def lcio_event_get_process_id
 @ Number of particles in an LCIO event.
 <<LCIO interface: interfaces>>=
   interface
      integer(c_int) function lcio_event_get_n_particles (evt_obj) bind(C)
        import
        type(c_ptr), value :: evt_obj
      end function lcio_event_get_n_particles
   end interface
 @ %def lcio_event_get_n_particles
 <<LCIO interface:>>=
 @
 <<LCIO interface: public>>=
   public :: lcio_event_get_n_tot
+<<LCIO interface: sub interfaces>>=
+    module function lcio_event_get_n_tot (evt) result (n_tot)
+      integer :: n_tot
+      type(lcio_event_t), intent(in) :: evt
+    end function lcio_event_get_n_tot
 <<LCIO interface: procedures>>=
-  function lcio_event_get_n_tot (evt) result (n_tot)
+  module function lcio_event_get_n_tot (evt) result (n_tot)
     integer :: n_tot
     type(lcio_event_t), intent(in) :: evt
     n_tot = lcio_event_get_n_particles (evt%obj)
   end function lcio_event_get_n_tot
 
 @ %def lcio_event_get_n_tot
 @ Extracting $\alpha_s$ and the scale.
 <<LCIO interface: interfaces>>=
   interface
      function lcio_event_get_alpha_qcd (evt_obj) result (as) bind(C)
        import
        real(c_double) :: as
        type(c_ptr), value :: evt_obj
      end function lcio_event_get_alpha_qcd
   end interface
   interface
      function lcio_event_get_scale (evt_obj) result (scale) bind(C)
        import
        real(c_double) :: scale
        type(c_ptr), value :: evt_obj
      end function lcio_event_get_scale
   end interface
 @ %def lcio_event_get_alpha_qcd lcio_event_get_scale
 @
 <<LCIO interface: public>>=
   public :: lcio_event_get_alphas
+<<LCIO interface: sub interfaces>>=
+    module function lcio_event_get_alphas (evt) result (as)
+      type(lcio_event_t), intent(in) :: evt
+      real(default) :: as
+    end function lcio_event_get_alphas
 <<LCIO interface: procedures>>=
-  function lcio_event_get_alphas (evt) result (as)
+  module function lcio_event_get_alphas (evt) result (as)
     type(lcio_event_t), intent(in) :: evt
     real(default) :: as
     as = lcio_event_get_alpha_qcd (evt%obj)
   end function lcio_event_get_alphas
 
 @ %def lcio_event_get_alphas
 @
 <<LCIO interface: public>>=
   public :: lcio_event_get_scaleval
+<<LCIO interface: sub interfaces>>=
+    module function lcio_event_get_scaleval (evt) result (scale)
+      type(lcio_event_t), intent(in) :: evt
+      real(default) :: scale
+    end function lcio_event_get_scaleval
 <<LCIO interface: procedures>>=
-  function lcio_event_get_scaleval (evt) result (scale)
+  module function lcio_event_get_scaleval (evt) result (scale)
     type(lcio_event_t), intent(in) :: evt
     real(default) :: scale
     scale = lcio_event_get_scale (evt%obj)
   end function lcio_event_get_scaleval
 
 @ %def lcio_event_get_scaleval
 @ Extracting particles by index from an LCIO event.
 <<LCIO interface: interfaces>>=
   interface
      type(c_ptr) function lcio_event_particle_k (evt_obj, k) bind(C)
        import
        type(c_ptr), value :: evt_obj
        integer(c_int), value :: k
      end function lcio_event_particle_k
   end interface
 @ %def lcio_event_particle_k
 @
 <<LCIO interface: public>>=
   public :: lcio_event_get_particle
+<<LCIO interface: sub interfaces>>=
+    module function lcio_event_get_particle (evt, n) result (prt)
+      type(lcio_event_t), intent(in) :: evt
+      integer, intent(in) :: n
+      type(lcio_particle_t) :: prt
+    end function lcio_event_get_particle
 <<LCIO interface: procedures>>=
-  function lcio_event_get_particle (evt, n) result (prt)
+  module function lcio_event_get_particle (evt, n) result (prt)
     type(lcio_event_t), intent(in) :: evt
     integer, intent(in) :: n
     type(lcio_particle_t) :: prt
     prt%obj = lcio_event_particle_k (evt%obj, int (n, c_int))
   end function lcio_event_get_particle
+
 @ %def lcio_event_get_particle
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[lcio_interface_ut.f90]]>>=
 <<File header>>
 
 module lcio_interface_ut
   use unit_tests
   use lcio_interface_uti
 
 <<Standard module head>>
 
 <<LCIO interface: public test>>
 
 contains
 
 <<LCIO interface: test driver>>
 
 end module lcio_interface_ut
 @ %def lcio_interface_ut
 @
 <<[[lcio_interface_uti.f90]]>>=
 <<File header>>
 
 module lcio_interface_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use lorentz
   use flavors
   use colors
   use polarizations
 
   use lcio_interface
 
 <<Standard module head>>
 
 <<LCIO interface: test declarations>>
 
 contains
 
 <<LCIO interface: tests>>
 
 end module lcio_interface_uti
 @ %def lcio_interface_ut
 @ API: driver for the unit tests below.
 <<LCIO interface: public test>>=
   public :: lcio_interface_test
 <<LCIO interface: test driver>>=
   subroutine lcio_interface_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<LCIO interface: execute tests>>
   end subroutine lcio_interface_test
 
 @  %def lcio_interface_test
 @
 <<LCIO interface: execute tests>>=
   call test (lcio_interface_1, "lcio_interface_1", &
        "check LCIO interface", &
        u, results)
 <<LCIO interface: test declarations>>=
   public :: lcio_interface_1
 <<LCIO interface: tests>>=
   subroutine lcio_interface_1 (u)
     use physics_defs, only: VECTOR
     use model_data, only: field_data_t
     integer, intent(in) :: u
     integer :: u_file, iostat
     type(lcio_event_t) :: evt
     type(lcio_particle_t) :: prt1, prt2, prt3, prt4, prt5, prt6, prt7, prt8
     type(flavor_t) :: flv
     type(color_t) :: col
     type(polarization_t) :: pol
     type(field_data_t), target :: photon_data
     character(220) :: buffer
 
     write (u, "(A)")  "* Test output: LCIO interface"
     write (u, "(A)")  "*   Purpose: test LCIO interface"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialization"
     write (u, "(A)")
 
     ! Initialize a photon flavor object and some polarization
     call photon_data%init (var_str ("PHOTON"), 22)
     call photon_data%set (spin_type=VECTOR)
     call photon_data%freeze ()
     call flv%init (photon_data)
     call pol%init_angles &
          (flv, 0.6_default, 1._default, 0.5_default)
 
     ! Event initialization
     call lcio_event_init (evt, 20, 1, 42)
 
     write (u, "(A)")  "* p -> q splitting"
     write (u, "(A)")
 
     ! $p\to q$ splittings
     call particle_init (prt1, &
          0._default, 0._default, 7000._default, 7000._default, &
          2212, 1._default, 3)
     call particle_init (prt2, &
          0._default, 0._default,-7000._default, 7000._default, &
          2212, 1._default, 3)
     call particle_init (prt3, &
           .750_default, -1.569_default, 32.191_default, 32.238_default, &
           1, -1._default/3._default, 3)
     call color_init_from_array (col, [501])
     call lcio_particle_set_color (prt3, col)
     call lcio_particle_set_parent (prt3, prt1)
     call lcio_particle_set_parent (prt3, prt2)
     call particle_init (prt4, &
          -3.047_default, -19._default, -54.629_default, 57.920_default, &
          -2, -2._default/3._default, 3)
     call color_init_from_array (col, [-501])
     call lcio_particle_set_color (prt4, col)
     call lcio_particle_set_parent (prt4, prt1)
     call lcio_particle_set_parent (prt4, prt2)
 
     write (u, "(A)")  "* Hard interaction"
     write (u, "(A)")
 
     ! Hard interaction
     call particle_init (prt6, &
          -3.813_default, 0.113_default, -1.833_default, 4.233_default, &
          22, 0._default, 1)
     call lcio_polarization_init (prt6, pol)
     call particle_init (prt5, &
          1.517_default, -20.68_default, -20.605_default, 85.925_default, &
          -24, -1._default, 3)
     call lcio_particle_set_parent (prt5, prt3)
     call lcio_particle_set_parent (prt5, prt4)
     call lcio_particle_set_parent (prt6, prt3)
     call lcio_particle_set_parent (prt6, prt4)
 
     ! $W^-$ decay
     call particle_init (prt7, &
          -2.445_default, 28.816_default, 6.082_default, 29.552_default, &
          1, -1._default/3._default, 1)
     call particle_init (prt8, &
          3.962_default, -49.498_default, -26.687_default, 56.373_default, &
          -2, -2._default/3._default, 1)
     call lcio_particle_set_t (prt7, 0.12_default)
     call lcio_particle_set_t (prt8, 0.12_default)
     call lcio_particle_set_vtx &
          (prt7, vector3_moving ([-0.3_default, 0.05_default, 0.004_default]))
     call lcio_particle_set_vtx &
          (prt8, vector3_moving ([-0.3_default, 0.05_default, 0.004_default]))
     call lcio_particle_set_parent (prt7, prt5)
     call lcio_particle_set_parent (prt8, prt5)
     call lcio_particle_add_to_evt_coll (prt1, evt)
     call lcio_particle_add_to_evt_coll (prt2, evt)
     call lcio_particle_add_to_evt_coll (prt3, evt)
     call lcio_particle_add_to_evt_coll (prt4, evt)
     call lcio_particle_add_to_evt_coll (prt5, evt)
     call lcio_particle_add_to_evt_coll (prt6, evt)
     call lcio_particle_add_to_evt_coll (prt7, evt)
     call lcio_particle_add_to_evt_coll (prt8, evt)
     call lcio_event_add_coll (evt)
 
     ! Event output
     write (u, "(A)")  "Writing in ASCII form to file 'lcio_test.slcio'"
     write (u, "(A)")
 
     call write_lcio_event (evt, var_str ("lcio_test.slcio"))
 
     write (u, "(A)")  "Writing completed"
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "lcio_test.slcio", &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (trim (buffer) == "")  cycle
        if (buffer(1:12) == " - timestamp")  buffer = "[...]"
        if (buffer(1:6) == " date:")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
     write (u, "(A)")
 
     ! Wrapup
     ! call pol%final ()
     call lcio_event_final (evt, .true.)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: lcio_interface_1"
 
   contains
 
     subroutine particle_init &
          (prt, px, py, pz, E, pdg, charge, status)
       type(lcio_particle_t), intent(out) :: prt
       real(default), intent(in) :: px, py, pz, E, charge
       integer, intent(in) :: pdg, status
       type(vector4_t) :: p
       p = vector4_moving (E, vector3_moving ([px, py, pz]))
       call lcio_particle_init (prt, p, pdg, charge, status)
     end subroutine particle_init
 
   end subroutine lcio_interface_1
 
 @ %def lcio_interface_1
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{HEP Common and Events}
 
 This is a separate module that manages data exchange between the common blocks
 and [[event_t]] objects. We separate this from the previous module in order
 to avoid a circular module dependency. It also contains the functions
 necessary for communication between [[hepmc_event_t]] and
 [[event_t]] or [[lcio_event_t]] and [[event_t]] as well as
 [[particle_set_t]] and [[particle_t]] objects.
 <<[[hep_events.f90]]>>=
 <<File header>>
 
 module hep_events
 
 <<Use kinds>>
 <<Use strings>>
+  use lorentz
+  use polarizations
+  use model_data
+  use particles
+  use hepmc_interface
+  use lcio_interface
+  use event_base
+
+<<Standard module head>>
+
+<<HEP events: public>>
+
+  interface
+<<HEP events: sub interfaces>>
+  end interface
+
+end module hep_events
+@ %def hep_events
+@
+<<[[hep_events_sub.f90]]>>=
+<<File header>>
+
+submodule (hep_events) hep_events_s
+
   use system_dependencies, only: HEPMC2_AVAILABLE
   use system_dependencies, only: HEPMC3_AVAILABLE
   use diagnostics
-  use lorentz
   use numeric_utils
   use flavors
   use colors
   use helicities
-  use polarizations
-  use model_data
   use subevents, only: PRT_BEAM, PRT_INCOMING, PRT_OUTGOING
   use subevents, only: PRT_UNDEFINED
   use subevents, only: PRT_VIRTUAL, PRT_RESONANT, PRT_BEAM_REMNANT
-  use particles
   use hep_common
-  use hepmc_interface
-  use lcio_interface
-  use event_base
 
-<<Standard module head>>
-
-<<HEP events: public>>
+  implicit none
 
 contains
 
 <<HEP events: procedures>>
 
-end module hep_events
-@ %def hep_events
+end submodule hep_events_s
+
+@ %def hep_events_s
 @
 \subsection{Data Transfer: events}
 Fill the HEPEUP block, given a \whizard\ event object.
 <<HEP events: public>>=
   public :: hepeup_from_event
+<<HEP events: sub interfaces>>=
+    module subroutine hepeup_from_event &
+         (event, keep_beams, keep_remnants, process_index)
+      class(generic_event_t), intent(in), target :: event
+      logical, intent(in), optional :: keep_beams
+      logical, intent(in), optional :: keep_remnants
+      integer, intent(in), optional :: process_index
+    end subroutine hepeup_from_event
 <<HEP events: procedures>>=
-  subroutine hepeup_from_event &
+  module subroutine hepeup_from_event &
        (event, keep_beams, keep_remnants, process_index)
     class(generic_event_t), intent(in), target :: event
     logical, intent(in), optional :: keep_beams
     logical, intent(in), optional :: keep_remnants
     integer, intent(in), optional :: process_index
     type(particle_set_t), pointer :: particle_set
     real(default) :: scale, alpha_qcd
     if (event%has_valid_particle_set ()) then
        particle_set => event%get_particle_set_ptr ()
        call hepeup_from_particle_set (particle_set, keep_beams, keep_remnants)
        if (present (process_index)) then
           call hepeup_set_event_parameters (proc_id = process_index)
        end if
        scale = event%get_fac_scale ()
        if (.not. vanishes (scale)) then
           call hepeup_set_event_parameters (scale = scale)
        end if
        alpha_qcd = event%get_alpha_s ()
        if (.not. vanishes (alpha_qcd)) then
           call hepeup_set_event_parameters (alpha_qcd = alpha_qcd)
        end if
        if (event%weight_prc_is_known ()) then
           call hepeup_set_event_parameters (weight = event%get_weight_prc ())
        end if
     else
        call msg_bug ("HEPEUP: event incomplete")
     end if
   end subroutine hepeup_from_event
 
 @ %def hepeup_from_event
 @ Reverse.
 
 Note: The current implementation sets the particle set of the hard
 process and is therefore not useful if the event on file is dressed.
 This should be reconsidered.
 
 Note: setting of scale or alpha is not yet supported by the
 [[event_t]] object.  Ticket \#628.
 <<HEP events: public>>=
   public :: hepeup_to_event
+<<HEP events: sub interfaces>>=
+    module subroutine hepeup_to_event &
+         (event, fallback_model, process_index, recover_beams, &
+         use_alpha_s, use_scale)
+      class(generic_event_t), intent(inout), target :: event
+      class(model_data_t), intent(in), target :: fallback_model
+      integer, intent(out), optional :: process_index
+      logical, intent(in), optional :: recover_beams
+      logical, intent(in), optional :: use_alpha_s
+      logical, intent(in), optional :: use_scale
+    end subroutine hepeup_to_event
 <<HEP events: procedures>>=
-  subroutine hepeup_to_event &
+  module subroutine hepeup_to_event &
        (event, fallback_model, process_index, recover_beams, &
        use_alpha_s, use_scale)
     class(generic_event_t), intent(inout), target :: event
     class(model_data_t), intent(in), target :: fallback_model
     integer, intent(out), optional :: process_index
     logical, intent(in), optional :: recover_beams
     logical, intent(in), optional :: use_alpha_s
     logical, intent(in), optional :: use_scale
     class(model_data_t), pointer :: model
     real(default) :: weight, scale, alpha_qcd
     type(particle_set_t) :: particle_set
     model => event%get_model_ptr ()
     call hepeup_to_particle_set &
          (particle_set, recover_beams, model, fallback_model)
     call event%set_hard_particle_set (particle_set)
     call particle_set%final ()
     if (present (process_index)) then
        call hepeup_get_event_parameters (proc_id = process_index)
     end if
     call hepeup_get_event_parameters (weight = weight, &
          scale = scale, alpha_qcd = alpha_qcd)
     call event%set_weight_ref (weight)
     if (present (use_alpha_s)) then
        if (use_alpha_s .and. alpha_qcd > 0) &
             call event%set_alpha_qcd_forced (alpha_qcd)
     end if
     if (present (use_scale)) then
        if (use_scale .and. scale > 0) &
             call event%set_scale_forced (scale)
     end if
   end subroutine hepeup_to_event
 
 @ %def hepeup_to_event
 @ Fill the HEPEVT (event) common block.
 
 The [[i_evt]] argument overrides the index stored in the [[event]] object.
 <<HEP events: public>>=
   public :: hepevt_from_event
+<<HEP events: sub interfaces>>=
+    module subroutine hepevt_from_event  &
+           (event, process_index, i_evt, keep_beams, keep_remnants, &
+            ensure_order, fill_hepev4)
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in), optional :: i_evt, process_index
+      logical, intent(in), optional :: keep_beams
+      logical, intent(in), optional :: keep_remnants
+      logical, intent(in), optional :: ensure_order
+      logical, intent(in), optional :: fill_hepev4
+    end subroutine hepevt_from_event
 <<HEP events: procedures>>=
-  subroutine hepevt_from_event  &
+  module subroutine hepevt_from_event  &
          (event, process_index, i_evt, keep_beams, keep_remnants, &
           ensure_order, fill_hepev4)
     class(generic_event_t), intent(in), target :: event
     integer, intent(in), optional :: i_evt, process_index
     logical, intent(in), optional :: keep_beams
     logical, intent(in), optional :: keep_remnants
     logical, intent(in), optional :: ensure_order
     logical, intent(in), optional :: fill_hepev4
     type(particle_set_t), pointer :: particle_set
     real(default) :: alpha_qcd, scale
     if (event%has_valid_particle_set ()) then
        particle_set => event%get_particle_set_ptr ()
        call hepevt_from_particle_set (particle_set, keep_beams, &
             keep_remnants, ensure_order, fill_hepev4)
        if (present (process_index)) then
           call hepevt_set_event_parameters (proc_id = process_index)
        end if
        if (event%weight_prc_is_known ()) then
           call hepevt_set_event_parameters (weight = event%get_weight_prc ())
        end if
        if (event%sqme_prc_is_known ()) then
           call hepevt_set_event_parameters &
                (function_value = event%get_sqme_prc ())
        end if
        scale = event%get_fac_scale ()
        if (.not. vanishes (scale)) then
           call hepevt_set_event_parameters (scale = scale)
        end if
        alpha_qcd = event%get_alpha_s ()
        if (.not. vanishes (alpha_qcd)) then
           call hepevt_set_event_parameters (alpha_qcd = alpha_qcd)
        end if
        if (present (i_evt)) then
           call hepevt_set_event_parameters (i_evt = i_evt)
        else if (event%has_index ()) then
           call hepevt_set_event_parameters (i_evt = event%get_index ())
        else
           call hepevt_set_event_parameters (i_evt = 0)
        end if
     else
        call msg_bug ("HEPEVT: event incomplete")
     end if
   end subroutine hepevt_from_event
 
 @ %def hepevt_from_event
 @
 \subsubsection{HepMC format}
 The master output function fills a HepMC GenEvent object that is
 already initialized, but has no vertices in it.
 
 We first set up the vertex lists and enter the vertices into the HepMC
 event.  Then, we assign first all incoming particles and then all
 outgoing particles to their associated vertices.  Particles which have
 neither parent nor children entries (this should not happen) are
 dropped.
 
 Finally, we insert the beam particles.  If there are none, use the incoming
 particles instead.
 @ Transform a particle into a [[hepmc_particle]] object, including
 color and polarization.  The HepMC status is equivalent to the HEPEVT
 status, in particular: 0 = null entry, 1 = physical particle, 2 =
 decayed/fragmented SM hadron, tau or muon, 3 = other unphysical particle
 entry, 4 = incoming particles, 11 = intermediate resonance such as squarks.
 The use of 11 for intermediate resonances is as done by HERWIG, see
 http://herwig.hepforge.org/trac/wiki/FaQs.
 <<HEP events: procedures>>=
   subroutine particle_to_hepmc (prt, hprt)
     type(particle_t), intent(in) :: prt
     type(hepmc_particle_t), intent(out) :: hprt
     integer :: hepmc_status
     select case (prt%get_status ())
     case (PRT_UNDEFINED)
        hepmc_status = 0
     case (PRT_OUTGOING)
        hepmc_status = 1
     case (PRT_BEAM)
        hepmc_status = 4
     case (PRT_RESONANT)
        hepmc_status = 2
     case (PRT_BEAM_REMNANT)
        if (prt%get_n_children () == 0) then
           hepmc_status = 1
        else
           hepmc_status = 3
        end if
     case default
        hepmc_status = 3
     end select
     call hepmc_particle_init (hprt, &
          prt%get_momentum (), prt%get_pdg (), &
          hepmc_status)
     if (HEPMC2_AVAILABLE) then
        call hepmc_particle_set_color (hprt, prt%get_color ())
        select case (prt%get_polarization_status ())
        case (PRT_DEFINITE_HELICITY)
           call hepmc_particle_set_polarization (hprt, &
                prt%get_helicity ())
        case (PRT_GENERIC_POLARIZATION)
           call hepmc_particle_set_polarization (hprt, &
                prt%get_polarization ())
        end select
     end if
   end subroutine particle_to_hepmc
 
 @ %def particle_to_hepmc
 @ For HepMC3, a HepMC particle needs first to be attached to a vertex
 and an event before non-intrinsic particle properties (color flow and
 helicity) could be set.
 <<HEP events: public>>=
   public :: hepmc_event_from_particle_set
+<<HEP events: sub interfaces>>=
+    module subroutine hepmc_event_from_particle_set &
+           (evt, particle_set, cross_section, error, color)
+      type(hepmc_event_t), intent(inout) :: evt
+      type(particle_set_t), intent(in) :: particle_set
+      real(default), intent(in), optional :: cross_section, error
+      logical, intent(in), optional :: color
+    end subroutine hepmc_event_from_particle_set
 <<HEP events: procedures>>=
-  subroutine hepmc_event_from_particle_set &
+  module subroutine hepmc_event_from_particle_set &
          (evt, particle_set, cross_section, error, color)
     type(hepmc_event_t), intent(inout) :: evt
     type(particle_set_t), intent(in) :: particle_set
     real(default), intent(in), optional :: cross_section, error
     logical, intent(in), optional :: color
     type(hepmc_vertex_t), dimension(:), allocatable :: v
     type(hepmc_particle_t), dimension(:), allocatable :: hprt
     type(hepmc_particle_t), dimension(2) :: hbeam
     type(vector4_t), dimension(:), allocatable :: vtx
     logical, dimension(:), allocatable :: is_beam
     integer, dimension(:), allocatable :: v_from, v_to
     integer :: n_vertices, n_tot, i
     logical :: write_color
     write_color = .false.
     if (present (color))  write_color = color
     n_tot = particle_set%get_n_tot ()
     allocate (v_from (n_tot), v_to (n_tot))
     call particle_set%assign_vertices (v_from, v_to, n_vertices)
     allocate (hprt (n_tot))
     allocate (vtx (n_vertices))
     vtx = vector4_null
     do i = 1, n_tot
        if (v_to(i) /= 0 .or. v_from(i) /= 0) then
           call particle_to_hepmc (particle_set%prt(i), hprt(i))
           if (v_from(i) /= 0) then
              vtx(v_from(i)) = particle_set%prt(i)%get_vertex ()
           end if
        end if
     end do
     if (present (cross_section) .and. present(error)) &
        call hepmc_event_set_cross_section (evt, cross_section, error)
     allocate (v (n_vertices))
     do i = 1, n_vertices
        call hepmc_vertex_init (v(i), vtx(i))
        call hepmc_event_add_vertex (evt, v(i))
     end do
     allocate (is_beam (n_tot))
     is_beam = particle_set%prt(1:n_tot)%get_status () == PRT_BEAM
     if (.not. any (is_beam)) then
        is_beam = particle_set%prt(1:n_tot)%get_status () == PRT_INCOMING
     end if
     if (count (is_beam) == 2) then
        hbeam = pack (hprt, is_beam)
        call hepmc_event_set_beam_particles (evt, hbeam(1), hbeam(2))
     end if
     do i = 1, n_tot
        if (v_to(i) /= 0) then
           call hepmc_vertex_add_particle_in (v(v_to(i)), hprt(i))
        end if
     end do
     do i = 1, n_tot
        if (v_from(i) /= 0) then
           call hepmc_vertex_add_particle_out (v(v_from(i)), hprt(i))
        end if
     end do
     FIND_SIGNAL_PROCESS: do i = 1, n_tot
        if (particle_set%prt(i)%get_status () == PRT_INCOMING) then
           call hepmc_event_set_signal_process_vertex (evt, v(v_to(i)))
           exit FIND_SIGNAL_PROCESS
        end if
     end do FIND_SIGNAL_PROCESS
     if (HEPMC3_AVAILABLE) then
        do i = 1, n_tot
           if (write_color) then
              call hepmc_particle_set_color (hprt(i), &
                   particle_set%prt(i)%get_color ())
           end if
           select case (particle_set%prt(i)%get_polarization_status ())
           case (PRT_DEFINITE_HELICITY)
              call hepmc_particle_set_polarization (hprt(i), &
                   particle_set%prt(i)%get_helicity ())
           case (PRT_GENERIC_POLARIZATION)
              call hepmc_particle_set_polarization (hprt(i), &
                   particle_set%prt(i)%get_polarization ())
           end select
        end do
     end if
   end subroutine hepmc_event_from_particle_set
 
 @ %def hepmc_event_from_particle_set
 @ Initialize a particle from a HepMC particle object.  The model is
 necessary for making a fully qualified flavor component.  We have the
 additional flag [[polarized]] which tells whether the polarization
 information should be interpreted or ignored, and the lookup array of
 barcodes.  Note that the lookup array is searched linearly, a possible
 bottleneck for large particle arrays.  If necessary, the barcode array
 could be replaced by a hash table.
 <<HEP events: procedures>>=
   subroutine particle_from_hepmc_particle &
        (prt, hprt, model, fallback_model, polarization, barcode)
     type(particle_t), intent(out) :: prt
     type(hepmc_particle_t), intent(in) :: hprt
     type(model_data_t), intent(in), target :: model
     type(model_data_t), intent(in), target :: fallback_model
     type(hepmc_vertex_t) :: vtx
     integer, intent(in) :: polarization
     integer, dimension(:), intent(in) :: barcode
     type(hepmc_polarization_t) :: hpol
     type(flavor_t) :: flv
     type(color_t) :: col
     type(helicity_t) :: hel
     type(polarization_t) :: pol
     type(vector4_t) :: vertex
     integer :: n_parents, n_children
     integer, dimension(:), allocatable :: &
          parent_barcode, child_barcode, parent, child
     integer :: i
     select case (hepmc_particle_get_status (hprt))
     case (1);  call prt%set_status (PRT_OUTGOING)
     case (2);  call prt%set_status (PRT_RESONANT)
     case (3);  call prt%set_status (PRT_VIRTUAL)
     end select
     if (hepmc_particle_is_beam (hprt)) call prt%set_status (PRT_BEAM)
     call flv%init (hepmc_particle_get_pdg (hprt), model, fallback_model)
     call col%init (hepmc_particle_get_color (hprt))
     call prt%set_flavor (flv)
     call prt%set_color (col)
     call prt%set_polarization (polarization)
     select case (polarization)
     case (PRT_DEFINITE_HELICITY)
        hpol = hepmc_particle_get_polarization (hprt)
        call hepmc_polarization_to_hel (hpol, prt%get_flv (), hel)
        call prt%set_helicity (hel)
        call hepmc_polarization_final (hpol)
     case (PRT_GENERIC_POLARIZATION)
        hpol = hepmc_particle_get_polarization (hprt)
        call hepmc_polarization_to_pol (hpol, prt%get_flv (), pol)
        call prt%set_pol (pol)
        call hepmc_polarization_final (hpol)
     end select
     call prt%set_momentum (hepmc_particle_get_momentum (hprt), &
          hepmc_particle_get_mass_squared (hprt))
     n_parents  = hepmc_particle_get_n_parents  (hprt)
     n_children = hepmc_particle_get_n_children (hprt)
     if (HEPMC2_AVAILABLE) then
        allocate (parent_barcode (n_parents),  parent (n_parents))
        allocate (child_barcode  (n_children), child  (n_children))
        parent_barcode = hepmc_particle_get_parent_barcodes (hprt)
        child_barcode  = hepmc_particle_get_child_barcodes  (hprt)
        do i = 1, size (barcode)
           where (parent_barcode == barcode(i))  parent = i
           where (child_barcode  == barcode(i))  child  = i
        end do
        call prt%set_parents (parent)
        call prt%set_children (child)
     else if (HEPMC3_AVAILABLE) then
        allocate (parent_barcode (n_parents),  parent (n_parents))
        allocate (child_barcode  (n_children), child  (n_children))
        parent_barcode = hepmc_particle_get_parent_barcodes (hprt)
        child_barcode  = hepmc_particle_get_child_barcodes  (hprt)
        do i = 1, size (barcode)
           where (parent_barcode == barcode(i))  parent = i
           where (child_barcode  == barcode(i))  child  = i
        end do
        call prt%set_parents (parent)
        call prt%set_children (child)
     end if
     if (prt%get_status () == PRT_VIRTUAL .and. n_parents == 0) &
          call prt%set_status (PRT_INCOMING)
     if (HEPMC2_AVAILABLE) then
        vtx = hepmc_particle_get_decay_vertex (hprt)
        if (hepmc_vertex_is_valid (vtx)) then
           vertex = hepmc_vertex_to_vertex (vtx)
           if (vertex /= vector4_null)  call prt%set_vertex (vertex)
        end if
     end if
   end subroutine particle_from_hepmc_particle
 
 @ %def particle_from_hepmc_particle
 @ If a particle set is initialized from a HepMC event record, we have
 to specify the treatment of polarization (unpolarized or density
 matrix) which is common to all particles.  Correlated polarization
 information is not available.
 
 There is some complication in reconstructing incoming particles and
 beam remnants.  First of all, they all will be tagged as virtual.  We
 then define an incoming particle as
 <<HEP events: public>>=
   public :: hepmc_event_to_particle_set
+<<HEP events: sub interfaces>>=
+    module subroutine hepmc_event_to_particle_set &
+         (particle_set, evt, model, fallback_model, polarization)
+      type(particle_set_t), intent(inout), target :: particle_set
+      type(hepmc_event_t), intent(in) :: evt
+      class(model_data_t), intent(in), target :: model, fallback_model
+      integer, intent(in) :: polarization
+    end subroutine hepmc_event_to_particle_set
 <<HEP events: procedures>>=
-  subroutine hepmc_event_to_particle_set &
+  module subroutine hepmc_event_to_particle_set &
        (particle_set, evt, model, fallback_model, polarization)
     type(particle_set_t), intent(inout), target :: particle_set
     type(hepmc_event_t), intent(in) :: evt
     class(model_data_t), intent(in), target :: model, fallback_model
     integer, intent(in) :: polarization
     type(hepmc_event_particle_iterator_t) :: it
     type(hepmc_vertex_t) :: v
     type(hepmc_vertex_particle_in_iterator_t) :: v_it
     type(hepmc_particle_t) :: prt
     integer, dimension(:), allocatable :: barcode, n_parents
     integer :: n_tot, n_beam, i, bc
     n_tot = hepmc_event_get_n_particles(evt)
     allocate (barcode (n_tot))
     if (HEPMC2_AVAILABLE) then
        call hepmc_event_particle_iterator_init (it, evt)
        do i = 1, n_tot
           barcode(i) = hepmc_particle_get_barcode &
                (hepmc_event_particle_iterator_get (it))
           call hepmc_event_particle_iterator_advance (it)
        end do
        allocate (particle_set%prt (n_tot))
        call hepmc_event_particle_iterator_reset (it)
        do i = 1, n_tot
           prt = hepmc_event_particle_iterator_get (it)
           call particle_from_hepmc_particle (particle_set%prt(i), &
                prt, model, fallback_model, polarization, barcode)
           call hepmc_event_particle_iterator_advance (it)
        end do
        call hepmc_event_particle_iterator_final (it)
        v = hepmc_event_get_signal_process_vertex (evt)
        if (hepmc_vertex_is_valid (v)) then
           call hepmc_vertex_particle_in_iterator_init (v_it, v)
           do while (hepmc_vertex_particle_in_iterator_is_valid (v_it))
              prt = hepmc_vertex_particle_in_iterator_get (v_it)
              bc = hepmc_particle_get_barcode &
                   (hepmc_vertex_particle_in_iterator_get (v_it))
              do i = 1, size(barcode)
                 if (bc == barcode(i))  &
                      call particle_set%prt(i)%set_status (PRT_INCOMING)
              end do
              call hepmc_vertex_particle_in_iterator_advance (v_it)
           end do
           call hepmc_vertex_particle_in_iterator_final (v_it)
        end if
     else if (HEPMC3_AVAILABLE) then
        allocate (particle_set%prt (n_tot))
        do i = 1, n_tot
           barcode(i) = hepmc_particle_get_barcode &
                (hepmc_event_get_nth_particle (evt, i))
        end do
        do i = 1, n_tot
           prt = hepmc_event_get_nth_particle (evt, i)
           call particle_from_hepmc_particle (particle_set%prt(i), &
                prt, model, fallback_model, polarization, barcode)
        end do
     end if
     do i = 1, n_tot
        if (particle_set%prt(i)%get_status () == PRT_VIRTUAL &
             .and. particle_set%prt(i)%get_n_children () == 0) &
             call particle_set%prt(i)%set_status (PRT_OUTGOING)
     end do
     if (HEPMC3_AVAILABLE) then
        n_beam = hepmc_event_get_n_beams (evt)
        do i = 1, n_beam
           bc = hepmc_event_get_nth_beam (evt, i)
           if (.not. particle_set%prt(bc)%get_status () == PRT_INCOMING) &
                call particle_set%prt(bc)%set_status (PRT_BEAM)
        end do
        do i = 1, n_tot
           if (particle_set%prt(i)%get_status () == PRT_VIRTUAL) then
              n_parents = particle_set%prt(i)%get_parents ()
              if (all &
                   (particle_set%prt(n_parents)%get_status () == PRT_BEAM)) then
                 call particle_set%prt(i)%set_status (PRT_INCOMING)
              end if
           end if
        end do
     end if
     particle_set%n_tot = n_tot
     particle_set%n_beam  = &
          count (particle_set%prt%get_status () == PRT_BEAM)
     particle_set%n_in  = &
          count (particle_set%prt%get_status () == PRT_INCOMING)
     particle_set%n_out = &
          count (particle_set%prt%get_status () == PRT_OUTGOING)
     particle_set%n_vir = &
          particle_set%n_tot - particle_set%n_in - particle_set%n_out
   end subroutine hepmc_event_to_particle_set
 
 @ %def hepmc_event_to_particle_set
 @ Fill a WHIZARD event from a HepMC event record.  In HepMC the weights
 are in a weight container.  If the size of this container is larger than
 one, it is ambiguous to assign the event a specific weight.  For now we
 only allow to read in unweighted events.
 <<HEP events: public>>=
   public :: hepmc_to_event
+<<HEP events: sub interfaces>>=
+    module subroutine hepmc_to_event &
+         (event, hepmc_event, fallback_model, process_index, &
+         recover_beams, use_alpha_s, use_scale)
+      class(generic_event_t), intent(inout), target :: event
+      type(hepmc_event_t), intent(inout) :: hepmc_event
+      class(model_data_t), intent(in), target :: fallback_model
+      integer, intent(out), optional :: process_index
+      logical, intent(in), optional :: recover_beams
+      logical, intent(in), optional :: use_alpha_s
+      logical, intent(in), optional :: use_scale
+    end subroutine hepmc_to_event
 <<HEP events: procedures>>=
-  subroutine hepmc_to_event &
+  module subroutine hepmc_to_event &
        (event, hepmc_event, fallback_model, process_index, &
        recover_beams, use_alpha_s, use_scale)
     class(generic_event_t), intent(inout), target :: event
     type(hepmc_event_t), intent(inout) :: hepmc_event
     class(model_data_t), intent(in), target :: fallback_model
     integer, intent(out), optional :: process_index
     logical, intent(in), optional :: recover_beams
     logical, intent(in), optional :: use_alpha_s
     logical, intent(in), optional :: use_scale
     class(model_data_t), pointer :: model
     real(default) :: scale, alpha_qcd
     type(particle_set_t) :: particle_set
     model => event%get_model_ptr ()
     call event%set_index (hepmc_event_get_event_index (hepmc_event))
     call hepmc_event_to_particle_set (particle_set, &
          hepmc_event, model, fallback_model, PRT_DEFINITE_HELICITY)
     call event%set_hard_particle_set (particle_set)
     call particle_set%final ()
     call event%set_weight_ref (1._default)
     alpha_qcd = hepmc_event_get_alpha_qcd (hepmc_event)
     scale = hepmc_event_get_scale (hepmc_event)
     if (present (use_alpha_s)) then
        if (use_alpha_s .and. alpha_qcd > 0) &
             call event%set_alpha_qcd_forced (alpha_qcd)
     end if
     if (present (use_scale)) then
        if (use_scale .and. scale > 0) &
             call event%set_scale_forced (scale)
     end if
   end subroutine hepmc_to_event
 
 @ %def hepmc_to_event
 @
 \subsubsection{LCIO event format}
 The master output function fills a LCIO event object that is
 already initialized, but has no particles in it.
 
 In contrast to HepMC in LCIO there are no vertices (except for tracker
 and other detector specifications). So we assign first all incoming
 particles and then all outgoing particles to LCIO particle types.
 Particles which have neither parent nor children entries (this
 should not happen) are dropped. Finally, we insert the beam particles.
 If there are none, use the incoming particles instead.
 
 Transform a particle into a [[lcio_particle]] object, including
 color and polarization.  The LCIO status is equivalent to the HepMC
 status, in particular: 0 = null entry, 1 = physical particle, 2 =
 decayed/fragmented SM hadron, tau or muon, 3 = other unphysical particle
 entry, 4 = incoming particles, 11 = intermediate resonance such as squarks.
 The use of 11 for intermediate resonances is as done by HERWIG, see
 http://herwig.hepforge.org/trac/wiki/FaQs.
 
 A beam-remnant particle (e.g., ISR photon) that has no children is
 tagged as outgoing, otherwise unphysical.
 <<HEP events: public>>=
   public :: particle_to_lcio
+<<HEP events: sub interfaces>>=
+    module subroutine particle_to_lcio (prt, lprt)
+      type(particle_t), intent(in) :: prt
+      type(lcio_particle_t), intent(out) :: lprt
+    end subroutine particle_to_lcio
 <<HEP events: procedures>>=
-  subroutine particle_to_lcio (prt, lprt)
+  module subroutine particle_to_lcio (prt, lprt)
     type(particle_t), intent(in) :: prt
     type(lcio_particle_t), intent(out) :: lprt
     integer :: lcio_status
     type(vector4_t) :: vtx
     select case (prt%get_status ())
     case (PRT_UNDEFINED)
        lcio_status = 0
     case (PRT_OUTGOING)
        lcio_status = 1
     case (PRT_BEAM_REMNANT)
        if (prt%get_n_children () == 0) then
           lcio_status = 1
        else
           lcio_status = 3
        end if
     case (PRT_BEAM)
        lcio_status = 4
     case (PRT_RESONANT)
        lcio_status = 2
     case default
        lcio_status = 3
     end select
     call lcio_particle_init (lprt, &
          prt%get_momentum (), &
          prt%get_pdg (), &
          prt%flv%get_charge (), &
          lcio_status)
     call lcio_particle_set_color (lprt, prt%get_color ())
     vtx = prt%get_vertex ()
     call lcio_particle_set_vtx (lprt, space_part (vtx))
     call lcio_particle_set_t (lprt, vtx%p(0))
     select case (prt%get_polarization_status ())
     case (PRT_DEFINITE_HELICITY)
        call lcio_polarization_init (lprt, prt%get_helicity ())
     case (PRT_GENERIC_POLARIZATION)
        call lcio_polarization_init (lprt, prt%get_polarization ())
     end select
   end subroutine particle_to_lcio
 
 @ %def particle_to_lcio
 @
 @ Initialize a particle from a LCIO particle object.  The model is
 necessary for making a fully qualified flavor component.
 <<HEP events: public>>=
   public :: particle_from_lcio_particle
+<<HEP events: sub interfaces>>=
+    module subroutine particle_from_lcio_particle &
+       (prt, lprt, model, fallback_model, daughters, parents, polarization)
+      type(particle_t), intent(out) :: prt
+      type(lcio_particle_t), intent(in) :: lprt
+      type(model_data_t), intent(in), target :: model
+      type(model_data_t), intent(in), target :: fallback_model
+      integer, dimension(:), intent(in) :: daughters, parents
+      integer, intent(in) :: polarization
+    end subroutine particle_from_lcio_particle
 <<HEP events: procedures>>=
-  subroutine particle_from_lcio_particle &
+  module subroutine particle_from_lcio_particle &
      (prt, lprt, model, fallback_model, daughters, parents, polarization)
     type(particle_t), intent(out) :: prt
     type(lcio_particle_t), intent(in) :: lprt
     type(model_data_t), intent(in), target :: model
     type(model_data_t), intent(in), target :: fallback_model
     integer, dimension(:), intent(in) :: daughters, parents
+    integer, intent(in) :: polarization
     type(vector4_t) :: vtx4
     type(flavor_t) :: flv
     type(color_t) :: col
     type(helicity_t) :: hel
     type(polarization_t) :: pol
-    integer, intent(in) :: polarization
     select case (lcio_particle_get_status (lprt))
     case (1);  call prt%set_status (PRT_OUTGOING)
     case (2);  call prt%set_status (PRT_RESONANT)
     case (3)
        select case (size (parents))
        case (0)
           call prt%set_status (PRT_INCOMING)
        case default
           call prt%set_status (PRT_VIRTUAL)
        end select
     case (4);  call prt%set_status (PRT_BEAM)
     end select
     call flv%init (lcio_particle_get_pdg (lprt), model, fallback_model)
     call col%init (lcio_particle_get_flow (lprt))
     if (flv%is_beam_remnant ())  call prt%set_status (PRT_BEAM_REMNANT)
     call prt%set_flavor (flv)
     call prt%set_color (col)
     call prt%set_polarization (polarization)
     select case (polarization)
     case (PRT_DEFINITE_HELICITY)
        call lcio_particle_to_hel (lprt, prt%get_flv (), hel)
        call prt%set_helicity (hel)
     case (PRT_GENERIC_POLARIZATION)
        call lcio_particle_to_pol (lprt, prt%get_flv (), pol)
        call prt%set_pol (pol)
     end select
     call prt%set_momentum (lcio_particle_get_momentum (lprt), &
          lcio_particle_get_mass_squared (lprt))
     call prt%set_parents (parents)
     call prt%set_children (daughters)
     vtx4 = vector4_moving (lcio_particle_get_time (lprt), &
          lcio_particle_get_vertex (lprt))
     if (vtx4 /= vector4_null)  call prt%set_vertex (vtx4)
   end subroutine particle_from_lcio_particle
 
 @ %def particle_from_lcio_particle
 @
 <<HEP events: public>>=
   public :: lcio_event_from_particle_set
+<<HEP events: sub interfaces>>=
+    module subroutine lcio_event_from_particle_set (evt, particle_set)
+      type(lcio_event_t), intent(inout) :: evt
+      type(particle_set_t), intent(in) :: particle_set
+    end subroutine lcio_event_from_particle_set
 <<HEP events: procedures>>=
-  subroutine lcio_event_from_particle_set (evt, particle_set)
+  module subroutine lcio_event_from_particle_set (evt, particle_set)
     type(lcio_event_t), intent(inout) :: evt
     type(particle_set_t), intent(in) :: particle_set
     type(lcio_particle_t), dimension(:), allocatable :: lprt
     type(particle_set_t), target :: pset_filtered
     integer, dimension(:), allocatable :: parent
     integer :: n_tot, i, j, n_beam, n_parents, type, beam_count
 
-    call particle_set%filter_particles ( pset_filtered, real_parents = .true. , &
-        keep_beams = .true. , keep_virtuals = .false.)
+    call particle_set%filter_particles ( pset_filtered, &
+         real_parents = .true. , keep_beams = .true. , keep_virtuals = .false.)
     n_tot = pset_filtered%n_tot
     n_beam = count (pset_filtered%prt%get_status () == PRT_BEAM)
     if (n_beam == 0) then
        type = PRT_INCOMING
     else
        type = PRT_BEAM
     end if
     beam_count = 0
     allocate (lprt (n_tot))
     do i = 1, n_tot
        call particle_to_lcio (pset_filtered%prt(i), lprt(i))
        n_parents = pset_filtered%prt(i)%get_n_parents ()
        if (n_parents /= 0) then
           allocate (parent (n_parents))
           parent = pset_filtered%prt(i)%get_parents ()
           do j = 1, n_parents
              call lcio_particle_set_parent  (lprt(i), lprt(parent(j)))
           end do
           deallocate (parent)
        end if
        if (pset_filtered%prt(i)%get_status () == type) then
           beam_count = beam_count + 1
           call lcio_event_set_beam &
                (evt, pset_filtered%prt(i)%get_pdg (), beam_count)
        end if
        call lcio_particle_add_to_evt_coll (lprt(i), evt)
     end do
     call lcio_event_add_coll (evt)
   end subroutine lcio_event_from_particle_set
 
 @ %def lcio_event_from_particle_set
 @ If a particle set is initialized from a LCIO event record, we have
 to specify the treatment of polarization (unpolarized or density
 matrix) which is common to all particles.  Correlated polarization
 information is not available.
 <<HEP events: public>>=
   public :: lcio_event_to_particle_set
+<<HEP events: sub interfaces>>=
+    module subroutine lcio_event_to_particle_set &
+         (particle_set, evt, model, fallback_model, polarization)
+      type(particle_set_t), intent(inout), target :: particle_set
+      type(lcio_event_t), intent(in) :: evt
+      class(model_data_t), intent(in), target :: model, fallback_model
+      integer, intent(in) :: polarization
+    end subroutine lcio_event_to_particle_set
 <<HEP events: procedures>>=
-  subroutine lcio_event_to_particle_set &
+  module subroutine lcio_event_to_particle_set &
        (particle_set, evt, model, fallback_model, polarization)
     type(particle_set_t), intent(inout), target :: particle_set
     type(lcio_event_t), intent(in) :: evt
     class(model_data_t), intent(in), target :: model, fallback_model
     integer, intent(in) :: polarization
     type(lcio_particle_t) :: prt
     integer, dimension(:), allocatable :: parents, daughters
     integer :: n_tot, i, j, n_parents, n_children
     n_tot = lcio_event_get_n_tot (evt)
     allocate (particle_set%prt (n_tot))
     do i = 1, n_tot
        prt = lcio_event_get_particle (evt, i-1)
        n_parents = lcio_particle_get_n_parents (prt)
        n_children = lcio_particle_get_n_children (prt)
        allocate (daughters (n_children))
        allocate (parents (n_parents))
        if (n_children > 0) then
           do j = 1, n_children
              daughters(j) = lcio_get_n_children (evt,i,j)
           end do
        end if
        if (n_parents > 0) then
           do j = 1, n_parents
              parents(j) = lcio_get_n_parents (evt,i,j)
           end do
        end if
        call particle_from_lcio_particle (particle_set%prt(i), &
             prt, model, fallback_model, &
             daughters, parents, polarization)
        deallocate (daughters, parents)
     end do
     do i = 1, n_tot
        if (particle_set%prt(i)%get_status () == PRT_VIRTUAL) then
           CHECK_BEAM: do j = 1, particle_set%prt(i)%get_n_parents ()
              if (particle_set%prt(j)%get_status () == PRT_BEAM) &
                   call particle_set%prt(i)%set_status (PRT_INCOMING)
              exit CHECK_BEAM
           end do CHECK_BEAM
        end if
     end do
     particle_set%n_tot = n_tot
     particle_set%n_beam  = &
          count (particle_set%prt%get_status () == PRT_BEAM)
     particle_set%n_in  = &
          count (particle_set%prt%get_status () == PRT_INCOMING)
     particle_set%n_out = &
          count (particle_set%prt%get_status () == PRT_OUTGOING)
     particle_set%n_vir = &
          particle_set%n_tot - particle_set%n_in - particle_set%n_out
   end subroutine lcio_event_to_particle_set
 
 @ %def lcio_event_to_particle_set
 @
 <<HEP events: public>>=
   public :: lcio_to_event
+<<HEP events: sub interfaces>>=
+    module subroutine lcio_to_event &
+         (event, lcio_event, fallback_model, process_index, recover_beams, &
+         use_alpha_s, use_scale)
+      class(generic_event_t), intent(inout), target :: event
+      type(lcio_event_t), intent(inout) :: lcio_event
+      class(model_data_t), intent(in), target :: fallback_model
+      integer, intent(out), optional :: process_index
+      logical, intent(in), optional :: recover_beams
+      logical, intent(in), optional :: use_alpha_s
+      logical, intent(in), optional :: use_scale
+    end subroutine lcio_to_event
 <<HEP events: procedures>>=
-  subroutine lcio_to_event &
+  module subroutine lcio_to_event &
        (event, lcio_event, fallback_model, process_index, recover_beams, &
        use_alpha_s, use_scale)
     class(generic_event_t), intent(inout), target :: event
     type(lcio_event_t), intent(inout) :: lcio_event
     class(model_data_t), intent(in), target :: fallback_model
     integer, intent(out), optional :: process_index
     logical, intent(in), optional :: recover_beams
     logical, intent(in), optional :: use_alpha_s
     logical, intent(in), optional :: use_scale
     class(model_data_t), pointer :: model
     real(default) :: scale, alpha_qcd
     type(particle_set_t) :: particle_set
     model => event%get_model_ptr ()
     call lcio_event_to_particle_set (particle_set, &
          lcio_event, model, fallback_model, PRT_DEFINITE_HELICITY)
     call event%set_hard_particle_set (particle_set)
     call particle_set%final ()
     call event%set_weight_ref (1._default)
     alpha_qcd = lcio_event_get_alphas (lcio_event)
     scale = lcio_event_get_scaleval (lcio_event)
     if (present (use_alpha_s)) then
        if (use_alpha_s .and. alpha_qcd > 0) &
             call event%set_alpha_qcd_forced (alpha_qcd)
     end if
     if (present (use_scale)) then
        if (use_scale .and. scale > 0) &
             call event%set_scale_forced (scale)
     end if
   end subroutine lcio_to_event
 
 @ %def lcio_to_event
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[hep_events_ut.f90]]>>=
 <<File header>>
 
 module hep_events_ut
   use unit_tests
   use hepmc_interface, only: HEPMC_IS_AVAILABLE
   use system_dependencies, only: HEPMC2_AVAILABLE
   use hep_events_uti
 
 <<Standard module head>>
 
 <<HEP events: public test>>
 
 contains
 
 <<HEP events: test driver>>
 
 end module hep_events_ut
 @ %def hep_events_ut
 @
 <<[[hep_events_uti.f90]]>>=
 <<File header>>
 
 module hep_events_uti
 
 <<Use kinds>>
 <<Use strings>>
   use lorentz
   use flavors
   use colors
   use helicities
   use quantum_numbers
   use state_matrices, only: FM_SELECT_HELICITY, FM_FACTOR_HELICITY
   use interactions
   use evaluators
   use model_data
   use particles
   use subevents
   use hepmc_interface
 
   use hep_events
 
 <<Standard module head>>
 
 <<HEP events: test declarations>>
 
 contains
 
 <<HEP events: tests>>
 
 end module hep_events_uti
 @ %def hep_events_ut
 @ API: driver for the unit tests below.
 <<HEP events: public test>>=
   public :: hep_events_test
 <<HEP events: test driver>>=
   subroutine hep_events_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<HEP events: execute tests>>
   end subroutine hep_events_test
 
 @  %def particles_test
 @ If [[HepMC]] is available, check the routines via [[HepMC]].
 
 Set up a chain of production and decay and factorize the result into
 particles.  The process is $d\bar d \to Z \to q\bar q$.
 <<HEP events: execute tests>>=
   if (hepmc_is_available ()) then
      call test (hep_events_1, "hep_events_1", &
           "check HepMC event routines", &
           u, results)
   end if
 <<HEP events: test declarations>>=
   public :: hep_events_1
 <<HEP events: tests>>=
   subroutine hep_events_1 (u)
     use os_interface
     integer, intent(in) :: u
     type(model_data_t), target :: model
     type(flavor_t), dimension(3) :: flv
     type(color_t), dimension(3) :: col
     type(helicity_t), dimension(3) :: hel
     type(quantum_numbers_t), dimension(3) :: qn
     type(vector4_t), dimension(3) :: p
     type(interaction_t), target :: int1, int2
     type(quantum_numbers_mask_t) :: qn_mask_conn
     type(evaluator_t), target :: eval
     type(interaction_t), pointer :: int
     type(particle_set_t) :: particle_set1, particle_set2
     type(hepmc_event_t) :: hepmc_event
     type(hepmc_iostream_t) :: iostream
     real(default) :: cross_section, error, weight
     logical :: ok
 
     write (u, "(A)")  "* Test output: HEP events"
     write (u, "(A)")  "*   Purpose: test HepMC event routines"
     write (u, "(A)")
 
     write (u, "(A)")  "* Reading model file"
 
     call model%init_sm_test ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Initializing production process"
 
     call int1%basic_init (2, 0, 1, set_relations=.true.)
     call flv%init ([1, -1, 23], model)
     call col%init_col_acl ([0, 0, 0], [0, 0, 0])
     call hel(3)%init ( 1, 1)
     call qn%init (flv, col, hel)
     call int1%add_state (qn, value=(0.25_default, 0._default))
     call hel(3)%init ( 1,-1)
     call qn%init (flv, col, hel)
     call int1%add_state (qn, value=(0._default, 0.25_default))
     call hel(3)%init (-1, 1)
     call qn%init (flv, col, hel)
     call int1%add_state (qn, value=(0._default,-0.25_default))
     call hel(3)%init (-1,-1)
     call qn%init (flv, col, hel)
     call int1%add_state (qn, value=(0.25_default, 0._default))
     call hel(3)%init ( 0, 0)
     call qn%init (flv, col, hel)
     call int1%add_state (qn, value=(0.5_default, 0._default))
     call int1%freeze ()
     p(1) = vector4_moving (45._default, 45._default, 3)
     p(2) = vector4_moving (45._default,-45._default, 3)
     p(3) = p(1) + p(2)
     call int1%set_momenta (p)
 
     write (u, "(A)")
     write (u, "(A)")  "* Setup decay process"
 
     call int2%basic_init (1, 0, 2, set_relations=.true.)
     call flv%init ([23, 1, -1], model)
     call col%init_col_acl ([0, 501, 0], [0, 0, 501])
     call hel%init ([1, 1, 1], [1, 1, 1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(1._default, 0._default))
     call hel%init ([1, 1, 1], [-1,-1,-1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(0._default, 0.1_default))
     call hel%init ([-1,-1,-1], [1, 1, 1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(0._default,-0.1_default))
     call hel%init ([-1,-1,-1], [-1,-1,-1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(1._default, 0._default))
     call hel%init ([0, 1,-1], [0, 1,-1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(4._default, 0._default))
     call hel%init ([0,-1, 1], [0, 1,-1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(2._default, 0._default))
     call hel%init ([0, 1,-1], [0,-1, 1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(2._default, 0._default))
     call hel%init ([0,-1, 1], [0,-1, 1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(4._default, 0._default))
     call flv%init ([23, 2, -2], model)
     call hel%init ([0, 1,-1], [0, 1,-1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(0.5_default, 0._default))
     call hel%init ([0,-1, 1], [0,-1, 1])
     call qn%init (flv, col, hel)
     call int2%add_state (qn, value=(0.5_default, 0._default))
     call int2%freeze ()
     p(2) = vector4_moving (45._default, 45._default, 2)
     p(3) = vector4_moving (45._default,-45._default, 2)
     call int2%set_momenta (p)
     call int2%set_source_link (1, int1, 3)
     call int1%basic_write (u)
     call int2%basic_write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Concatenate production and decay"
 
     call eval%init_product (int1, int2, qn_mask_conn, &
          connections_are_resonant=.true.)
     call eval%receive_momenta ()
     call eval%evaluate ()
     call eval%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Factorize as subevent (complete, polarized)"
     write (u, "(A)")
 
     int => eval%interaction_t
     call particle_set1%init &
          (ok, int, int, FM_FACTOR_HELICITY, &
           [0.2_default, 0.2_default], .false., .true.)
     call particle_set1%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Factorize as subevent (in/out only, selected helicity)"
     write (u, "(A)")
 
     int => eval%interaction_t
     call particle_set2%init &
          (ok, int, int, FM_SELECT_HELICITY, &
           [0.9_default, 0.9_default], .false., .false.)
     call particle_set2%write (u)
     call particle_set2%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Factorize as subevent (complete, selected helicity)"
     write (u, "(A)")
 
     int => eval%interaction_t
     call particle_set2%init &
          (ok, int, int, FM_SELECT_HELICITY, &
           [0.7_default, 0.7_default], .false., .true.)
     call particle_set2%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Transfer particle_set to HepMC, print, and output to"
     write (u, "(A)")  "        hep_events.hepmc.dat"
     write (u, "(A)")
 
     cross_section = 42.0_default
     error = 17.0_default
     weight = 1.0_default
     call hepmc_event_init (hepmc_event, 11, 127)
     call hepmc_event_from_particle_set (hepmc_event, particle_set2, &
          cross_section, error, .true.)
     call hepmc_event_add_weight (hepmc_event, weight, .true.)
     call hepmc_event_print (hepmc_event)
     call hepmc_iostream_open_out &
          (iostream , var_str ("hep_events.hepmc.dat"), 2)
     call hepmc_iostream_write_event (iostream, hepmc_event)
     call hepmc_iostream_close (iostream)
 
     write (u, "(A)")
     write (u, "(A)")  "* Recover from HepMC file"
     write (u, "(A)")
 
     call particle_set2%final ()
     call hepmc_event_final (hepmc_event)
     call hepmc_event_init (hepmc_event)
     call hepmc_iostream_open_in &
          (iostream , var_str ("hep_events.hepmc.dat"), HEPMC3_MODE_HEPMC3)
     call hepmc_iostream_read_event (iostream, hepmc_event, ok=ok)
     call hepmc_iostream_close (iostream)
     call hepmc_event_to_particle_set (particle_set2, &
          hepmc_event, model, model, PRT_DEFINITE_HELICITY)
     call particle_set2%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call particle_set1%final ()
     call particle_set2%final ()
     call eval%final ()
     call int1%final ()
     call int2%final ()
     call hepmc_event_final (hepmc_event)
     call model%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: hep_events_1"
 
   end subroutine hep_events_1
 
 @
 @ %def hep_events_1
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{LHEF Input/Output}
 The LHEF event record is standardized.  It is an ASCII format.  We try
 our best at using it for both input and output.
 <<[[eio_lhef.f90]]>>=
 <<File header>>
 
 module eio_lhef
 
 <<Use kinds>>
 <<Use strings>>
-  use io_units
-  use string_utils
-  use numeric_utils
-  use diagnostics
-  use os_interface
   use xml
   use event_base
   use event_handles, only: event_handle_t
   use eio_data
   use eio_base
-  use hep_common
-  use hep_events
 
 <<Standard module head>>
 
 <<EIO LHEF: public>>
 
 <<EIO LHEF: types>>
 
+  interface
+<<EIO LHEF: sub interfaces>>
+  end interface
+
+end module eio_lhef
+@ %def eio_lhef
+@
+<<[[eio_lhef_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_lhef) eio_lhef_s
+
+  use io_units
+  use string_utils
+  use numeric_utils
+  use diagnostics
+  use os_interface
+  use hep_common
+  use hep_events
+
+  implicit none
+
 contains
 
 <<EIO LHEF: procedures>>
 
-end module eio_lhef
-@ %def eio_lhef
+end submodule eio_lhef_s
+
+@ %def eio_lhef_s
 @
 \subsection{Type}
 With sufficient confidence that it will always be three characters, we
 can store the version string with a default value.
 <<EIO LHEF: public>>=
   public :: eio_lhef_t
 <<EIO LHEF: types>>=
   type, extends (eio_t) :: eio_lhef_t
      logical :: writing = .false.
      logical :: reading = .false.
      integer :: unit = 0
      type(event_sample_data_t) :: data
      type(cstream_t) :: cstream
      character(3) :: version = "1.0"
      logical :: keep_beams = .false.
      logical :: keep_remnants = .true.
      logical :: keep_virtuals = .false.
      logical :: recover_beams = .true.
      logical :: unweighted = .true.
      logical :: write_sqme_ref = .false.
      logical :: write_sqme_prc = .false.
      logical :: write_sqme_alt = .false.
      logical :: use_alphas_from_file = .false.
      logical :: use_scale_from_file = .false.
      integer :: n_alt = 0
      integer, dimension(:), allocatable :: proc_num_id
      integer :: i_weight_sqme = 0
      type(xml_tag_t) :: tag_lhef, tag_head, tag_init, tag_event
      type(xml_tag_t), allocatable :: tag_whiz_info
      type(xml_tag_t), allocatable :: tag_gen_n, tag_gen_v
      type(xml_tag_t), allocatable :: tag_generator, tag_xsecinfo
      type(xml_tag_t), allocatable :: tag_sqme_ref, tag_sqme_prc
      type(xml_tag_t), dimension(:), allocatable :: tag_sqme_alt, tag_wgts_alt
      type(xml_tag_t), allocatable :: tag_weight, tag_weightinfo, tag_weights
    contains
    <<EIO LHEF: eio lhef: TBP>>
   end type eio_lhef_t
 
 @ %def eio_lhef_t
 @
 \subsection{Specific Methods}
 Set parameters that are specifically used with LHEF.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: set_parameters => eio_lhef_set_parameters
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_set_parameters (eio, &
+         keep_beams, keep_remnants, recover_beams, &
+         use_alphas_from_file, use_scale_from_file, &
+         version, extension, write_sqme_ref, write_sqme_prc, write_sqme_alt)
+      class(eio_lhef_t), intent(inout) :: eio
+      logical, intent(in), optional :: keep_beams
+      logical, intent(in), optional :: keep_remnants
+      logical, intent(in), optional :: recover_beams
+      logical, intent(in), optional :: use_alphas_from_file
+      logical, intent(in), optional :: use_scale_from_file
+      character(*), intent(in), optional :: version
+      type(string_t), intent(in), optional :: extension
+      logical, intent(in), optional :: write_sqme_ref
+      logical, intent(in), optional :: write_sqme_prc
+      logical, intent(in), optional :: write_sqme_alt
+    end subroutine eio_lhef_set_parameters
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_set_parameters (eio, &
+  module subroutine eio_lhef_set_parameters (eio, &
        keep_beams, keep_remnants, recover_beams, &
        use_alphas_from_file, use_scale_from_file, &
        version, extension, write_sqme_ref, write_sqme_prc, write_sqme_alt)
     class(eio_lhef_t), intent(inout) :: eio
     logical, intent(in), optional :: keep_beams
     logical, intent(in), optional :: keep_remnants
     logical, intent(in), optional :: recover_beams
     logical, intent(in), optional :: use_alphas_from_file
     logical, intent(in), optional :: use_scale_from_file
     character(*), intent(in), optional :: version
     type(string_t), intent(in), optional :: extension
     logical, intent(in), optional :: write_sqme_ref
     logical, intent(in), optional :: write_sqme_prc
     logical, intent(in), optional :: write_sqme_alt
     if (present (keep_beams))  eio%keep_beams = keep_beams
     if (present (keep_remnants))  eio%keep_remnants = keep_remnants
     if (present (recover_beams))  eio%recover_beams = recover_beams
     if (present (use_alphas_from_file)) &
          eio%use_alphas_from_file = use_alphas_from_file
     if (present (use_scale_from_file)) &
          eio%use_scale_from_file = use_scale_from_file
     if (present (version)) then
        select case (version)
        case ("1.0", "2.0", "3.0")
           eio%version = version
        case default
           call msg_error ("LHEF version " // version &
                // " is not supported.  Inserting 2.0")
           eio%version = "2.0"
        end select
     end if
     if (present (extension)) then
        eio%extension = extension
     else
        eio%extension = "lhe"
     end if
     if (present (write_sqme_ref))  eio%write_sqme_ref = write_sqme_ref
     if (present (write_sqme_prc))  eio%write_sqme_prc = write_sqme_prc
     if (present (write_sqme_alt))  eio%write_sqme_alt = write_sqme_alt
   end subroutine eio_lhef_set_parameters
 
 @ %def eio_lhef_set_parameters
 @
 \subsection{Common Methods}
 Output.  This is not the actual event format, but a readable account
 of the current object status.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: write => eio_lhef_write
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_write (object, unit)
+      class(eio_lhef_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_lhef_write
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_write (object, unit)
+  module subroutine eio_lhef_write (object, unit)
     class(eio_lhef_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "LHEF event stream:"
     if (object%writing) then
        write (u, "(3x,A,A)")  "Writing to file   = ", char (object%filename)
     else if (object%reading) then
        write (u, "(3x,A,A)")  "Reading from file = ", char (object%filename)
     else
        write (u, "(3x,A)")  "[closed]"
     end if
     write (u, "(3x,A,L1)")    "Keep beams        = ", object%keep_beams
     write (u, "(3x,A,L1)")    "Keep remnants     = ", object%keep_remnants
     write (u, "(3x,A,L1)")    "Recover beams     = ", object%recover_beams
     write (u, "(3x,A,L1)")    "Alpha_s from file = ", &
          object%use_alphas_from_file
     write (u, "(3x,A,L1)")    "Scale from file   = ", &
          object%use_scale_from_file
     write (u, "(3x,A,A)")     "Version           = ", object%version
     write (u, "(3x,A,A,A)")     "File extension    = '", &
          char (object%extension), "'"
     if (allocated (object%proc_num_id)) then
        write (u, "(3x,A)")  "Numerical process IDs:"
        do i = 1, size (object%proc_num_id)
           write (u, "(5x,I0,': ',I0)")  i, object%proc_num_id(i)
        end do
     end if
   end subroutine eio_lhef_write
 
 @ %def eio_lhef_write
 @ Finalizer: close any open file.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: final => eio_lhef_final
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_final (object)
+      class(eio_lhef_t), intent(inout) :: object
+    end subroutine eio_lhef_final
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_final (object)
+  module subroutine eio_lhef_final (object)
     class(eio_lhef_t), intent(inout) :: object
     if (allocated (object%proc_num_id))  deallocate (object%proc_num_id)
     if (object%writing) then
        write (msg_buffer, "(A,A,A)")  "Events: closing LHEF file '", &
             char (object%filename), "'"
        call msg_message ()
        call object%write_footer ()
        close (object%unit)
        object%writing = .false.
     else if (object%reading) then
        write (msg_buffer, "(A,A,A)")  "Events: closing LHEF file '", &
             char (object%filename), "'"
        call msg_message ()
        call object%cstream%final ()
        close (object%unit)
        object%reading = .false.
     end if
   end subroutine eio_lhef_final
 
 @ %def eio_lhef_final
 @ Common initialization for input and output.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: common_init => eio_lhef_common_init
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_common_init (eio, sample, data, extension)
+      class(eio_lhef_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+    end subroutine eio_lhef_common_init
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_common_init (eio, sample, data, extension)
+  module subroutine eio_lhef_common_init (eio, sample, data, extension)
     class(eio_lhef_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     if (.not. present (data)) &
          call msg_bug ("LHEF initialization: missing data")
     eio%data = data
     eio%unweighted = data%unweighted
     if (eio%unweighted) then
        select case (data%norm_mode)
        case (NORM_UNIT)
        case default;  call msg_fatal &
             ("LHEF: normalization for unweighted events must be '1'")
        end select
     else
        select case (data%norm_mode)
        case (NORM_SIGMA)
        case default;  call msg_fatal &
             ("LHEF: normalization for weighted events must be 'sigma'")
        end select
     end if
     eio%n_alt = data%n_alt
     eio%sample = sample
     if (present (extension)) then
        eio%extension = extension
     end if
     call eio%set_filename ()
     eio%unit = free_unit ()
     call eio%init_tags (data)
     allocate (eio%proc_num_id (data%n_proc), source = data%proc_num_id)
   end subroutine eio_lhef_common_init
 
 @ %def eio_lhef_common_init
 @ Initialize the tag objects.  Some tags depend on the LHEF
 version.  In particular, the tags that in LHEF 2.0 identify
 individual weights by name in each event block, in LHEF 3.0 are
 replaced by info tags in the init block and a single \texttt{weights}
 tag in the event block.  The name attributes of those tags
 are specific for \whizard.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: init_tags => eio_lhef_init_tags
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_init_tags (eio, data)
+      class(eio_lhef_t), intent(inout) :: eio
+      type(event_sample_data_t), intent(in) :: data
+    end subroutine eio_lhef_init_tags
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_init_tags (eio, data)
+  module subroutine eio_lhef_init_tags (eio, data)
     class(eio_lhef_t), intent(inout) :: eio
     type(event_sample_data_t), intent(in) :: data
     real(default), parameter :: pb_per_fb = 1.e-3_default
     real(default) :: xsec_width
     integer :: i
     call eio%tag_lhef%init ( &
          var_str ("LesHouchesEvents"), &
          [xml_attribute (var_str ("version"), var_str (eio%version))], &
          .true.)
     call eio%tag_head%init ( &
          var_str ("header"), &
          .true.)
     call eio%tag_init%init ( &
          var_str ("init"), &
          .true.)
     call eio%tag_event%init (var_str ("event"), &
          .true.)
     allocate (eio%tag_whiz_info)
     call eio%tag_whiz_info%init (var_str ("WhizardInfo"), .true.)
     select case (eio%version)
     case ("1.0")
        allocate (eio%tag_gen_n)
        call eio%tag_gen_n%init ( &
             var_str ("generator_name"), &
             .true.)
        allocate (eio%tag_gen_v)
        call eio%tag_gen_v%init ( &
             var_str ("generator_version"), &
             .true.)
     end select
     select case (eio%version)
     case ("2.0", "3.0")
        allocate (eio%tag_generator)
        call eio%tag_generator%init ( &
             var_str ("generator"), &
             [xml_attribute (var_str ("version"), var_str ("<<Version>>"))], &
             .true.)
        allocate (eio%tag_xsecinfo)
        if (data%n_beam == 2) then
           xsec_width = data%total_cross_section * pb_per_fb
        else
           xsec_width = data%total_cross_section
        end if
        call eio%tag_xsecinfo%init ( &
             var_str ("xsecinfo"), &
             [xml_attribute (var_str ("neve"), str (data%n_evt)), &
              xml_attribute (var_str ("totxsec"), &
                             str (xsec_width))])
     end select
     select case (eio%version)
     case ("2.0")
        allocate (eio%tag_weight)
        call eio%tag_weight%init (var_str ("weight"), &
             [xml_attribute (var_str ("name"))])
        if (eio%write_sqme_ref) then
           allocate (eio%tag_sqme_ref)
           call eio%tag_sqme_ref%init (var_str ("weight"), &
                [xml_attribute (var_str ("name"), var_str ("sqme_ref"))], &
                .true.)
        end if
        if (eio%write_sqme_prc) then
           allocate (eio%tag_sqme_prc)
           call eio%tag_sqme_prc%init (var_str ("weight"), &
                [xml_attribute (var_str ("name"), var_str ("sqme_prc"))], &
                .true.)
        end if
        if (eio%n_alt > 0) then
           if (eio%write_sqme_alt) then
              allocate (eio%tag_sqme_alt (1))
              call eio%tag_sqme_alt(1)%init (var_str ("weight"), &
                   [xml_attribute (var_str ("name"), var_str ("sqme_alt"))], &
                   .true.)
           end if
           allocate (eio%tag_wgts_alt (1))
           call eio%tag_wgts_alt(1)%init (var_str ("weight"), &
                [xml_attribute (var_str ("name"), var_str ("wgts_alt"))], &
                .true.)
        end if
     case ("3.0")
        if (eio%write_sqme_ref) then
           allocate (eio%tag_sqme_ref)
           call eio%tag_sqme_ref%init (var_str ("weightinfo"), &
                [xml_attribute (var_str ("name"), var_str ("sqme_ref"))])
        end if
        if (eio%write_sqme_prc) then
           allocate (eio%tag_sqme_prc)
           call eio%tag_sqme_prc%init (var_str ("weightinfo"), &
                [xml_attribute (var_str ("name"), var_str ("sqme_prc"))])
        end if
        if (eio%n_alt > 0) then
           if (eio%write_sqme_alt) then
              allocate (eio%tag_sqme_alt (eio%n_alt))
              do i = 1, eio%n_alt
                 call eio%tag_sqme_alt(i)%init (var_str ("weightinfo"), &
                      [xml_attribute (var_str ("name"), &
                                      var_str ("sqme_alt") // str (i))])
              end do
           end if
           allocate (eio%tag_wgts_alt (eio%n_alt))
           do i = 1, eio%n_alt
              call eio%tag_wgts_alt(i)%init (var_str ("weightinfo"), &
                   [xml_attribute (var_str ("name"), &
                                   var_str ("wgts_alt") // str (i))])
           end do
        end if
        allocate (eio%tag_weightinfo)
        call eio%tag_weightinfo%init (var_str ("weightinfo"), &
             [xml_attribute (var_str ("name"))])
        allocate (eio%tag_weights)
        call eio%tag_weights%init (var_str ("weights"), .true.)
     end select
   end subroutine eio_lhef_init_tags
 
 @ %def eio_lhef_init_tags
 @ Initialize event writing.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: init_out => eio_lhef_init_out
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_init_out (eio, sample, data, success, extension)
+      class(eio_lhef_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_lhef_init_out
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_init_out (eio, sample, data, success, extension)
+  module subroutine eio_lhef_init_out (eio, sample, data, success, extension)
     class(eio_lhef_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     integer :: u, i
     logical :: is_width
     is_width = data%n_beam == 1
     call eio%set_splitting (data)
     call eio%common_init (sample, data, extension)
     write (msg_buffer, "(A,A,A)")  "Events: writing to LHEF file '", &
          char (eio%filename), "'"
     call msg_message ()
     eio%writing = .true.
     u = eio%unit
     open (u, file = char (eio%filename), &
          action = "write", status = "replace")
     call eio%write_header (is_width)
     call heprup_init &
          (data%pdg_beam, &
           data%energy_beam, &
           n_processes = data%n_proc, &
           unweighted = data%unweighted, &
           negative_weights = data%negative_weights)
     do i = 1, data%n_proc
        call heprup_set_process_parameters (i = i, &
             process_id = data%proc_num_id(i), &
             cross_section = data%cross_section(i), &
             error = data%error(i), &
             is_width = is_width)
     end do
     call eio%tag_init%write (u);  write (u, *)
     call heprup_write_lhef (u)
     select case (eio%version)
     case ("2.0");  call eio%write_init_20 (data)
     case ("3.0");  call eio%write_init_30 (data)
     end select
     call eio%tag_init%close (u);  write (u, *)
     if (present (success))  success = .true.
   end subroutine eio_lhef_init_out
 
 @ %def eio_lhef_init_out
 @ Initialize event reading.  First read the LHEF tag and version, then
 read the header and skip over its contents, then read the init block.
 (We require the opening and closing tags of the init block to be placed
 on separate lines without extra stuff.)
 
 For input, we do not (yet?) support split event files.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: init_in => eio_lhef_init_in
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_init_in (eio, sample, data, success, extension)
+      class(eio_lhef_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_lhef_init_in
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_init_in (eio, sample, data, success, extension)
+  module subroutine eio_lhef_init_in (eio, sample, data, success, extension)
     class(eio_lhef_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     logical :: exist, ok, closing
     type(event_sample_data_t) :: data_file
     type(string_t) :: string
     integer :: u
     eio%split = .false.
     call eio%common_init (sample, data, extension)
     write (msg_buffer, "(A,A,A)")  "Events: reading from LHEF file '", &
          char (eio%filename), "'"
     call msg_message ()
     inquire (file = char (eio%filename), exist = exist)
     if (.not. exist)  call msg_fatal ("Events: LHEF file not found.")
     eio%reading = .true.
     u = eio%unit
     open (u, file = char (eio%filename), &
          action = "read", status = "old")
     call eio%cstream%init (u)
     call eio%read_header ()
     call eio%tag_init%read (eio%cstream, ok)
     if (.not. ok)  call err_init
     select case (eio%version)
     case ("1.0");  call eio%read_init_10 (data_file)
        call eio%tag_init%read_content (eio%cstream, string, closing)
        if (string /= "" .or. .not. closing)  call err_init
     case ("2.0");  call eio%read_init_20 (data_file)
     case ("3.0");  call eio%read_init_30 (data_file)
     end select
     call eio%merge_data (data, data_file)
     if (present (success))  success = .true.
 
   contains
 
     subroutine err_init
       call msg_fatal ("LHEF: syntax error in init tag")
     end subroutine err_init
 
   end subroutine eio_lhef_init_in
 
 @ %def eio_lhef_init_in
 @ Merge event sample data: we can check the data in the file against
 our assumptions and set or reset parameters.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: merge_data => eio_merge_data
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_merge_data (eio, data, data_file)
+      class(eio_lhef_t), intent(inout) :: eio
+      type(event_sample_data_t), intent(inout) :: data
+      type(event_sample_data_t), intent(in) :: data_file
+    end subroutine eio_merge_data
 <<EIO LHEF: procedures>>=
-  subroutine eio_merge_data (eio, data, data_file)
+  module subroutine eio_merge_data (eio, data, data_file)
     class(eio_lhef_t), intent(inout) :: eio
     type(event_sample_data_t), intent(inout) :: data
     type(event_sample_data_t), intent(in) :: data_file
     real, parameter :: tolerance = 1000 * epsilon (1._default)
     if (data%unweighted .neqv. data_file%unweighted)  call err_weights
     if (data%negative_weights .neqv. data_file%negative_weights) &
          call err_weights
     if (data%norm_mode /= data_file%norm_mode)  call err_norm
     if (data%n_beam /= data_file%n_beam)  call err_beams
     if (any (data%pdg_beam /= data_file%pdg_beam))  call err_beams
     if (any (abs ((data%energy_beam - data_file%energy_beam)) &
          > (data%energy_beam + data_file%energy_beam) * tolerance)) &
          call err_beams
     if (data%n_proc /= data_file%n_proc)  call err_proc
     if (any (data%proc_num_id /= data_file%proc_num_id))  call err_proc
     where (data%cross_section == 0)
        data%cross_section = data_file%cross_section
        data%error = data_file%error
     end where
     data%total_cross_section = sum (data%cross_section)
     if (data_file%n_evt > 0) then
        if (data%n_evt > 0 .and. data_file%n_evt /= data%n_evt)  call err_n_evt
        data%n_evt = data_file%n_evt
     end if
   contains
     subroutine err_weights
       call msg_fatal ("LHEF: mismatch in event weight properties")
     end subroutine err_weights
     subroutine err_norm
       call msg_fatal ("LHEF: mismatch in event normalization")
     end subroutine err_norm
     subroutine err_beams
       call msg_fatal ("LHEF: mismatch in beam properties")
     end subroutine err_beams
     subroutine err_proc
       call msg_fatal ("LHEF: mismatch in process definitions")
     end subroutine err_proc
     subroutine err_n_evt
       call msg_error ("LHEF: mismatch in specified number of events (ignored)")
     end subroutine err_n_evt
   end subroutine eio_merge_data
 
 @ %def eio_merge_data
 @ Switch from input to output: reopen the file for reading.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: switch_inout => eio_lhef_switch_inout
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_switch_inout (eio, success)
+      class(eio_lhef_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_lhef_switch_inout
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_switch_inout (eio, success)
+  module subroutine eio_lhef_switch_inout (eio, success)
     class(eio_lhef_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("LHEF: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_lhef_switch_inout
 
 @ %def eio_lhef_switch_inout
 @ Split event file: increment the counter, close the current file, open a new
 one.  If the file needs a header, repeat it for the new file.  (We assume that
 the common block contents are still intact.)
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: split_out => eio_lhef_split_out
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_split_out (eio)
+      class(eio_lhef_t), intent(inout) :: eio
+    end subroutine eio_lhef_split_out
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_split_out (eio)
+  module subroutine eio_lhef_split_out (eio)
     class(eio_lhef_t), intent(inout) :: eio
     integer :: u
     if (eio%split) then
        eio%split_index = eio%split_index + 1
        call eio%set_filename ()
        write (msg_buffer, "(A,A,A)")  "Events: writing to LHEF file '", &
             char (eio%filename), "'"
        call msg_message ()
        call eio%write_footer ()
        u = eio%unit
        close (u)
        open (u, file = char (eio%filename), &
             action = "write", status = "replace")
        call eio%write_header ()
        call eio%tag_init%write (u);  write (u, *)
        call heprup_write_lhef (u)
        select case (eio%version)
        case ("2.0");  call eio%write_init_20 (eio%data)
        case ("3.0");  call eio%write_init_30 (eio%data)
        end select
        call eio%tag_init%close (u);  write (u, *)
     end if
   end subroutine eio_lhef_split_out
 
 @ %def eio_lhef_split_out
 @ Output an event.  Write first the event indices, then weight and
 squared matrix element, then the particle set.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: output => eio_lhef_output
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_lhef_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_lhef_output
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_output &
+  module subroutine eio_lhef_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_lhef_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     integer :: u
     u = given_output_unit (eio%unit);  if (u < 0)  return
     if (present (passed)) then
        if (.not. passed)  return
     end if
     if (eio%writing) then
        call hepeup_from_event (event, &
             process_index = eio%proc_num_id (i_prc), &
             keep_beams = eio%keep_beams, &
             keep_remnants = eio%keep_remnants)
        write (u, '(A)') "<event>"
        call hepeup_write_lhef (eio%unit)
        select case (eio%version)
          case ("2.0");  call eio%write_event_20 (event)
          case ("3.0");  call eio%write_event_30 (event)
        end select
        write (u, '(A)') "</event>"
     else
        call eio%write ()
        call msg_fatal ("LHEF file is not open for writing")
     end if
   end subroutine eio_lhef_output
 
 @ %def eio_lhef_output
 @ Input an event.  Upon input of [[i_prc]], we can just read in the
 whole HEPEUP common block.  These data are known to come first.  The
 [[i_prc]] value can be deduced from the IDPRUP value by a table
 lookup.
 
 Reading the common block bypasses the [[cstream]] which accesses the
 input unit.  This is consistent with the LHEF specification.  After
 the common-block data have been swallowed, we can resume reading from
 stream.
 
 We don't catch actual I/O errors.  However, we return a negative value in
 [[iostat]] if we reached the terminating [[</LesHouchesEvents>]] tag.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: input_i_prc => eio_lhef_input_i_prc
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_input_i_prc (eio, i_prc, iostat)
+      class(eio_lhef_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_lhef_input_i_prc
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_lhef_input_i_prc (eio, i_prc, iostat)
     class(eio_lhef_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     integer :: i, proc_num_id
     type(string_t) :: s
     logical :: ok
     iostat = 0
     call eio%tag_lhef%read_content (eio%cstream, s, ok)
     if (ok) then
        if (s == "") then
           iostat = -1
        else
           call err_close
        end if
        return
     else
        call eio%cstream%revert_record (s)
     end if
     call eio%tag_event%read (eio%cstream, ok)
     if (.not. ok) then
        call err_evt1
        return
     end if
     call hepeup_read_lhef (eio%unit)
     call hepeup_get_event_parameters (proc_id = proc_num_id)
     i_prc = 0
     FIND_I_PRC: do i = 1, size (eio%proc_num_id)
        if (eio%proc_num_id(i) == proc_num_id) then
           i_prc = i
           exit FIND_I_PRC
        end if
     end do FIND_I_PRC
     if (i_prc == 0)  call err_index
   contains
     subroutine err_close
       call msg_error ("LHEF: reading events: syntax error in closing tag")
       iostat = 1
     end subroutine
     subroutine err_evt1
       call msg_error ("LHEF: reading events: invalid event tag, &
            &aborting read")
       iostat = 2
     end subroutine err_evt1
     subroutine err_index
       call msg_error ("LHEF: reading events: undefined process ID " &
            // char (str (proc_num_id)) // ", aborting read")
       iostat = 3
     end subroutine err_index
   end subroutine eio_lhef_input_i_prc
 
 @ %def eio_lhef_input_i_prc
 @ Since we have already read the event information from file, this
 input routine can transfer the common-block contents to the event
 record.  Also, we read any further information in the event record.
 
-Since LHEF doesn't give this information, we must assume that the MCI
+Since LHEF does not give this information, we must assume that the MCI
 group, term, and channel can all be safely set to 1.  This works if
 there is only one MCI group and term.  The channel doesn't matter for
 the matrix element.
 
 The event index is incremented, as if the event was generated.  The
 LHEF format does not support event indices.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: input_event => eio_lhef_input_event
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_input_event (eio, event, iostat, event_handle)
+      class(eio_lhef_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_lhef_input_event
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_lhef_input_event (eio, event, iostat, event_handle)
     class(eio_lhef_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     type(string_t) :: s
     logical :: closing
     iostat = 0
     call event%reset_contents ()
     call event%select (1, 1, 1)
     call hepeup_to_event (event, eio%fallback_model, &
          recover_beams = eio%recover_beams, &
          use_alpha_s = eio%use_alphas_from_file, &
          use_scale = eio%use_scale_from_file)
     select case (eio%version)
     case ("1.0")
        call eio%tag_event%read_content (eio%cstream, s, closing = closing)
        if (s /= "" .or. .not. closing)  call err_evt2
     case ("2.0");  call eio%read_event_20 (event)
     case ("3.0");  call eio%read_event_30 (event)
     end select
     call event%increment_index ()
   contains
     subroutine err_evt2
       call msg_error ("LHEF: reading events: syntax error in event record, &
            &aborting read")
       iostat = 2
     end subroutine err_evt2
 
   end subroutine eio_lhef_input_event
 
 @ %def eio_lhef_input_event
 @
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: skip => eio_lhef_skip
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_skip (eio, iostat)
+      class(eio_lhef_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_lhef_skip
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_skip (eio, iostat)
+  module subroutine eio_lhef_skip (eio, iostat)
     class(eio_lhef_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     if (eio%reading) then
        read (eio%unit, iostat = iostat)
     else
        call eio%write ()
        call msg_fatal ("Raw event file is not open for reading")
     end if
   end subroutine eio_lhef_skip
 
 @ %def eio_lhef_skip
 @
 \subsection{Les Houches Event File: header/footer}
 These two routines write the header and footer for the Les Houches
 Event File format (LHEF).
 
 The current version writes no information except for the generator
 name and version (v.1.0 only).
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: write_header => eio_lhef_write_header
   procedure :: write_footer => eio_lhef_write_footer
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_write_header (eio, is_width)
+      class(eio_lhef_t), intent(in) :: eio
+      logical, intent(in), optional :: is_width
+    end subroutine eio_lhef_write_header
+    module subroutine eio_lhef_write_footer (eio)
+      class(eio_lhef_t), intent(in) :: eio
+    end subroutine eio_lhef_write_footer
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_write_header (eio, is_width)
+  module subroutine eio_lhef_write_header (eio, is_width)
     class(eio_lhef_t), intent(in) :: eio
     logical, intent(in), optional :: is_width
     logical :: is_w
     integer :: u
     u = given_output_unit (eio%unit);  if (u < 0)  return
     is_w = .false.
     if (present (is_width))  is_w = is_width
     call eio%tag_lhef%write (u);  write (u, *)
     call eio%tag_head%write (u);  write (u, *)
     select case (eio%version)
     case ("1.0")
        write (u, "(2x)", advance = "no")
        call eio%tag_gen_n%write (var_str ("WHIZARD"), u)
        write (u, *)
        write (u, "(2x)", advance = "no")
        call eio%tag_gen_v%write (var_str ("<<Version>>"), u)
        write (u, *)
     end select
     if (is_w) then
        call eio%tag_whiz_info%write (u); write (u, *)
        write (u, "(A)") &
             "#  Special LHE event setup for decays, units in GeV"
        call eio%tag_whiz_info%close (u); write (u, *)
     end if
     call eio%tag_head%close (u);  write (u, *)
   end subroutine eio_lhef_write_header
 
-  subroutine eio_lhef_write_footer (eio)
+  module subroutine eio_lhef_write_footer (eio)
     class(eio_lhef_t), intent(in) :: eio
     integer :: u
     u = given_output_unit (eio%unit);  if (u < 0)  return
     call eio%tag_lhef%close (u)
   end subroutine eio_lhef_write_footer
 
 @ %def eio_lhef_write_header eio_lhef_write_footer
 @ Reading the header just means finding the tags and ignoring any
 contents.  When done, we should stand just after the header tag.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: read_header => eio_lhef_read_header
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_read_header (eio)
+      class(eio_lhef_t), intent(inout) :: eio
+    end subroutine eio_lhef_read_header
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_read_header (eio)
+  module subroutine eio_lhef_read_header (eio)
     class(eio_lhef_t), intent(inout) :: eio
     logical :: success, closing
     type(string_t) :: content
     call eio%tag_lhef%read (eio%cstream, success)
     if (.not. success .or. .not. eio%tag_lhef%has_content)  call err_lhef
     if (eio%tag_lhef%get_attribute (1) /= eio%version)  call err_version
     call eio%tag_head%read (eio%cstream, success)
     if (.not. success)  call err_header
     if (eio%tag_head%has_content) then
        SKIP_HEADER_CONTENT: do
           call eio%tag_head%read_content (eio%cstream, content, closing)
           if (closing)  exit SKIP_HEADER_CONTENT
        end do SKIP_HEADER_CONTENT
     end if
   contains
     subroutine err_lhef
       call msg_fatal ("LHEF: LesHouchesEvents tag absent or corrupted")
     end subroutine err_lhef
     subroutine err_header
       call msg_fatal ("LHEF: header tag absent or corrupted")
     end subroutine err_header
     subroutine err_version
        call msg_error ("LHEF: version mismatch: expected " &
             // eio%version // ", found " &
             // char (eio%tag_lhef%get_attribute (1)))
     end subroutine err_version
   end subroutine eio_lhef_read_header
 
 @ %def eio_lhef_read_header
 @
 \subsection{Version-Specific Code: 1.0}
 In version 1.0, the init tag contains just HEPRUP data.  While a
 [[cstream]] is connected to the input unit, we bypass it temporarily
 for the purpose of reading the HEPRUP contents.  This is consistent
 with the LHEF standard.
 
 This routine does not read the closing tag of the init block.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: read_init_10 => eio_lhef_read_init_10
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_read_init_10 (eio, data)
+      class(eio_lhef_t), intent(in) :: eio
+      type(event_sample_data_t), intent(out) :: data
+    end subroutine eio_lhef_read_init_10
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_read_init_10 (eio, data)
+  module subroutine eio_lhef_read_init_10 (eio, data)
     class(eio_lhef_t), intent(in) :: eio
     type(event_sample_data_t), intent(out) :: data
     integer :: n_proc, i
     logical :: is_width
     call heprup_read_lhef (eio%unit)
     call heprup_get_run_parameters (n_processes = n_proc)
     call data%init (n_proc)
     if (IDBMUP(2) == 0) then
        data%n_beam = 1
        is_width = .true.
     else
        data%n_beam = 2
        is_width = .false.
     end if
     call heprup_get_run_parameters ( &
          unweighted = data%unweighted, &
          negative_weights = data%negative_weights, &
          beam_pdg = data%pdg_beam, &
          beam_energy = data%energy_beam)
     if (data%unweighted) then
        data%norm_mode = NORM_UNIT
     else
        data%norm_mode = NORM_SIGMA
     end if
     do i = 1, n_proc
        call heprup_get_process_parameters (i, &
             process_id = data%proc_num_id(i), &
             cross_section = data%cross_section(i), &
             error = data%error(i), &
             is_width = is_width)
     end do
   end subroutine eio_lhef_read_init_10
 
 @ %def eio_lhef_read_init_10
 @
 \subsection{Version-Specific Code: 2.0}
 This is the init information for the 2.0 format, after the HEPRUP
 data.  We have the following tags:
 \begin{itemize}
 \item \texttt{generator}  Generator name and version.
 \item \texttt{xsecinfo}  Cross section and weights data.  We have the
   total cross section and number of events (assuming that the event
   file is intact), but information on minimum and maximum weights is
   not available before the file is complete.  We just write the
   mandatory tags.  (Note that the default values of the other tags
   describe a uniform unit weight, but we can determine most values
   only after the sample is complete.)
 \item \texttt{cutsinfo}  This optional tag is too specific to represent the
   possibilities of WHIZARD, so we skip it.
 \item \texttt{procinfo}  This optional tag is useful for giving
   details of NLO calculations.  Skipped.
 \item \texttt{mergetype}  Optional, also not applicable.
 \end{itemize}
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: write_init_20 => eio_lhef_write_init_20
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_write_init_20 (eio, data)
+      class(eio_lhef_t), intent(in) :: eio
+      type(event_sample_data_t), intent(in) :: data
+    end subroutine eio_lhef_write_init_20
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_write_init_20 (eio, data)
+  module subroutine eio_lhef_write_init_20 (eio, data)
     class(eio_lhef_t), intent(in) :: eio
     type(event_sample_data_t), intent(in) :: data
     integer :: u
     u = eio%unit
     call eio%tag_generator%write (u)
     write (u, "(A)", advance="no")  "WHIZARD"
     call eio%tag_generator%close (u);  write (u, *)
     call eio%tag_xsecinfo%write (u);  write (u, *)
   end subroutine eio_lhef_write_init_20
 
 @ %def eio_lhef_write_init_20
 @ When reading the init block, we first call the 1.0 routine that
 fills HEPRUP.  Then we consider the possible tags.  Only the
 \texttt{generator} and \texttt{xsecinfo} tags are of interest.  We
 skip everything else except for the closing tag.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: read_init_20 => eio_lhef_read_init_20
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_read_init_20 (eio, data)
+      class(eio_lhef_t), intent(inout) :: eio
+      type(event_sample_data_t), intent(out) :: data
+    end subroutine eio_lhef_read_init_20
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_read_init_20 (eio, data)
+  module subroutine eio_lhef_read_init_20 (eio, data)
     class(eio_lhef_t), intent(inout) :: eio
     type(event_sample_data_t), intent(out) :: data
     real(default), parameter :: pb_per_fb = 1.e-3_default
     type(string_t) :: content
     logical :: found, closing
     call eio_lhef_read_init_10 (eio, data)
     SCAN_INIT_TAGS: do
        call eio%tag_generator%read (eio%cstream, found)
        if (found) then
           if (.not. eio%tag_generator%has_content)  call err_generator
           call eio%tag_generator%read_content (eio%cstream, content, closing)
           call msg_message ("LHEF: Event file has been generated by " &
                // char (content) // " " &
                // char (eio%tag_generator%get_attribute (1)))
           cycle SCAN_INIT_TAGS
        end if
        call eio%tag_xsecinfo%read (eio%cstream, found)
        if (found) then
           if (eio%tag_xsecinfo%has_content)  call err_xsecinfo
           cycle SCAN_INIT_TAGS
        end if
        call eio%tag_init%read_content (eio%cstream, content, closing)
        if (closing) then
           if (content /= "")  call err_init
           exit SCAN_INIT_TAGS
        end if
     end do SCAN_INIT_TAGS
     data%n_evt = &
          read_ival (eio%tag_xsecinfo%get_attribute (1))
     if (data%n_beam == 1) then
        data%total_cross_section = &
             read_rval (eio%tag_xsecinfo%get_attribute (2))
     else
        data%total_cross_section = &
             read_rval (eio%tag_xsecinfo%get_attribute (2)) / pb_per_fb
     end if
   contains
     subroutine err_generator
       call msg_fatal ("LHEF: invalid generator tag")
     end subroutine err_generator
     subroutine err_xsecinfo
       call msg_fatal ("LHEF: invalid xsecinfo tag")
     end subroutine err_xsecinfo
     subroutine err_init
       call msg_fatal ("LHEF: syntax error after init tag")
     end subroutine err_init
   end subroutine eio_lhef_read_init_20
 
 @ %def eio_lhef_read_init_20
 @ This is additional event-specific information for the 2.0 format,
 after the HEPEUP data.  We can specify weights, starting from the
 master weight and adding alternative weights.  The alternative weights
 are collected in a common tag.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: write_event_20 => eio_lhef_write_event_20
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_write_event_20 (eio, event)
+      class(eio_lhef_t), intent(in) :: eio
+      class(generic_event_t), intent(in) :: event
+    end subroutine eio_lhef_write_event_20
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_write_event_20 (eio, event)
+  module subroutine eio_lhef_write_event_20 (eio, event)
     class(eio_lhef_t), intent(in) :: eio
     class(generic_event_t), intent(in) :: event
     type(string_t) :: s
     integer :: i, u
     u = eio%unit
     if (eio%write_sqme_ref) then
        s = str (event%get_sqme_ref ())
        call eio%tag_sqme_ref%write (s, u);  write (u, *)
     end if
     if (eio%write_sqme_prc) then
        s = str (event%get_sqme_prc ())
        call eio%tag_sqme_prc%write (s, u);  write (u, *)
     end if
     if (eio%n_alt > 0) then
        if (eio%write_sqme_alt) then
           s = str (event%get_sqme_alt(1))
           do i = 2, eio%n_alt
              s = s // " " // str (event%get_sqme_alt(i));  write (u, *)
           end do
           call eio%tag_sqme_alt(1)%write (s, u)
        end if
        s = str (event%get_weight_alt(1))
        do i = 2, eio%n_alt
           s = s // " " // str (event%get_weight_alt(i));  write (u, *)
        end do
        call eio%tag_wgts_alt(1)%write (s, u)
     end if
   end subroutine eio_lhef_write_event_20
 
 @ %def eio_lhef_write_event_20
 @ Read extra event data.  If there is a weight entry labeled [[sqme_prc]], we
 take this as the squared matrix-element value (the new
 \emph{reference} value [[sqme_ref]]). Other tags, including
 tags written by the above writer, are skipped.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: read_event_20 => eio_lhef_read_event_20
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_read_event_20 (eio, event)
+      class(eio_lhef_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout) :: event
+    end subroutine eio_lhef_read_event_20
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_read_event_20 (eio, event)
+  module subroutine eio_lhef_read_event_20 (eio, event)
     class(eio_lhef_t), intent(inout) :: eio
     class(generic_event_t), intent(inout) :: event
     type(string_t) :: content
     logical :: found, closing
     SCAN_EVENT_TAGS: do
        call eio%tag_weight%read (eio%cstream, found)
        if (found) then
           if (.not. eio%tag_weight%has_content)  call err_weight
           call eio%tag_weight%read_content (eio%cstream, content, closing)
           if (.not. closing)  call err_weight
           if (eio%tag_weight%get_attribute (1) == "sqme_prc") then
              call event%set_sqme_ref (read_rval (content))
           end if
           cycle SCAN_EVENT_TAGS
        end if
        call eio%tag_event%read_content (eio%cstream, content, closing)
        if (closing) then
           if (content /= "")  call err_event
           exit SCAN_EVENT_TAGS
        end if
     end do SCAN_EVENT_TAGS
   contains
     subroutine err_weight
       call msg_fatal ("LHEF: invalid weight tag in event record")
     end subroutine err_weight
     subroutine err_event
       call msg_fatal ("LHEF: syntax error after event tag")
     end subroutine err_event
   end subroutine eio_lhef_read_event_20
 
 @ %def eio_lhef_read_event_20
 @
 \subsection{Version-Specific Code: 3.0}
 This is the init information for the 3.0 format, after the HEPRUP
 data.  We have the following tags:
 \begin{itemize}
 \item \texttt{generator}  Generator name and version.
 \item \texttt{xsecinfo}  Cross section and weights data.  We have the
   total cross section and number of events (assuming that the event
   file is intact), but information on minimum and maximum weights is
   not available before the file is complete.  We just write the
   mandatory tags.  (Note that the default values of the other tags
   describe a uniform unit weight, but we can determine most values
   only after the sample is complete.)
 \item \texttt{cutsinfo}  This optional tag is too specific to represent the
   possibilities of WHIZARD, so we skip it.
 \item \texttt{procinfo}  This optional tag is useful for giving
   details of NLO calculations.  Skipped.
 \item \texttt{weightinfo}  Determine the meaning of optional weights, whose
   values are given in the event record.
 \end{itemize}
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: write_init_30 => eio_lhef_write_init_30
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_write_init_30 (eio, data)
+      class(eio_lhef_t), intent(in) :: eio
+      type(event_sample_data_t), intent(in) :: data
+    end subroutine eio_lhef_write_init_30
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_write_init_30 (eio, data)
+  module subroutine eio_lhef_write_init_30 (eio, data)
     class(eio_lhef_t), intent(in) :: eio
     type(event_sample_data_t), intent(in) :: data
     integer :: u, i
     u = given_output_unit (eio%unit)
     call eio%tag_generator%write (u)
     write (u, "(A)", advance="no")  "WHIZARD"
-    call eiO%tag_generator%close (u);  write (u, *)
+    call eio%tag_generator%close (u);  write (u, *)
     call eio%tag_xsecinfo%write (u);  write (u, *)
     if (eio%write_sqme_ref) then
        call eio%tag_sqme_ref%write (u);  write (u, *)
     end if
     if (eio%write_sqme_prc) then
        call eio%tag_sqme_prc%write (u);  write (u, *)
     end if
     if (eio%write_sqme_alt) then
        do i = 1, eio%n_alt
           call eio%tag_sqme_alt(i)%write (u);  write (u, *)
        end do
     end if
     do i = 1, eio%n_alt
        call eio%tag_wgts_alt(i)%write (u);  write (u, *)
     end do
   end subroutine eio_lhef_write_init_30
 
 @ %def eio_lhef_write_init_30
 @ When reading the init block, we first call the 1.0 routine that
 fills HEPRUP.  Then we consider the possible tags.  Only the
 \texttt{generator} and \texttt{xsecinfo} tags are of interest.  We
 skip everything else except for the closing tag.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: read_init_30 => eio_lhef_read_init_30
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_read_init_30 (eio, data)
+      class(eio_lhef_t), intent(inout) :: eio
+      type(event_sample_data_t), intent(out) :: data
+    end subroutine eio_lhef_read_init_30
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_read_init_30 (eio, data)
+  module subroutine eio_lhef_read_init_30 (eio, data)
     class(eio_lhef_t), intent(inout) :: eio
     type(event_sample_data_t), intent(out) :: data
     real(default), parameter :: pb_per_fb = 1.e-3_default
     type(string_t) :: content
     logical :: found, closing
     integer :: n_weightinfo
     call eio_lhef_read_init_10 (eio, data)
     n_weightinfo = 0
     eio%i_weight_sqme = 0
     SCAN_INIT_TAGS: do
        call eio%tag_generator%read (eio%cstream, found)
        if (found) then
           if (.not. eio%tag_generator%has_content)  call err_generator
           call eio%tag_generator%read_content (eio%cstream, content, closing)
           call msg_message ("LHEF: Event file has been generated by " &
                // char (content) // " " &
                // char (eio%tag_generator%get_attribute (1)))
           cycle SCAN_INIT_TAGS
        end if
        call eio%tag_xsecinfo%read (eio%cstream, found)
        if (found) then
           if (eio%tag_xsecinfo%has_content)  call err_xsecinfo
           cycle SCAN_INIT_TAGS
        end if
        call eio%tag_weightinfo%read (eio%cstream, found)
        if (found) then
           if (eio%tag_weightinfo%has_content)  call err_xsecinfo
           n_weightinfo = n_weightinfo + 1
           if (eio%tag_weightinfo%get_attribute (1) == "sqme_prc") then
              eio%i_weight_sqme = n_weightinfo
           end if
           cycle SCAN_INIT_TAGS
        end if
        call eio%tag_init%read_content (eio%cstream, content, closing)
        if (closing) then
           if (content /= "")  call err_init
           exit SCAN_INIT_TAGS
        end if
     end do SCAN_INIT_TAGS
     data%n_evt = &
          read_ival (eio%tag_xsecinfo%get_attribute (1))
     if (data%n_beam == 1) then
        data%total_cross_section = &
             read_rval (eio%tag_xsecinfo%get_attribute (2))
     else
        data%total_cross_section = &
             read_rval (eio%tag_xsecinfo%get_attribute (2)) / pb_per_fb
     end if
   contains
     subroutine err_generator
       call msg_fatal ("LHEF: invalid generator tag")
     end subroutine err_generator
     subroutine err_xsecinfo
       call msg_fatal ("LHEF: invalid xsecinfo tag")
     end subroutine err_xsecinfo
     subroutine err_init
       call msg_fatal ("LHEF: syntax error after init tag")
     end subroutine err_init
   end subroutine eio_lhef_read_init_30
 
 @ %def eio_lhef_read_init_30
 @ This is additional event-specific information for the 3.0 format,
 after the HEPEUP data.  We can specify weights, starting from the
 master weight and adding alternative weights.  The weight tags are
 already allocated, so we just have to transfer the weight values to
 strings, assemble them and write them to file.  All weights are
 collected in a single tag.
 
 Note: If efficiency turns out to be an issue, we may revert to
 traditional character buffer writing.  However, we need to know the
 maximum length.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: write_event_30 => eio_lhef_write_event_30
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_write_event_30 (eio, event)
+      class(eio_lhef_t), intent(in) :: eio
+      class(generic_event_t), intent(in) :: event
+    end subroutine eio_lhef_write_event_30
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_write_event_30 (eio, event)
+  module subroutine eio_lhef_write_event_30 (eio, event)
     class(eio_lhef_t), intent(in) :: eio
     class(generic_event_t), intent(in) :: event
     type(string_t) :: s
     integer :: u, i
     u = eio%unit
     s = ""
     if (eio%write_sqme_ref) then
        s = s // str (event%get_sqme_ref ()) // " "
     end if
     if (eio%write_sqme_prc) then
        s = s // str (event%get_sqme_prc ()) // " "
     end if
     if (eio%n_alt > 0) then
        if (eio%write_sqme_alt) then
           s = s // str (event%get_sqme_alt(1)) // " "
           do i = 2, eio%n_alt
              s = s // str (event%get_sqme_alt(i)) // " "
           end do
        end if
        s = s // str (event%get_weight_alt(1)) // " "
        do i = 2, eio%n_alt
           s = s // str (event%get_weight_alt(i)) // " "
        end do
     end if
     if (len_trim (s) > 0) then
        call eio%tag_weights%write (trim (s), u);  write (u, *)
     end if
   end subroutine eio_lhef_write_event_30
 
 @ %def eio_lhef_write_event_30
 @ Read extra event data.  If there is a [[weights]] tag and if there
 was a [[weightinfo]] entry labeled [[sqme_prc]], we extract the
 corresponding entry from the weights string and store this as the
 event's  squared matrix-element value.  Other tags, including
 tags written by the above writer, are skipped.
 <<EIO LHEF: eio lhef: TBP>>=
   procedure :: read_event_30 => eio_lhef_read_event_30
+<<EIO LHEF: sub interfaces>>=
+    module subroutine eio_lhef_read_event_30 (eio, event)
+      class(eio_lhef_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout) :: event
+    end subroutine eio_lhef_read_event_30
 <<EIO LHEF: procedures>>=
-  subroutine eio_lhef_read_event_30 (eio, event)
+  module subroutine eio_lhef_read_event_30 (eio, event)
     class(eio_lhef_t), intent(inout) :: eio
     class(generic_event_t), intent(inout) :: event
     type(string_t) :: content, string
     logical :: found, closing
     integer :: i
     SCAN_EVENT_TAGS: do
        call eio%tag_weights%read (eio%cstream, found)
        if (found) then
           if (.not. eio%tag_weights%has_content)  call err_weights
           call eio%tag_weights%read_content (eio%cstream, content, closing)
           if (.not. closing)  call err_weights
           if (eio%i_weight_sqme > 0) then
              SCAN_WEIGHTS: do i = 1, eio%i_weight_sqme
                 call split (content, string, " ")
                 content = adjustl (content)
                 if (i == eio%i_weight_sqme) then
                    call event%set_sqme_ref (read_rval (string))
                    exit SCAN_WEIGHTS
                 end if
              end do SCAN_WEIGHTS
           end if
           cycle SCAN_EVENT_TAGS
        end if
        call eio%tag_event%read_content (eio%cstream, content, closing)
        if (closing) then
           if (content /= "")  call err_event
           exit SCAN_EVENT_TAGS
        end if
     end do SCAN_EVENT_TAGS
   contains
     subroutine err_weights
       call msg_fatal ("LHEF: invalid weights tag in event record")
     end subroutine err_weights
     subroutine err_event
       call msg_fatal ("LHEF: syntax error after event tag")
     end subroutine err_event
   end subroutine eio_lhef_read_event_30
 
 @ %def eio_lhef_read_event_30
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_lhef_ut.f90]]>>=
 <<File header>>
 
 module eio_lhef_ut
   use unit_tests
   use eio_lhef_uti
 
 <<Standard module head>>
 
 <<EIO LHEF: public test>>
 
 contains
 
 <<EIO LHEF: test driver>>
 
 end module eio_lhef_ut
 @ %def eio_lhef_ut
 @
 <<[[eio_lhef_uti.f90]]>>=
 <<File header>>
 
 module eio_lhef_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use model_data
   use event_base
   use eio_data
   use eio_base
 
   use eio_lhef
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
   use eio_base_ut, only: eio_prepare_fallback_model, eio_cleanup_fallback_model
 
 <<Standard module head>>
 
 <<EIO LHEF: test declarations>>
 
 contains
 
 <<EIO LHEF: tests>>
 
 end module eio_lhef_uti
 @ %def eio_lhef_ut
 @ API: driver for the unit tests below.
 <<EIO LHEF: public test>>=
   public :: eio_lhef_test
 <<EIO LHEF: test driver>>=
   subroutine eio_lhef_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO LHEF: execute tests>>
   end subroutine eio_lhef_test
 
 @ %def eio_lhef_test
 @
 \subsubsection{Version 1.0 Output}
 We test the implementation of all I/O methods.  We start with output
 according to version 1.0.
 <<EIO LHEF: execute tests>>=
   call test (eio_lhef_1, "eio_lhef_1", &
        "write version 1.0", &
        u, results)
 <<EIO LHEF: test declarations>>=
   public :: eio_lhef_1
 <<EIO LHEF: tests>>=
   subroutine eio_lhef_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_lhef_1"
     write (u, "(A)")  "*   Purpose: generate an event and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_lhef_1"
 
     allocate (eio_lhef_t :: eio)
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters ()
     end select
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // "." // eio%extension), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:21) == "  <generator_version>")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_lhef_t :: eio)
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters ()
     end select
 
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lhef_1"
 
   end subroutine eio_lhef_1
 
 @ %def eio_lhef_1
 @
 \subsubsection{Version 2.0 Output}
 Version 2.0 has added a lot of options to the LHEF format.  We
 implement some of them.
 <<EIO LHEF: execute tests>>=
   call test (eio_lhef_2, "eio_lhef_2", &
        "write version 2.0", &
        u, results)
 <<EIO LHEF: test declarations>>=
   public :: eio_lhef_2
 <<EIO LHEF: tests>>=
   subroutine eio_lhef_2 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_lhef_2"
     write (u, "(A)")  "*   Purpose: generate an event and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%unweighted = .false.
     data%norm_mode = NORM_SIGMA
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_lhef_2"
 
     allocate (eio_lhef_t :: eio)
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters (version = "2.0", write_sqme_prc = .true.)
     end select
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
 
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // "." // eio%extension), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:10) == "<generator")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lhef_2"
 
   end subroutine eio_lhef_2
 
 @ %def eio_lhef_2
 @
 \subsubsection{Version 3.0 Output}
 Version 3.0 is an update which removes some tags (which we didn't use anyway)
 and suggests a new treatment of weights.
 <<EIO LHEF: execute tests>>=
   call test (eio_lhef_3, "eio_lhef_3", &
        "write version 3.0", &
        u, results)
 <<EIO LHEF: test declarations>>=
   public :: eio_lhef_3
 <<EIO LHEF: tests>>=
   subroutine eio_lhef_3 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(80) :: buffer
 
     write (u, "(A)")  "* Test output: eio_lhef_3"
     write (u, "(A)")  "*   Purpose: generate an event and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%unweighted = .false.
     data%norm_mode = NORM_SIGMA
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_lhef_3"
 
     allocate (eio_lhef_t :: eio)
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters (version = "3.0", write_sqme_prc = .true.)
     end select
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
 
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents:"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".lhe"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (buffer(1:10) == "<generator")  buffer = "[...]"
        if (iostat /= 0)  exit
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lhef_3"
 
   end subroutine eio_lhef_3
 
 @ %def eio_lhef_3
 @
 \subsubsection{Version 1.0 Input}
 Check input of a version-1.0 conforming LHEF file.
 <<EIO LHEF: execute tests>>=
   call test (eio_lhef_4, "eio_lhef_4", &
        "read version 1.0", &
        u, results)
 <<EIO LHEF: test declarations>>=
   public :: eio_lhef_4
 <<EIO LHEF: tests>>=
   subroutine eio_lhef_4 (u)
     integer, intent(in) :: u
     class(model_data_t), pointer :: fallback_model
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_lhef_4"
     write (u, "(A)")  "*   Purpose: read a LHEF 1.0 file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Write a LHEF data file"
     write (u, "(A)")
 
     u_file = free_unit ()
     sample = "eio_lhef_4"
     open (u_file, file = char (sample // ".lhe"), &
          status = "replace", action = "readwrite")
 
     write (u_file, "(A)")  '<LesHouchesEvents version="1.0">'
     write (u_file, "(A)")  '<header>'
     write (u_file, "(A)")  '  <arbitrary_tag opt="foo">content</arbitrary_tag>'
     write (u_file, "(A)")  '  Text'
     write (u_file, "(A)")  '  <another_tag />'
     write (u_file, "(A)")  '</header>'
     write (u_file, "(A)")  '<init>'
     write (u_file, "(A)")  ' 25 25  5.0000000000E+02  5.0000000000E+02 &
          & -1 -1 -1 -1 3 1'
     write (u_file, "(A)")  '  1.0000000000E-01  1.0000000000E-03 &
          & 1.0000000000E+00 42'
     write (u_file, "(A)")  '</init>'
     write (u_file, "(A)")  '<event>'
     write (u_file, "(A)")  ' 4 42  3.0574068604E+08  1.0000000000E+03 &
          & -1.0000000000E+00 -1.0000000000E+00'
     write (u_file, "(A)")  ' 25 -1 0 0 0 0  0.0000000000E+00  0.0000000000E+00 &
          & 4.8412291828E+02  5.0000000000E+02  1.2500000000E+02 &
          & 0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 -1 0 0 0 0  0.0000000000E+00  0.0000000000E+00 &
          &-4.8412291828E+02  5.0000000000E+02  1.2500000000E+02 &
          & 0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 1 1 2 0 0 -1.4960220911E+02 -4.6042825611E+02 &
          & 0.0000000000E+00  5.0000000000E+02  1.2500000000E+02 &
          & 0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 1 1 2 0 0  1.4960220911E+02  4.6042825611E+02 &
          & 0.0000000000E+00  5.0000000000E+02  1.2500000000E+02 &
          & 0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  '</event>'
     write (u_file, "(A)")  '</LesHouchesEvents>'
     close (u_file)
 
 
     write (u, "(A)")  "* Initialize test process"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event, unweighted = .false.)
 
     allocate (eio_lhef_t :: eio)
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters (recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     call data%write (u)
     write (u, *)
 
     write (u, "(A)")  "* Initialize and read header"
     write (u, "(A)")
 
     call eio%init_in (sample, data)
     call eio%write (u)
 
     write (u, *)
 
     select type (eio)
     type is (eio_lhef_t)
        call eio%tag_lhef%write (u);  write (u, *)
     end select
 
     write (u, *)
     call data%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read event"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
 
     select type (eio)
     type is (eio_lhef_t)
        write (u, "(A,I0,A,I0)")  "Found process #", i_prc, &
             " with ID = ", eio%proc_num_id(i_prc)
     end select
 
     call eio%input_event (event, iostat)
 
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read closing"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(A,I0)")  "iostat = ", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lhef_4"
 
   end subroutine eio_lhef_4
 
 @ %def eio_lhef_4
 @
 \subsubsection{Version 2.0 Input}
 Check input of a version-2.0 conforming LHEF file.
 <<EIO LHEF: execute tests>>=
   call test (eio_lhef_5, "eio_lhef_5", &
        "read version 2.0", &
        u, results)
 <<EIO LHEF: test declarations>>=
   public :: eio_lhef_5
 <<EIO LHEF: tests>>=
   subroutine eio_lhef_5 (u)
     integer, intent(in) :: u
     class(model_data_t), pointer :: fallback_model
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_lhef_5"
     write (u, "(A)")  "*   Purpose: read a LHEF 2.0 file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Write a LHEF data file"
     write (u, "(A)")
 
     u_file = free_unit ()
     sample = "eio_lhef_5"
     open (u_file, file = char (sample // ".lhe"), &
          status = "replace", action = "readwrite")
 
     write (u_file, "(A)")  '<LesHouchesEvents version="2.0">'
     write (u_file, "(A)")  '<header>'
     write (u_file, "(A)")  '</header>'
     write (u_file, "(A)")  '<init>'
     write (u_file, "(A)")  ' 25 25  5.0000000000E+02  5.0000000000E+02 &
          &-1 -1 -1 -1 4 1'
     write (u_file, "(A)")  '  1.0000000000E-01  1.0000000000E-03 &
          & 0.0000000000E+00 42'
     write (u_file, "(A)")  '<generator version="2.2.3">WHIZARD&
          &</generator>'
     write (u_file, "(A)")  '<xsecinfo neve="1" totxsec="1.0000000000E-01" />'
     write (u_file, "(A)")  '</init>'
     write (u_file, "(A)")  '<event>'
     write (u_file, "(A)")  ' 4 42  3.0574068604E+08  1.0000000000E+03 &
          &-1.0000000000E+00 -1.0000000000E+00'
     write (u_file, "(A)")  ' 25 -1 0 0 0 0  0.0000000000E+00 &
          & 0.0000000000E+00  4.8412291828E+02  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 -1 0 0 0 0  0.0000000000E+00 &
          & 0.0000000000E+00 -4.8412291828E+02  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 1 1 2 0 0 -1.4960220911E+02 &
          &-4.6042825611E+02  0.0000000000E+00  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 1 1 2 0 0  1.4960220911E+02 &
          & 4.6042825611E+02  0.0000000000E+00  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  '<weight name="sqme_prc">1.0000000000E+00</weight>'
     write (u_file, "(A)")  '</event>'
     write (u_file, "(A)")  '</LesHouchesEvents>'
     close (u_file)
 
     write (u, "(A)")  "* Initialize test process"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event, unweighted = .false.)
 
     allocate (eio_lhef_t :: eio)
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters (version = "2.0", recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call data%init (1)
     data%unweighted = .false.
     data%norm_mode = NORM_SIGMA
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     call data%write (u)
     write (u, *)
 
     write (u, "(A)")  "* Initialize and read header"
     write (u, "(A)")
 
     call eio%init_in (sample, data)
     call eio%write (u)
 
     write (u, *)
 
     select type (eio)
     type is (eio_lhef_t)
        call eio%tag_lhef%write (u);  write (u, *)
     end select
 
     write (u, *)
     call data%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read event"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
 
     select type (eio)
     type is (eio_lhef_t)
        write (u, "(A,I0,A,I0)")  "Found process #", i_prc, &
             " with ID = ", eio%proc_num_id(i_prc)
     end select
 
     call eio%input_event (event, iostat)
 
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read closing"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(A,I0)")  "iostat = ", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lhef_5"
 
   end subroutine eio_lhef_5
 
 @ %def eio_lhef_5
 @
 \subsubsection{Version 3.0 Input}
 Check input of a version-3.0 conforming LHEF file.
 <<EIO LHEF: execute tests>>=
   call test (eio_lhef_6, "eio_lhef_6", &
        "read version 3.0", &
        u, results)
 <<EIO LHEF: test declarations>>=
   public :: eio_lhef_6
 <<EIO LHEF: tests>>=
   subroutine eio_lhef_6 (u)
     integer, intent(in) :: u
     class(model_data_t), pointer :: fallback_model
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_lhef_6"
     write (u, "(A)")  "*   Purpose: read a LHEF 3.0 file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Write a LHEF data file"
     write (u, "(A)")
 
     u_file = free_unit ()
     sample = "eio_lhef_6"
     open (u_file, file = char (sample // ".lhe"), &
          status = "replace", action = "readwrite")
 
     write (u_file, "(A)")  '<LesHouchesEvents version="3.0">'
     write (u_file, "(A)")  '<header>'
     write (u_file, "(A)")  '</header>'
     write (u_file, "(A)")  '<init>'
     write (u_file, "(A)")  ' 25 25  5.0000000000E+02  5.0000000000E+02 &
          &-1 -1 -1 -1 4 1'
     write (u_file, "(A)")  '  1.0000000000E-01  1.0000000000E-03 &
          & 0.0000000000E+00 42'
     write (u_file, "(A)")  '<generator version="2.2.3">WHIZARD&
          &</generator>'
     write (u_file, "(A)")  '<xsecinfo neve="1" totxsec="1.0000000000E-01" />'
     write (u_file, "(A)")  '<weightinfo name="sqme_prc" />'
     write (u_file, "(A)")  '</init>'
     write (u_file, "(A)")  '<event>'
     write (u_file, "(A)")  ' 4 42  3.0574068604E+08  1.0000000000E+03 &
          &-1.0000000000E+00 -1.0000000000E+00'
     write (u_file, "(A)")  ' 25 -1 0 0 0 0  0.0000000000E+00 &
          & 0.0000000000E+00  4.8412291828E+02  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 -1 0 0 0 0  0.0000000000E+00 &
          & 0.0000000000E+00 -4.8412291828E+02  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 1 1 2 0 0 -1.4960220911E+02 &
          &-4.6042825611E+02  0.0000000000E+00  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  ' 25 1 1 2 0 0  1.4960220911E+02 &
          & 4.6042825611E+02  0.0000000000E+00  5.0000000000E+02 &
          & 1.2500000000E+02  0.0000000000E+00  9.0000000000E+00'
     write (u_file, "(A)")  '<weights>1.0000000000E+00</weights>'
     write (u_file, "(A)")  '</event>'
     write (u_file, "(A)")  '</LesHouchesEvents>'
     close (u_file)
 
     write (u, "(A)")  "* Initialize test process"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event, unweighted = .false.)
 
     allocate (eio_lhef_t :: eio)
     select type (eio)
     type is (eio_lhef_t)
        call eio%set_parameters (version = "3.0", recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call data%init (1)
     data%unweighted = .false.
     data%norm_mode = NORM_SIGMA
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     call data%write (u)
     write (u, *)
 
     write (u, "(A)")  "* Initialize and read header"
     write (u, "(A)")
 
     call eio%init_in (sample, data)
     call eio%write (u)
 
     write (u, *)
 
     select type (eio)
     type is (eio_lhef_t)
        call eio%tag_lhef%write (u);  write (u, *)
     end select
 
     write (u, *)
     call data%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read event"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
 
     select type (eio)
     type is (eio_lhef_t)
        write (u, "(A,I0,A,I0)")  "Found process #", i_prc, &
             " with ID = ", eio%proc_num_id(i_prc)
     end select
 
     call eio%input_event (event, iostat)
 
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read closing"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(A,I0)")  "iostat = ", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lhef_6"
 
   end subroutine eio_lhef_6
 
 @ %def eio_lhef_6
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{STDHEP File Formats}
 Here, we implement the two existing STDHEP file formats, one based on the
 HEPRUP/HEPEUP common blocks, the other based on the HEPEVT common block.
 The second one is actually the standard STDHEP format.
 <<[[eio_stdhep.f90]]>>=
 <<File header>>
 
 module eio_stdhep
 
   use kinds, only: i32, i64
 <<Use strings>>
-  use io_units
-  use string_utils
-  use diagnostics
   use event_base
   use event_handles, only: event_handle_t
-  use hep_common
-  use hep_events
   use eio_data
   use eio_base
 
 <<Standard module head>>
 
 <<EIO stdhep: public>>
 
 <<EIO stdhep: types>>
 
+  interface
+<<EIO stdhep: sub interfaces>>
+  end interface
+
+end module eio_stdhep
+@ %def eio_stdhep
+@
+<<[[eio_stdhep_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_stdhep) eio_stdhep_s
+
+  use io_units
+  use string_utils
+  use diagnostics
+  use hep_common
+  use hep_events
+
+  implicit none
+
 <<EIO stdhep: variables>>
 
 contains
 
 <<EIO stdhep: procedures>>
 
-end module eio_stdhep
-@ %def eio_stdhep
+end submodule eio_stdhep_s
+
+@ %def eio_stdhep_s
 @
 \subsection{Type}
 <<EIO stdhep: public>>=
   public :: eio_stdhep_t
 <<EIO stdhep: types>>=
   type, abstract, extends (eio_t) :: eio_stdhep_t
      logical :: writing = .false.
      logical :: reading = .false.
      integer :: unit = 0
      logical :: keep_beams = .false.
      logical :: keep_remnants = .true.
      logical :: ensure_order = .false.
      logical :: recover_beams = .false.
      logical :: use_alphas_from_file = .false.
      logical :: use_scale_from_file = .false.
      integer, dimension(:), allocatable :: proc_num_id
      integer(i64) :: n_events_expected = 0
    contains
    <<EIO stdhep: eio stdhep: TBP>>
   end type eio_stdhep_t
 
 @ %def eio_stdhep_t
 @
 <<EIO stdhep: public>>=
   public :: eio_stdhep_hepevt_t
 <<EIO stdhep: types>>=
   type, extends (eio_stdhep_t) :: eio_stdhep_hepevt_t
   end type eio_stdhep_hepevt_t
 
 @ %def eio_stdhep_hepevt_t
 @
 <<EIO stdhep: public>>=
   public :: eio_stdhep_hepeup_t
 <<EIO stdhep: types>>=
   type, extends (eio_stdhep_t) :: eio_stdhep_hepeup_t
   end type eio_stdhep_hepeup_t
 
 @ %def eio_stdhep_hepeup_t
 @
 <<EIO stdhep: public>>=
   public :: eio_stdhep_hepev4_t
 <<EIO stdhep: types>>=
   type, extends (eio_stdhep_t) :: eio_stdhep_hepev4_t
   end type eio_stdhep_hepev4_t
 
 @ %def eio_stdhep_hepev4_t
 @
 \subsection{Specific Methods}
 Set parameters that are specifically used with STDHEP file formats.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: set_parameters => eio_stdhep_set_parameters
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_set_parameters (eio, &
+         keep_beams, keep_remnants, ensure_order, recover_beams, &
+         use_alphas_from_file, use_scale_from_file, extension)
+      class(eio_stdhep_t), intent(inout) :: eio
+      logical, intent(in), optional :: keep_beams
+      logical, intent(in), optional :: keep_remnants
+      logical, intent(in), optional :: ensure_order
+      logical, intent(in), optional :: recover_beams
+      logical, intent(in), optional :: use_alphas_from_file
+      logical, intent(in), optional :: use_scale_from_file
+      type(string_t), intent(in), optional :: extension
+    end subroutine eio_stdhep_set_parameters
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_set_parameters (eio, &
+  module subroutine eio_stdhep_set_parameters (eio, &
        keep_beams, keep_remnants, ensure_order, recover_beams, &
        use_alphas_from_file, use_scale_from_file, extension)
     class(eio_stdhep_t), intent(inout) :: eio
     logical, intent(in), optional :: keep_beams
     logical, intent(in), optional :: keep_remnants
     logical, intent(in), optional :: ensure_order
     logical, intent(in), optional :: recover_beams
     logical, intent(in), optional :: use_alphas_from_file
     logical, intent(in), optional :: use_scale_from_file
     type(string_t), intent(in), optional :: extension
     if (present (keep_beams))  eio%keep_beams = keep_beams
     if (present (keep_remnants))  eio%keep_remnants = keep_remnants
     if (present (ensure_order))  eio%ensure_order = ensure_order
     if (present (recover_beams))  eio%recover_beams = recover_beams
     if (present (use_alphas_from_file)) &
          eio%use_alphas_from_file = use_alphas_from_file
     if (present (use_scale_from_file))  &
          eio%use_scale_from_file = use_scale_from_file
     if (present (extension)) then
        eio%extension = extension
     else
        select type (eio)
        type is (eio_stdhep_hepevt_t)
           eio%extension = "hep"
        type is (eio_stdhep_hepev4_t)
           eio%extension = "ev4.hep"
        type is (eio_stdhep_hepeup_t)
           eio%extension = "up.hep"
        end select
     end if
   end subroutine eio_stdhep_set_parameters
 
 @ %def eio_ascii_stdhep_parameters
 @
 \subsection{Common Methods}
 Output.  This is not the actual event format, but a readable account
 of the current object status.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: write => eio_stdhep_write
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_write (object, unit)
+      class(eio_stdhep_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_stdhep_write
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_write (object, unit)
+  module subroutine eio_stdhep_write (object, unit)
     class(eio_stdhep_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "STDHEP event stream:"
     if (object%writing) then
        write (u, "(3x,A,A)")  "Writing to file   = ", char (object%filename)
     else if (object%reading) then
        write (u, "(3x,A,A)")  "Reading from file = ", char (object%filename)
     else
        write (u, "(3x,A)")  "[closed]"
     end if
     write (u, "(3x,A,L1)")    "Keep beams        = ", object%keep_beams
     write (u, "(3x,A,L1)")    "Keep remnants     = ", object%keep_remnants
     write (u, "(3x,A,L1)")    "Recover beams     = ", object%recover_beams
     write (u, "(3x,A,L1)")    "Alpha_s from file = ", &
          object%use_alphas_from_file
     write (u, "(3x,A,L1)")    "Scale from file   = ", &
          object%use_scale_from_file
     if (allocated (object%proc_num_id)) then
        write (u, "(3x,A)")  "Numerical process IDs:"
        do i = 1, size (object%proc_num_id)
           write (u, "(5x,I0,': ',I0)")  i, object%proc_num_id(i)
        end do
     end if
   end subroutine eio_stdhep_write
 
 @ %def eio_stdhep_write
 @ Finalizer: close any open file.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: final => eio_stdhep_final
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_final (object)
+      class(eio_stdhep_t), intent(inout) :: object
+    end subroutine eio_stdhep_final
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_final (object)
+  module subroutine eio_stdhep_final (object)
     class(eio_stdhep_t), intent(inout) :: object
     if (allocated (object%proc_num_id))  deallocate (object%proc_num_id)
     if (object%writing) then
        write (msg_buffer, "(A,A,A)")  "Events: closing STDHEP file '", &
             char (object%filename), "'"
        call msg_message ()
        call stdhep_write (200)
        call stdhep_end ()
        object%writing = .false.
     else if (object%reading) then
        write (msg_buffer, "(A,A,A)")  "Events: closing STDHEP file '", &
             char (object%filename), "'"
        call msg_message ()
        object%reading = .false.
     end if
   end subroutine eio_stdhep_final
 
 @ %def eio_stdhep_final
 @ Common initialization for input and output.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: common_init => eio_stdhep_common_init
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_common_init (eio, sample, data, extension)
+      class(eio_stdhep_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+    end subroutine eio_stdhep_common_init
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_common_init (eio, sample, data, extension)
+  module subroutine eio_stdhep_common_init (eio, sample, data, extension)
     class(eio_stdhep_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     if (.not. present (data)) &
          call msg_bug ("STDHEP initialization: missing data")
     if (present (extension)) then
        eio%extension = extension
     end if
     eio%sample = sample
     call eio%set_filename ()
     eio%unit = free_unit ()
     allocate (eio%proc_num_id (data%n_proc), source = data%proc_num_id)
   end subroutine eio_stdhep_common_init
 
 @ %def eio_stdhep_common_init
 @ Split event file: increment the counter, close the current file, open a new
 one.  If the file needs a header, repeat it for the new file.  (We assume that
 the common block contents are still intact.)
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: split_out => eio_stdhep_split_out
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_split_out (eio)
+      class(eio_stdhep_t), intent(inout) :: eio
+    end subroutine eio_stdhep_split_out
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_split_out (eio)
+  module subroutine eio_stdhep_split_out (eio)
     class(eio_stdhep_t), intent(inout) :: eio
     if (eio%split) then
        eio%split_index = eio%split_index + 1
        call eio%set_filename ()
        write (msg_buffer, "(A,A,A)")  "Events: writing to STDHEP file '", &
             char (eio%filename), "'"
        call msg_message ()
        call stdhep_write (200)
        call stdhep_end ()
        select type (eio)
        type is (eio_stdhep_hepeup_t)
           call stdhep_init_out (char (eio%filename), &
                "WHIZARD <<Version>>", eio%n_events_expected)
           call stdhep_write (100)
           call stdhep_write (STDHEP_HEPRUP)
        type is (eio_stdhep_hepevt_t)
           call stdhep_init_out (char (eio%filename), &
                "WHIZARD <<Version>>", eio%n_events_expected)
           call stdhep_write (100)
        type is (eio_stdhep_hepev4_t)
           call stdhep_init_out (char (eio%filename), &
                "WHIZARD <<Version>>", eio%n_events_expected)
           call stdhep_write (100)
        end select
     end if
   end subroutine eio_stdhep_split_out
 
 @ %def eio_stdhep_split_out
 @ Initialize event writing.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: init_out => eio_stdhep_init_out
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_stdhep_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_stdhep_init_out
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_init_out (eio, sample, data, success, extension)
+  module subroutine eio_stdhep_init_out &
+       (eio, sample, data, success, extension)
     class(eio_stdhep_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     logical :: is_width
     integer :: i
     if (.not. present (data)) &
          call msg_bug ("STDHEP initialization: missing data")
     is_width = data%n_beam == 1
     call eio%set_splitting (data)
     call eio%common_init (sample, data, extension)
     eio%n_events_expected = data%n_evt
     write (msg_buffer, "(A,A,A)")  "Events: writing to STDHEP file '", &
          char (eio%filename), "'"
     call msg_message ()
     eio%writing = .true.
     select type (eio)
     type is (eio_stdhep_hepeup_t)
        call heprup_init &
             (data%pdg_beam, &
             data%energy_beam, &
             n_processes = data%n_proc, &
             unweighted = data%unweighted, &
             negative_weights = data%negative_weights)
        do i = 1, data%n_proc
           call heprup_set_process_parameters (i = i, &
                process_id = data%proc_num_id(i), &
                cross_section = data%cross_section(i), &
                error = data%error(i), &
                is_width = is_width)
        end do
        call stdhep_init_out (char (eio%filename), &
             "WHIZARD <<Version>>", eio%n_events_expected)
        call stdhep_write (100)
        call stdhep_write (STDHEP_HEPRUP)
     type is (eio_stdhep_hepevt_t)
        call stdhep_init_out (char (eio%filename), &
             "WHIZARD <<Version>>", eio%n_events_expected)
        call stdhep_write (100)
     type is (eio_stdhep_hepev4_t)
        call stdhep_init_out (char (eio%filename), &
             "WHIZARD <<Version>>", eio%n_events_expected)
        call stdhep_write (100)
     end select
     if (present (success))  success = .true.
   end subroutine eio_stdhep_init_out
 
 @ %def eio_stdhep_init_out
 @ Initialize event reading.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: init_in => eio_stdhep_init_in
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_init_in &
+          (eio, sample, data, success, extension)
+      class(eio_stdhep_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_stdhep_init_in
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_init_in (eio, sample, data, success, extension)
+  module subroutine eio_stdhep_init_in &
+        (eio, sample, data, success, extension)
     class(eio_stdhep_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     integer :: ilbl, lok
     logical :: exist
     call eio%common_init (sample, data, extension)
     write (msg_buffer, "(A,A,A)")  "Events: reading from STDHEP file '", &
          char (eio%filename), "'"
     call msg_message ()
     inquire (file = char (eio%filename), exist = exist)
     if (.not. exist)  call msg_fatal ("Events: STDHEP file not found.")
     eio%reading = .true.
     call stdhep_init_in (char (eio%filename), eio%n_events_expected)
     call stdhep_read (ilbl, lok)
     if (lok /= 0) then
        call stdhep_end ()
        write (msg_buffer, "(A)")  "Events: STDHEP file appears to" // &
             " be empty."
        call msg_message ()
     end if
     if (ilbl == 100) then
        write (msg_buffer, "(A)")  "Events: reading in STDHEP events"
        call msg_message ()
     end if
     if (present (success))  success = .false.
   end subroutine eio_stdhep_init_in
 
 @ %def eio_stdhep_init_in
 @ Switch from input to output: reopen the file for reading.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: switch_inout => eio_stdhep_switch_inout
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_switch_inout (eio, success)
+      class(eio_stdhep_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_stdhep_switch_inout
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_switch_inout (eio, success)
+  module subroutine eio_stdhep_switch_inout (eio, success)
     class(eio_stdhep_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("STDHEP: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_stdhep_switch_inout
 
 @ %def eio_stdhep_switch_inout
 @ Output an event.  Write first the event indices, then weight and
 squared matrix element, then the particle set.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: output => eio_stdhep_output
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_stdhep_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_stdhep_output
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_output &
+  module subroutine eio_stdhep_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_stdhep_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     if (present (passed)) then
        if (.not. passed)  return
     end if
     if (eio%writing) then
        select type (eio)
        type is (eio_stdhep_hepeup_t)
           call hepeup_from_event (event, &
                process_index = eio%proc_num_id (i_prc), &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants)
           call stdhep_write (STDHEP_HEPEUP)
        type is (eio_stdhep_hepevt_t)
           call hepevt_from_event (event, &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order)
           call stdhep_write (STDHEP_HEPEVT)
        type is (eio_stdhep_hepev4_t)
           call hepevt_from_event (event, &
                process_index = eio%proc_num_id (i_prc), &
                keep_beams = eio%keep_beams, &
                keep_remnants = eio%keep_remnants, &
                ensure_order = eio%ensure_order, &
                fill_hepev4 = .true.)
           call stdhep_write (STDHEP_HEPEV4)
        end select
     else
        call eio%write ()
        call msg_fatal ("STDHEP file is not open for writing")
     end if
   end subroutine eio_stdhep_output
 
 @ %def eio_stdhep_output
 @ Input an event. We do not allow to read in STDHEP files written via
 the HEPEVT common block as there is no control on the process ID.
 This implies that the event index cannot be read; it is simply
 incremented to count the current event sample.
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: input_i_prc => eio_stdhep_input_i_prc
   procedure :: input_event => eio_stdhep_input_event
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_input_i_prc (eio, i_prc, iostat)
+      class(eio_stdhep_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_stdhep_input_i_prc
+    module subroutine eio_stdhep_input_event (eio, event, iostat, event_handle)
+      class(eio_stdhep_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_stdhep_input_event
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_stdhep_input_i_prc (eio, i_prc, iostat)
     class(eio_stdhep_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     integer :: i, ilbl, proc_num_id
     iostat = 0
     select type (eio)
     type is (eio_stdhep_hepevt_t)
        if (size (eio%proc_num_id) > 1) then
           call msg_fatal ("Events: only single processes allowed " // &
                "with the STDHEP HEPEVT format.")
        else
           proc_num_id = eio%proc_num_id (1)
           call stdhep_read (ilbl, lok)
        end if
     type is (eio_stdhep_hepev4_t)
        call stdhep_read (ilbl, lok)
        proc_num_id = idruplh
     type is (eio_stdhep_hepeup_t)
        call stdhep_read (ilbl, lok)
        if (lok /= 0)  call msg_error ("Events: STDHEP appears to be " // &
             "empty or corrupted.")
        if (ilbl == 12) then
           call stdhep_read (ilbl, lok)
        end if
        if (ilbl == 11) then
           proc_num_id = IDPRUP
        end if
     end select
     FIND_I_PRC: do i = 1, size (eio%proc_num_id)
        if (eio%proc_num_id(i) == proc_num_id) then
           i_prc = i
           exit FIND_I_PRC
        end if
     end do FIND_I_PRC
     if (i_prc == 0)  call err_index
   contains
     subroutine err_index
       call msg_error ("STDHEP: reading events: undefined process ID " &
            // char (str (proc_num_id)) // ", aborting read")
       iostat = 1
     end subroutine err_index
   end subroutine eio_stdhep_input_i_prc
 
-  subroutine eio_stdhep_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_stdhep_input_event (eio, event, iostat, event_handle)
     class(eio_stdhep_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     iostat = 0
     call event%reset_contents ()
     call event%select (1, 1, 1)
     call hepeup_to_event (event, eio%fallback_model, &
          recover_beams = eio%recover_beams, &
          use_alpha_s = eio%use_alphas_from_file, &
          use_scale = eio%use_scale_from_file)
     call event%increment_index ()
   end subroutine eio_stdhep_input_event
 
 @ %def eio_stdhep_input_i_prc
 @ %def eio_stdhep_input_event
 <<EIO stdhep: eio stdhep: TBP>>=
   procedure :: skip => eio_stdhep_skip
+<<EIO stdhep: sub interfaces>>=
+    module subroutine eio_stdhep_skip (eio, iostat)
+      class(eio_stdhep_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_stdhep_skip
 <<EIO stdhep: procedures>>=
-  subroutine eio_stdhep_skip (eio, iostat)
+  module subroutine eio_stdhep_skip (eio, iostat)
     class(eio_stdhep_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     if (eio%reading) then
        read (eio%unit, iostat = iostat)
     else
        call eio%write ()
        call msg_fatal ("Raw event file is not open for reading")
     end if
   end subroutine eio_stdhep_skip
 
 @ %def eio_stdhep_skip
 @ STDHEP speficic routines.
 <<EIO stdhep: public>>=
   public :: stdhep_init_out
   public :: stdhep_init_in
   public :: stdhep_write
   public :: stdhep_end
+<<EIO stdhep: sub interfaces>>=
+    module subroutine stdhep_init_out (file, title, nevt)
+      character(len=*), intent(in) :: file, title
+      integer(i64), intent(in) :: nevt
+    end subroutine stdhep_init_out
+    module subroutine stdhep_init_in (file, nevt)
+      character(len=*), intent(in) :: file
+      integer(i64), intent(out) :: nevt
+    end subroutine stdhep_init_in
+    module subroutine stdhep_write (ilbl)
+      integer, intent(in) :: ilbl
+    end subroutine stdhep_write
+    module subroutine stdhep_read (ilbl, lok)
+      integer, intent(out) :: ilbl, lok
+    end subroutine stdhep_read
+    module subroutine stdhep_end ()
+    end subroutine stdhep_end
 <<EIO stdhep: procedures>>=
-  subroutine stdhep_init_out (file, title, nevt)
+  module subroutine stdhep_init_out (file, title, nevt)
     character(len=*), intent(in) :: file, title
     integer(i64), intent(in) :: nevt
     integer(i32) :: nevt32
     nevt32 = min (nevt, int (huge (1_i32), i64))
     call stdxwinit (file, title, nevt32, istr, lok)
   end subroutine stdhep_init_out
 
-  subroutine stdhep_init_in (file, nevt)
+  module subroutine stdhep_init_in (file, nevt)
     character(len=*), intent(in) :: file
     integer(i64), intent(out) :: nevt
     integer(i32) :: nevt32
     call stdxrinit (file, nevt32, istr, lok)
     if (lok /= 0)  call msg_fatal ("STDHEP: error in reading file '" // &
          file // "'.")
     nevt = int (nevt32, i64)
   end subroutine stdhep_init_in
 
-  subroutine stdhep_write (ilbl)
+  module subroutine stdhep_write (ilbl)
     integer, intent(in) :: ilbl
     call stdxwrt (ilbl, istr, lok)
   end subroutine stdhep_write
 
-  subroutine stdhep_read (ilbl, lok)
+  module subroutine stdhep_read (ilbl, lok)
     integer, intent(out) :: ilbl, lok
     call stdxrd (ilbl, istr, lok)
     if (lok /= 0)  return
   end subroutine stdhep_read
 
-  subroutine stdhep_end
+  module subroutine stdhep_end ()
     call stdxend (istr)
   end subroutine stdhep_end
 
 @  %def stdhep_init stdhep_read stdhep_write stdhep_end
 @
 \subsection{Variables}
 <<EIO stdhep: variables>>=
   integer, save :: istr, lok
   integer, parameter :: &
        STDHEP_HEPEVT = 1, STDHEP_HEPEV4 = 4, &
        STDHEP_HEPEUP = 11, STDHEP_HEPRUP = 12
 @
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_stdhep_ut.f90]]>>=
 <<File header>>
 
 module eio_stdhep_ut
   use unit_tests
   use eio_stdhep_uti
 
 <<Standard module head>>
 
 <<EIO stdhep: public test>>
 
 contains
 
 <<EIO stdhep: test driver>>
 
 end module eio_stdhep_ut
 @ %def eio_stdhep_ut
 @
 <<[[eio_stdhep_uti.f90]]>>=
 <<File header>>
 
 module eio_stdhep_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use model_data
   use event_base
   use eio_data
   use eio_base
   use xdr_wo_stdhep
 
   use eio_stdhep
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
   use eio_base_ut, only: eio_prepare_fallback_model, eio_cleanup_fallback_model
 
 <<Standard module head>>
 
 <<EIO stdhep: test declarations>>
 
 contains
 
 <<EIO stdhep: tests>>
 
 end module eio_stdhep_uti
 @ %def eio_stdhep_ut
 @ API: driver for the unit tests below.
 <<EIO stdhep: public test>>=
   public :: eio_stdhep_test
 <<EIO stdhep: test driver>>=
   subroutine eio_stdhep_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO stdhep: execute tests>>
   end subroutine eio_stdhep_test
 
 @ %def eio_stdhep_test
 @
 \subsubsection{Test I/O methods}
 We test the implementation of the STDHEP HEPEVT I/O method:
 <<EIO stdhep: execute tests>>=
   call test (eio_stdhep_1, "eio_stdhep_1", &
        "read and write event contents, format [stdhep]", &
        u, results)
 <<EIO stdhep: test declarations>>=
   public :: eio_stdhep_1
 <<EIO stdhep: tests>>=
   subroutine eio_stdhep_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(215) :: buffer
 
     write (u, "(A)")  "* Test output: eio_stdhep_1"
     write (u, "(A)")  "*   Purpose: generate an event in STDHEP HEPEVT format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_stdhep_1"
 
     allocate (eio_stdhep_hepevt_t :: eio)
     select type (eio)
     type is (eio_stdhep_hepevt_t)
        call eio%set_parameters ()
     end select
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (61)  ! not supported by reader, actually
     call event%evaluate_expressions ()
     call event%pacify_particle_set ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Write STDHEP file contents to ASCII file"
     write (u, "(A)")
 
     call write_stdhep_event &
          (sample // ".hep", var_str ("eio_stdhep_1.hep.out"), 1)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read in ASCII contents of STDHEP file"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "eio_stdhep_1.hep.out", &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (iostat /= 0)  exit
        if (trim (buffer) == "")  cycle
        if (buffer(1:18) == "    total blocks: ")  &
             buffer = "    total blocks: [...]"
        if (buffer(1:25) == "           title: WHIZARD")  &
             buffer = "           title: WHIZARD [version]"
        if (buffer(1:17) == "            date:")  &
             buffer = "            date: [...]"
        if (buffer(1:17) == "    closing date:")  &
             buffer = "    closing date: [...]"
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_stdhep_hepevt_t :: eio)
 
     select type (eio)
     type is (eio_stdhep_hepevt_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_stdhep_1"
 
   end subroutine eio_stdhep_1
 
 @ %def eio_stdhep_1
 @
 We test the implementation of the STDHEP HEPEUP I/O method:
 <<EIO stdhep: execute tests>>=
   call test (eio_stdhep_2, "eio_stdhep_2", &
        "read and write event contents, format [stdhep]", &
        u, results)
 <<EIO stdhep: test declarations>>=
   public :: eio_stdhep_2
 <<EIO stdhep: tests>>=
   subroutine eio_stdhep_2 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(model_data_t), pointer :: fallback_model
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(215) :: buffer
 
     write (u, "(A)")  "* Test output: eio_stdhep_2"
     write (u, "(A)")  "*   Purpose: generate an event in STDHEP HEPEUP format"
     write (u, "(A)")  "*      and write weight to file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event, unweighted = .false.)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_stdhep_2"
 
     allocate (eio_stdhep_hepeup_t :: eio)
     select type (eio)
     type is (eio_stdhep_hepeup_t)
        call eio%set_parameters ()
     end select
     call eio%set_fallback_model (fallback_model)
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (62)  ! not supported by reader, actually
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Write STDHEP file contents to ASCII file"
     write (u, "(A)")
 
     call write_stdhep_event &
          (sample // ".up.hep", var_str ("eio_stdhep_2.hep.out"), 2)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read in ASCII contents of STDHEP file"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "eio_stdhep_2.hep.out", &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (iostat /= 0)  exit
        if (trim (buffer) == "")  cycle
        if (buffer(1:18) == "    total blocks: ")  &
             buffer = "    total blocks: [...]"
        if (buffer(1:25) == "           title: WHIZARD")  &
             buffer = "           title: WHIZARD [version]"
        if (buffer(1:17) == "            date:")  &
             buffer = "            date: [...]"
        if (buffer(1:17) == "    closing date:")  &
             buffer = "    closing date: [...]"
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_stdhep_hepeup_t :: eio)
 
     select type (eio)
     type is (eio_stdhep_hepeup_t)
        call eio%set_parameters (keep_beams = .true.)
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_stdhep_2"
 
   end subroutine eio_stdhep_2
 
 @ %def eio_stdhep_2
 @
 Check input from a StdHep file, HEPEVT block.
 <<EIO stdhep: execute tests>>=
   call test (eio_stdhep_3, "eio_stdhep_3", &
        "read StdHep file, HEPEVT block", &
        u, results)
 <<EIO stdhep: test declarations>>=
   public :: eio_stdhep_3
 <<EIO stdhep: tests>>=
   subroutine eio_stdhep_3 (u)
     integer, intent(in) :: u
     class(model_data_t), pointer :: fallback_model
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_stdhep_3"
     write (u, "(A)")  "*   Purpose: read a StdHep file, HEPEVT block"
     write (u, "(A)")
 
     write (u, "(A)")  "* Write a StdHep data file, HEPEVT block"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_stdhep_3"
 
     allocate (eio_stdhep_hepevt_t :: eio)
     select type (eio)
     type is (eio_stdhep_hepevt_t)
        call eio%set_parameters ()
     end select
     call eio%set_fallback_model (fallback_model)
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (63)  ! not supported by reader, actually
     call event%evaluate_expressions ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (eio)
     deallocate (fallback_model)
 
     write (u, "(A)")  "* Initialize test process"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event, unweighted = .false.)
 
     allocate (eio_stdhep_hepevt_t :: eio)
     select type (eio)
     type is (eio_stdhep_hepevt_t)
        call eio%set_parameters (recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     call data%write (u)
     write (u, *)
 
     write (u, "(A)")  "* Initialize"
     write (u, "(A)")
 
     call eio%init_in (sample, data)
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read event"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
 
     select type (eio)
     type is (eio_stdhep_hepevt_t)
        write (u, "(A,I0,A,I0)")  "Found process #", i_prc, &
             " with ID = ", eio%proc_num_id(i_prc)
     end select
 
     call eio%input_event (event, iostat)
 
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read closing"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(A,I0)")  "iostat = ", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_stdhep_3"
 
   end subroutine eio_stdhep_3
 
 @ %def eio_stdhep_3
 @
 Check input from a StdHep file, HEPEVT block.
 <<EIO stdhep: execute tests>>=
   call test (eio_stdhep_4, "eio_stdhep_4", &
        "read StdHep file, HEPRUP/HEPEUP block", &
        u, results)
 <<EIO stdhep: test declarations>>=
   public :: eio_stdhep_4
 <<EIO stdhep: tests>>=
   subroutine eio_stdhep_4 (u)
     integer, intent(in) :: u
     class(model_data_t), pointer :: fallback_model
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_stdhep_3"
     write (u, "(A)")  "*   Purpose: read a StdHep file, HEPRUP/HEPEUP block"
     write (u, "(A)")
 
     write (u, "(A)")  "* Write a StdHep data file, HEPRUP/HEPEUP block"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event)
 
     call data%init (1)
     data%n_evt = 1
     data%n_beam = 2
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event, HEPEUP/HEPRUP"
     write (u, "(A)")
 
     sample = "eio_stdhep_4"
 
     allocate (eio_stdhep_hepeup_t :: eio)
     select type (eio)
     type is (eio_stdhep_hepeup_t)
        call eio%set_parameters ()
     end select
     call eio%set_fallback_model (fallback_model)
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (64)   ! not supported by reader, actually
     call event%evaluate_expressions ()
     call event%pacify_particle_set ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (eio)
     deallocate (fallback_model)
 
     write (u, "(A)")  "* Initialize test process"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event, unweighted = .false.)
 
     allocate (eio_stdhep_hepeup_t :: eio)
     select type (eio)
     type is (eio_stdhep_hepeup_t)
        call eio%set_parameters (recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     call data%write (u)
     write (u, *)
 
     write (u, "(A)")  "* Initialize"
     write (u, "(A)")
 
     call eio%init_in (sample, data)
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read event"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
 
     select type (eio)
     type is (eio_stdhep_hepeup_t)
        write (u, "(A,I0,A,I0)")  "Found process #", i_prc, &
             " with ID = ", eio%proc_num_id(i_prc)
     end select
 
     call eio%input_event (event, iostat)
 
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read closing"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(A,I0)")  "iostat = ", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_stdhep_4"
 
   end subroutine eio_stdhep_4
 
 @ %def eio_stdhep_4
 @
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{HepMC Output}
 The HepMC event record is standardized.  It is an ASCII format.  We try
 our best at using it for both input and output.
 <<[[eio_hepmc.f90]]>>=
 <<File header>>
 
 module eio_hepmc
 
 <<Use kinds>>
 <<Use strings>>
-  use io_units
-  use string_utils
-  use diagnostics
-  use particles
-  use model_data
   use event_base
   use event_handles, only: event_handle_t
-  use hep_events
   use eio_data
   use eio_base
   use hepmc_interface
 
 <<Standard module head>>
 
 <<EIO HepMC: public>>
 
 <<EIO HepMC: types>>
 
+  interface
+<<EIO HepMC: sub interfaces>>
+  end interface
+
+end module eio_hepmc
+@ %def eio_hepmc
+@
+<<[[eio_hepmc_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_hepmc) eio_hepmc_s
+
+  use io_units
+  use string_utils
+  use diagnostics
+  use particles
+  use model_data
+  use hep_events
+
+  implicit none
+
 contains
 
 <<EIO HepMC: procedures>>
 
-end module eio_hepmc
-@ %def eio_hepmc
+end submodule eio_hepmc_s
+
+@ %def eio_hepmc_s
 @
 \subsection{Type}
 A type [[hepmc_event]] is introduced as container to store HepMC event
 data, particularly for splitting the reading into read out of the process
 index and the proper event data.
 
 Note: the [[keep_beams]] flag is not supported.  Beams will always
 be written.  Tools like \texttt{Rivet} can use the cross section
 information of a HepMC file for scaling plots.  As there is no header in
 HepMC and this is written for every event, we make it optional with
 [[output_cross_section]].
 <<EIO HepMC: public>>=
   public :: eio_hepmc_t
 <<EIO HepMC: types>>=
   type, extends (eio_t) :: eio_hepmc_t
      logical :: writing = .false.
      logical :: reading = .false.
      type(event_sample_data_t) :: data
      ! logical :: keep_beams = .false.
      logical :: recover_beams = .false.
      logical :: use_alphas_from_file = .false.
      logical :: use_scale_from_file = .false.
      logical :: output_cross_section = .false.
      integer :: hepmc3_mode = HEPMC3_MODE_HEPMC3
      logical :: hepmc3_flows = .false.
      type(hepmc_iostream_t) :: iostream
      type(hepmc_event_t) :: hepmc_event
      integer, dimension(:), allocatable :: proc_num_id
    contains
    <<EIO HepMC: eio hepmc: TBP>>
   end type eio_hepmc_t
 
 @ %def eio_hepmc_t
 @
 \subsection{Specific Methods}
 Set parameters that are specifically used with HepMC.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: set_parameters => eio_hepmc_set_parameters
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_set_parameters &
+         (eio, recover_beams, use_alphas_from_file, &
+         use_scale_from_file, extension, output_cross_section, &
+         hepmc3_mode, hepmc3_write_flows)
+      class(eio_hepmc_t), intent(inout) :: eio
+      logical, intent(in), optional :: recover_beams
+      logical, intent(in), optional :: use_alphas_from_file
+      logical, intent(in), optional :: use_scale_from_file
+      logical, intent(in), optional :: output_cross_section
+      type(string_t), intent(in), optional :: extension
+      integer, intent(in), optional :: hepmc3_mode
+      logical ,intent(in), optional :: hepmc3_write_flows
+    end subroutine eio_hepmc_set_parameters
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_set_parameters &
+  module subroutine eio_hepmc_set_parameters &
        (eio, recover_beams, use_alphas_from_file, &
        use_scale_from_file, extension, output_cross_section, &
        hepmc3_mode, hepmc3_write_flows)
     class(eio_hepmc_t), intent(inout) :: eio
     logical, intent(in), optional :: recover_beams
     logical, intent(in), optional :: use_alphas_from_file
     logical, intent(in), optional :: use_scale_from_file
     logical, intent(in), optional :: output_cross_section
     type(string_t), intent(in), optional :: extension
     integer, intent(in), optional :: hepmc3_mode
     logical ,intent(in), optional :: hepmc3_write_flows
     if (present (recover_beams)) &
          eio%recover_beams = recover_beams
     if (present (use_alphas_from_file)) &
          eio%use_alphas_from_file = use_alphas_from_file
     if (present (use_scale_from_file)) &
          eio%use_scale_from_file = use_scale_from_file
     if (present (extension)) then
        eio%extension = extension
     else
        eio%extension = "hepmc"
     end if
     if (present (output_cross_section)) &
          eio%output_cross_section = output_cross_section
     if (present (hepmc3_mode)) &
          eio%hepmc3_mode = hepmc3_mode
     if (present (hepmc3_write_flows)) &
          eio%hepmc3_flows = hepmc3_write_flows
   end subroutine eio_hepmc_set_parameters
 
 @ %def eio_hepmc_set_parameters
 @
 \subsection{Common Methods}
 Output.  This is not the actual event format, but a readable account
 of the current object status.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: write => eio_hepmc_write
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_write (object, unit)
+      class(eio_hepmc_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_hepmc_write
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_write (object, unit)
+  module subroutine eio_hepmc_write (object, unit)
     class(eio_hepmc_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "HepMC event stream:"
     if (object%writing) then
        write (u, "(3x,A,A)")  "Writing to file   = ", char (object%filename)
     else if (object%reading) then
        write (u, "(3x,A,A)")  "Reading from file = ", char (object%filename)
     else
        write (u, "(3x,A)")  "[closed]"
     end if
     write (u, "(3x,A,L1)")    "Recover beams     = ", object%recover_beams
     write (u, "(3x,A,L1)")    "Alpha_s from file = ", &
          object%use_alphas_from_file
     write (u, "(3x,A,L1)")    "Scale from file   = ", &
          object%use_scale_from_file
     write (u, "(3x,A,A,A)")     "File extension    = '", &
          char (object%extension), "'"
     write (u, "(3x,A,I0)")    "HepMC3 mode       = ", object%hepmc3_mode
     write (u, "(3x,A,L1)")    "HepMC3 flows      = ", object%hepmc3_flows
     if (allocated (object%proc_num_id)) then
        write (u, "(3x,A)")  "Numerical process IDs:"
        do i = 1, size (object%proc_num_id)
           write (u, "(5x,I0,': ',I0)")  i, object%proc_num_id(i)
        end do
     end if
   end subroutine eio_hepmc_write
 
 @ %def eio_hepmc_write
 @ Finalizer: close any open file.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: final => eio_hepmc_final
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_final (object)
+      class(eio_hepmc_t), intent(inout) :: object
+    end subroutine eio_hepmc_final
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_final (object)
+  module subroutine eio_hepmc_final (object)
     class(eio_hepmc_t), intent(inout) :: object
     if (allocated (object%proc_num_id))  deallocate (object%proc_num_id)
     if (object%writing) then
        write (msg_buffer, "(A,A,A)")  "Events: closing HepMC file '", &
             char (object%filename), "'"
        call msg_message ()
        call hepmc_iostream_close (object%iostream)
        object%writing = .false.
     else if (object%reading) then
        write (msg_buffer, "(A,A,A)")  "Events: closing HepMC file '", &
             char (object%filename), "'"
        call msg_message ()
        call hepmc_iostream_close (object%iostream)
        object%reading = .false.
     end if
   end subroutine eio_hepmc_final
 
 @ %def eio_hepmc_final
 @ Split event file: increment the counter, close the current file, open a new
 one.  If the file needs a header, repeat it for the new file.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: split_out => eio_hepmc_split_out
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_split_out (eio)
+      class(eio_hepmc_t), intent(inout) :: eio
+    end subroutine eio_hepmc_split_out
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_split_out (eio)
+  module subroutine eio_hepmc_split_out (eio)
     class(eio_hepmc_t), intent(inout) :: eio
     if (eio%split) then
        eio%split_index = eio%split_index + 1
        call eio%set_filename ()
        write (msg_buffer, "(A,A,A)")  "Events: writing to HepMC file '", &
             char (eio%filename), "'"
        call msg_message ()
        call hepmc_iostream_close (eio%iostream)
        call hepmc_iostream_open_out (eio%iostream, &
             eio%filename, eio%hepmc3_mode)
     end if
   end subroutine eio_hepmc_split_out
 
 @ %def eio_hepmc_split_out
 @ Common initialization for input and output.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: common_init => eio_hepmc_common_init
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_common_init (eio, sample, data, extension)
+      class(eio_hepmc_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+    end subroutine eio_hepmc_common_init
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_common_init (eio, sample, data, extension)
+  module subroutine eio_hepmc_common_init (eio, sample, data, extension)
     class(eio_hepmc_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     if (.not. present (data)) &
          call msg_bug ("HepMC initialization: missing data")
     eio%data = data
     ! We could relax this condition now with weighted hepmc events
     if (data%unweighted) then
        select case (data%norm_mode)
        case (NORM_UNIT)
        case default; call msg_fatal &
             ("HepMC: normalization for unweighted events must be '1'")
        end select
     end if
     eio%sample = sample
     if (present (extension)) then
        eio%extension = extension
     end if
     call eio%set_filename ()
     allocate (eio%proc_num_id (data%n_proc), source = data%proc_num_id)
   end subroutine eio_hepmc_common_init
 
 @ %def eio_hepmc_common_init
 @ Initialize event writing.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: init_out => eio_hepmc_init_out
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_init_out (eio, sample, data, success, extension)
+      class(eio_hepmc_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_hepmc_init_out
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_init_out (eio, sample, data, success, extension)
+  module subroutine eio_hepmc_init_out (eio, sample, data, success, extension)
     class(eio_hepmc_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     call eio%set_splitting (data)
     call eio%common_init (sample, data, extension)
     write (msg_buffer, "(A,A,A)")  "Events: writing to HepMC file '", &
          char (eio%filename), "'"
     call msg_message ()
     eio%writing = .true.
     call hepmc_iostream_open_out (eio%iostream, &
          eio%filename, eio%hepmc3_mode)
     if (present (success))  success = .true.
   end subroutine eio_hepmc_init_out
 
 @ %def eio_hepmc_init_out
 @ Initialize event reading. For input, we do not (yet) support split
 event files.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: init_in => eio_hepmc_init_in
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_init_in (eio, sample, data, success, extension)
+      class(eio_hepmc_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_hepmc_init_in
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_init_in (eio, sample, data, success, extension)
+  module subroutine eio_hepmc_init_in (eio, sample, data, success, extension)
     class(eio_hepmc_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     logical :: exist
     eio%split = .false.
     call eio%common_init (sample, data, extension)
     write (msg_buffer, "(A,A,A)")  "Events: reading from HepMC file '", &
          char (eio%filename), "'"
     call msg_message ()
     inquire (file = char (eio%filename), exist = exist)
     if (.not. exist)  call msg_fatal ("Events: HepMC file not found.")
     eio%reading = .true.
     call hepmc_iostream_open_in (eio%iostream, &
          eio%filename, eio%hepmc3_mode)
     if (present (success))  success = .true.
   end subroutine eio_hepmc_init_in
 
 @ %def eio_hepmc_init_in
 @ Switch from input to output: reopen the file for reading.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: switch_inout => eio_hepmc_switch_inout
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_switch_inout (eio, success)
+      class(eio_hepmc_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_hepmc_switch_inout
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_switch_inout (eio, success)
+  module subroutine eio_hepmc_switch_inout (eio, success)
     class(eio_hepmc_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("HepMC: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_hepmc_switch_inout
 
 @ %def eio_hepmc_switch_inout
 @ Output an event to the allocated HepMC output stream. For the
 moment, we set [[alpha_qed]] always to -1. There should be methods for
 the handling of $\alpha$ in [[me_methods]] in the same way as for
 $\alpha_s$.
 
 If an [[event_handle]] is in the argument list, and it is of the correct HepMC
 type, do not destroy the event but transfer it there (i.e., the enclosed C
 pointer).
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: output => eio_hepmc_output
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_hepmc_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_hepmc_output
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_output &
+  module subroutine eio_hepmc_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_hepmc_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     type(particle_set_t), pointer :: pset_ptr
     if (present (passed)) then
        if (.not. passed)  return
     end if
     if (eio%writing) then
        pset_ptr => event%get_particle_set_ptr ()
        call hepmc_event_init (eio%hepmc_event, &
             proc_id = eio%proc_num_id(i_prc), &
             event_id = event%get_index ())
        if (eio%output_cross_section .and. eio%data%n_beam == 2) then
           call hepmc_event_from_particle_set (eio%hepmc_event, pset_ptr, &
                eio%data%cross_section(i_prc), eio%data%error(i_prc), &
                color = eio%hepmc3_flows)
        else
           call hepmc_event_from_particle_set (eio%hepmc_event, pset_ptr, &
                color = eio%hepmc3_flows)
        end if
        call hepmc_event_set_scale (eio%hepmc_event, event%get_fac_scale ())
        call hepmc_event_set_alpha_qcd (eio%hepmc_event, event%get_alpha_s ())
        call hepmc_event_set_alpha_qed (eio%hepmc_event, -1._default)
        if (.not. eio%data%unweighted) then
           select case (eio%data%norm_mode)
           case (NORM_UNIT,NORM_N_EVT)
              call hepmc_event_add_weight &
                   (eio%hepmc_event, event%weight_prc, .false.)
           case default
              call hepmc_event_add_weight &
                   (eio%hepmc_event, event%weight_prc, .true.)
           end select
        end if
        call hepmc_iostream_write_event (eio%iostream, &
             eio%hepmc_event, eio%hepmc3_mode)
        call maybe_transfer_event_to_handle (eio%hepmc_event, event_handle)
        call hepmc_event_final (eio%hepmc_event)
     else
        call eio%write ()
        call msg_fatal ("HepMC file is not open for writing")
     end if
   end subroutine eio_hepmc_output
 
 @ %def eio_hepmc_output
 @ Input an event.
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: input_i_prc => eio_hepmc_input_i_prc
   procedure :: input_event => eio_hepmc_input_event
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_input_i_prc (eio, i_prc, iostat)
+      class(eio_hepmc_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_hepmc_input_i_prc
+    module subroutine eio_hepmc_input_event (eio, event, iostat, event_handle)
+      class(eio_hepmc_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_hepmc_input_event
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_hepmc_input_i_prc (eio, i_prc, iostat)
     class(eio_hepmc_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     logical :: ok
     integer :: i, proc_num_id
     iostat = 0
     call hepmc_event_init (eio%hepmc_event)
     call hepmc_iostream_read_event (eio%iostream, &
          eio%hepmc_event, ok=ok)
     proc_num_id = hepmc_event_get_process_id (eio%hepmc_event)
     if (.not. ok) then
        iostat = -1
        return
     end if
     i_prc = 0
     FIND_I_PRC: do i = 1, size (eio%proc_num_id)
        if (eio%proc_num_id(i) == proc_num_id) then
           i_prc = i
           exit FIND_I_PRC
        end if
     end do FIND_I_PRC
     if (i_prc == 0)  call err_index
   contains
     subroutine err_index
       call msg_error ("HepMC: reading events: undefined process ID " &
            // char (str (proc_num_id)) // ", aborting read")
       iostat = 1
     end subroutine err_index
   end subroutine eio_hepmc_input_i_prc
 
-  subroutine eio_hepmc_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_hepmc_input_event (eio, event, iostat, event_handle)
     class(eio_hepmc_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     iostat = 0
     call event%reset_contents ()
     call event%select (1, 1, 1)
     call hepmc_to_event (event, eio%hepmc_event, &
          eio%fallback_model, &
          recover_beams = eio%recover_beams, &
          use_alpha_s = eio%use_alphas_from_file, &
          use_scale = eio%use_scale_from_file)
     call maybe_transfer_event_to_handle (eio%hepmc_event, event_handle)
     call hepmc_event_final (eio%hepmc_event)
   end subroutine eio_hepmc_input_event
 
 @ %def eio_hepmc_input_i_prc
 @ %def eio_hepmc_input_event
 @
 If an [[event_handle]] is in the argument list, and it is of the correct HepMC
 type, do not destroy the event but transfer it to the handle (i.e., the
 enclosed C pointer).  Nullify the original pointer, so the event does not get
 destroyed.
 <<EIO HepMC: procedures>>=
   subroutine maybe_transfer_event_to_handle (hepmc_event, event_handle)
     type(hepmc_event_t), intent(inout) :: hepmc_event
     class(event_handle_t), intent(inout), optional :: event_handle
     if (present (event_handle)) then
        select type (event_handle)
        type is (hepmc_event_t)
           call hepmc_event_final (event_handle)  ! just in case
           event_handle = hepmc_event
           call hepmc_event_nullify (hepmc_event) ! avoid destructor call
        end select
     end if
   end subroutine maybe_transfer_event_to_handle
 
 @ %def transfer_event_to_handle
 @
 <<EIO HepMC: eio hepmc: TBP>>=
   procedure :: skip => eio_hepmc_skip
+<<EIO HepMC: sub interfaces>>=
+    module subroutine eio_hepmc_skip (eio, iostat)
+      class(eio_hepmc_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_hepmc_skip
 <<EIO HepMC: procedures>>=
-  subroutine eio_hepmc_skip (eio, iostat)
+  module subroutine eio_hepmc_skip (eio, iostat)
     class(eio_hepmc_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_hepmc_skip
 
 @ %def eio_hepmc_skip
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_hepmc_ut.f90]]>>=
 <<File header>>
 
 module eio_hepmc_ut
   use unit_tests
   use system_dependencies, only: HEPMC2_AVAILABLE
   use system_dependencies, only: HEPMC3_AVAILABLE
   use eio_hepmc_uti
 
 <<Standard module head>>
 
 <<EIO HepMC: public test>>
 
 contains
 
 <<EIO HepMC: test driver>>
 
 end module eio_hepmc_ut
 @ %def eio_hepmc_ut
 @
 <<[[eio_hepmc_uti.f90]]>>=
 <<File header>>
 
 module eio_hepmc_uti
 
 <<Use kinds>>
 <<Use strings>>
   use system_dependencies, only: HEPMC2_AVAILABLE
   use system_dependencies, only: HEPMC3_AVAILABLE
   use io_units
   use diagnostics
   use model_data
   use event_base
   use eio_data
   use eio_base
 
   use eio_hepmc
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
   use eio_base_ut, only: eio_prepare_fallback_model, eio_cleanup_fallback_model
 
 <<Standard module head>>
 
 <<EIO HepMC: test declarations>>
 
 contains
 
 <<EIO HepMC: tests>>
 
 end module eio_hepmc_uti
 @ %def eio_hepmc_ut
 @ API: driver for the unit tests below.
 <<EIO HepMC: public test>>=
   public :: eio_hepmc_test
 <<EIO HepMC: test driver>>=
   subroutine eio_hepmc_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO HepMC: execute tests>>
   end subroutine eio_hepmc_test
 
 @ %def eio_hepmc_test
 @
 \subsubsection{Test I/O methods}
 We test the implementation of all I/O methods.
 <<EIO HepMC: execute tests>>=
   if (HEPMC2_AVAILABLE) then
      call test (eio_hepmc_1, "eio_hepmc2_1", &
           "write event contents", &
           u, results)
   else if (HEPMC3_AVAILABLE) then
      call test (eio_hepmc_1, "eio_hepmc3_1", &
           "write event contents", &
           u, results)
   end if
 <<EIO HepMC: test declarations>>=
   public :: eio_hepmc_1
 <<EIO HepMC: tests>>=
   subroutine eio_hepmc_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(116) :: buffer
 
     write (u, "(A)")  "* Test output: eio_hepmc_1"
     write (u, "(A)")  "*   Purpose: write a HepMC file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted=.false.)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_hepmc_1"
 
     allocate (eio_hepmc_t :: eio)
     select type (eio)
     type is (eio_hepmc_t)
        call eio%set_parameters ()
     end select
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (55)
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents (blanking out last two digits):"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".hepmc"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (iostat /= 0)  exit
        if (trim (buffer) == "")  cycle
        if (buffer(1:14) == "HepMC::Version")  cycle
        if (HEPMC2_AVAILABLE) then
           if (buffer(1:10) == "P 10001 25") &
                call buffer_blanker (buffer, 32, 55, 78)
           if (buffer(1:10) == "P 10002 25") &
                call buffer_blanker (buffer, 33, 56, 79)
           if (buffer(1:10) == "P 10003 25") &
                call buffer_blanker (buffer, 29, 53, 78, 101)
           if (buffer(1:10) == "P 10004 25") &
                call buffer_blanker (buffer, 28, 51, 76, 99)
        else if (HEPMC3_AVAILABLE) then
           if (buffer(1:8) == "P 1 0 25") &
                call buffer_blanker (buffer, 26, 49, 72)
           if (buffer(1:8) == "P 2 0 25") &
                call buffer_blanker (buffer, 26, 49, 73)
           if (buffer(1:9) == "P 3 -1 25") &
                call buffer_blanker (buffer, 28, 52, 75)
           if (buffer(1:9) == "P 4 -1 25") &
                call buffer_blanker (buffer, 27, 50, 73)
        end if
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_hepmc_t :: eio)
 
     select type (eio)
     type is (eio_hepmc_t)
        call eio%set_parameters ()
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_hepmc_1"
 
   contains
 
     subroutine buffer_blanker (buf, pos1, pos2, pos3, pos4)
       character(len=*), intent(inout) :: buf
       integer, intent(in) :: pos1, pos2, pos3
       integer, intent(in), optional :: pos4
       type(string_t) :: line
       line = var_str (trim (buf))
       line = replace (line, pos1, "XX")
       line = replace (line, pos2, "XX")
       line = replace (line, pos3, "XX")
       if (present (pos4)) then
          line = replace (line, pos4, "XX")
       end if
       line = replace (line, "4999999999999", "5000000000000")
       buf = char (line)
     end subroutine buffer_blanker
 
   end subroutine eio_hepmc_1
 
 @ %def eio_hepmc_1
 @ Test also the reading of HepMC events.
 <<EIO HepMC: execute tests>>=
   if (HEPMC2_AVAILABLE) then
      call test (eio_hepmc_2, "eio_hepmc2_2", &
           "read event contents", &
           u, results)
   else if (HEPMC3_AVAILABLE) then
      call test (eio_hepmc_2, "eio_hepmc3_2", &
           "read event contents", &
           u, results)
   end if
 <<EIO HepMC: test declarations>>=
   public :: eio_hepmc_2
 <<EIO HepMC: tests>>=
   subroutine eio_hepmc_2 (u)
     integer, intent(in) :: u
     class(model_data_t), pointer :: fallback_model
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_hepmc_2"
     write (u, "(A)")  "*   Purpose: read a HepMC event"
     write (u, "(A)")
 
     write (u, "(A)")  "* Write a HepMC data file"
     write (u, "(A)")
 
     u_file = free_unit ()
     sample = "eio_hepmc_2"
     open (u_file, file = char (sample // ".hepmc"), &
          status = "replace", action = "readwrite")
 
     if (HEPMC2_AVAILABLE) then
        write (u_file, "(A)")  "HepMC::Version 2.06.09"
        write (u_file, "(A)")  "HepMC::IO_GenEvent-START_EVENT_LISTING"
        write (u_file, "(A)")  "E 66 -1 -1.0000000000000000e+00 &
             &-1.0000000000000000e+00 &
             &-1.0000000000000000e+00 42 0 1 10001 10002 0 0"
        write (u_file, "(A)")  "U GEV MM"
        write (u_file, "(A)")  "V -1 0 0 0 0 0 2 2 0"
        write (u_file, "(A)")  "P 10001 25 0 0 4.8412291827592713e+02 &
             &5.0000000000000000e+02 &
             &1.2499999999999989e+02 3 0 0 -1 0"
        write (u_file, "(A)")  "P 10002 25 0 0 -4.8412291827592713e+02 &
             &5.0000000000000000e+02 &
             &1.2499999999999989e+02 3 0 0 -1 0"
        write (u_file, "(A)")  "P 10003 25 -1.4960220911365536e+02 &
             &-4.6042825611414656e+02 &
             &0 5.0000000000000000e+02 1.2500000000000000e+02 1 0 0 0 0"
        write (u_file, "(A)")  "P 10004 25 1.4960220911365536e+02 &
             &4.6042825611414656e+02 &
             &0 5.0000000000000000e+02 1.2500000000000000e+02 1 0 0 0 0"
        write (u_file, "(A)")  "HepMC::IO_GenEvent-END_EVENT_LISTING"
     else if (HEPMC3_AVAILABLE) then
        write (u_file, "(A)")  "HepMC::Version 3.01.01"
        write (u_file, "(A)")  "HepMC::Asciiv3-START_EVENT_LISTING"
        write (u_file, "(A)")  "E 55 1 4"
        write (u_file, "(A)")  "U GEV MM"
        write (u_file, "(A)")  "A 0 alphaQCD -1"
        write (u_file, "(A)")  "A 0 event_scale 1000"
        write (u_file, "(A)")  "A 0 signal_process_id 42"
        write (u_file, "(A)")  "P 1 0 25 0.0000000000000000e+00 &
             &0.0000000000000000e+00 4.8412291827592713e+02 &
             &5.0000000000000000e+02 1.2499999999999989e+02 3"
        write (u_file, "(A)")  "P 2 0 25 0.0000000000000000e+00 &
             &0.0000000000000000e+00 -4.8412291827592713e+02 &
             &5.0000000000000000e+02 1.2499999999999989e+02 3"
        write (u_file, "(A)")  "V -1 0 [1,2]"
        write (u_file, "(A)")  "P 3 -1 25 -1.4960220911365536e+02 &
             &-4.6042825611414656e+02 0.0000000000000000e+00 &
             &5.0000000000000000e+02 1.2500000000000000e+02 1"
        write (u_file, "(A)")  "P 4 -1 25 1.4960220911365536e+02 &
             &4.6042825611414656e+02 0.0000000000000000e+00 &
             &5.0000000000000000e+02 1.2500000000000000e+02 1"
        write (u_file, "(A)")  "HepMC::Asciiv3-END_EVENT_LISTING"
     else
        call msg_fatal &
             ("Trying to execute eio_hepmc unit tests without a linked HepMC")
     end if
     close (u_file)
 
     write (u, "(A)")  "* Initialize test process"
     write (u, "(A)")
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event, unweighted=.false.)
 
     allocate (eio_hepmc_t :: eio)
     select type (eio)
     type is (eio_hepmc_t)
        call eio%set_parameters (recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     call data%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Initialize"
     write (u, "(A)")
 
     call eio%init_in (sample, data)
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read event"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
 
     select type (eio)
     type is (eio_hepmc_t)
        write (u, "(A,I0,A,I0)")  "Found process #", i_prc, &
             " with ID = ", eio%proc_num_id(i_prc)
     end select
 
     call eio%input_event (event, iostat)
 
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read closing"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(A,I0)")  "iostat = ", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_hepmc_2"
 
   end subroutine eio_hepmc_2
 
 @ %def eio_hepmc_2
 @
 Test also the correct normalization of weighted HepMC events.
 <<EIO HepMC: execute tests>>=
   if (HEPMC2_AVAILABLE) then
      call test (eio_hepmc_3, "eio_hepmc2_3", &
           "write event contents", &
           u, results)
   else if (HEPMC3_AVAILABLE) then
      call test (eio_hepmc_3, "eio_hepmc3_3", &
           "event contents weighted, '1' normalization", &
           u, results)
   end if
 <<EIO HepMC: test declarations>>=
   public :: eio_hepmc_3
 <<EIO HepMC: tests>>=
   subroutine eio_hepmc_3 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: u_file, iostat
     character(126) :: buffer
 
     write (u, "(A)")  "* Test output: eio_hepmc_3"
     write (u, "(A)")  "*   Purpose: test correct HepMC normalization"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event, unweighted=.false., &
          sample_norm = var_str ("1"))
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .false.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 20
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_hepmc_3"
 
     allocate (eio_hepmc_t :: eio)
     select type (eio)
     type is (eio_hepmc_t)
        call eio%set_parameters ()
     end select
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (55)
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* File contents (blanking out last two digits):"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = char (sample // ".hepmc"), &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (iostat /= 0)  exit
        if (trim (buffer) == "")  cycle
        if (buffer(1:14) == "HepMC::Version")  cycle
        if (HEPMC2_AVAILABLE) then
           if (buffer(1:4) == "E 55") then
              buffer = replace (buffer, 113, "XXXXXXXXX")
           end if
           if (buffer(1:10) == "P 10001 25") &
                call buffer_blanker (buffer, 32, 55, 78)
           if (buffer(1:10) == "P 10002 25") &
                call buffer_blanker (buffer, 33, 56, 79)
           if (buffer(1:10) == "P 10003 25") &
                call buffer_blanker (buffer, 29, 53, 78, 101)
           if (buffer(1:10) == "P 10004 25") &
                call buffer_blanker (buffer, 28, 51, 76, 99)
        else if (HEPMC3_AVAILABLE) then
           if (buffer(1:4) == "W 3.") then
              buffer = replace (buffer, 11, "XXXXXXXXXXXXXXXX")
           end if
           if (buffer(1:8) == "P 1 0 25") &
                call buffer_blanker (buffer, 26, 49, 72, 118)
           if (buffer(1:8) == "P 2 0 25") &
                call buffer_blanker (buffer, 26, 49, 73, 119)
           if (buffer(1:9) == "P 3 -1 25") &
                call buffer_blanker (buffer, 28, 52, 75, 121)
           if (buffer(1:9) == "P 4 -1 25") &
                call buffer_blanker (buffer, 27, 50, 73, 119)
        end if
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_hepmc_t :: eio)
 
     select type (eio)
     type is (eio_hepmc_t)
        call eio%set_parameters ()
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_hepmc_3"
 
   contains
 
     subroutine buffer_blanker (buf, pos1, pos2, pos3, pos4)
       character(len=*), intent(inout) :: buf
       integer, intent(in) :: pos1, pos2, pos3
       integer, intent(in), optional :: pos4
       type(string_t) :: line
       line = var_str (trim (buf))
       line = replace (line, pos1, "XX")
       line = replace (line, pos2, "XX")
       line = replace (line, pos3, "XX")
       if (present (pos4)) then
          line = replace (line, pos4, "XX")
       end if
       line = replace (line, "4999999999999", "5000000000000")
       buf = char (line)
     end subroutine buffer_blanker
 
   end subroutine eio_hepmc_3
 
 @ %def eio_hepmc_3
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{LCIO Output}
 The LCIO event record is standardized for the use with Linear $e^+e^-$
 colliders. It is a binary event format.  We try our best at using it
 for both input and output.
 <<[[eio_lcio.f90]]>>=
 <<File header>>
 
 module eio_lcio
 
 <<Use kinds>>
 <<Use strings>>
-  use io_units
-  use string_utils
-  use diagnostics
-  use particles
   use event_base
   use event_handles, only: event_handle_t
-  use hep_events
   use eio_data
   use eio_base
   use lcio_interface
 
 <<Standard module head>>
 
 <<EIO LCIO: public>>
 
 <<EIO LCIO: types>>
 
+  interface
+<<EIO LCIO: sub interfaces>>
+  end interface
+
+end module eio_lcio
+@ %def eio_lcio
+@
+<<[[eio_lcio_sub.f90]]>>=
+<<File header>>
+
+submodule (eio_lcio) eio_lcio_s
+
+  use io_units
+  use string_utils
+  use diagnostics
+  use particles
+  use hep_events
+
+  implicit none
+
 contains
 
 <<EIO LCIO: procedures>>
 
-end module eio_lcio
-@ %def eio_lcio
+end submodule eio_lcio_s
+
+@ %def eio_lcio_s
 @
 \subsection{Type}
 A type [[lcio_event]] is introduced as container to store LCIO event
 data, particularly for splitting the reading into read out of the process
 index and the proper event data.
 
 Note: the [[keep_beams]] flag is not supported.
 <<EIO LCIO: public>>=
   public :: eio_lcio_t
 <<EIO LCIO: types>>=
   type, extends (eio_t) :: eio_lcio_t
      logical :: writing = .false.
      logical :: reading = .false.
      type(event_sample_data_t) :: data
      logical :: recover_beams = .false.
      logical :: use_alphas_from_file = .false.
      logical :: use_scale_from_file = .false.
      logical :: proc_as_run_id = .true.
      integer :: n_alt = 0
      integer :: lcio_run_id = 0
      type(lcio_writer_t) :: lcio_writer
      type(lcio_reader_t) :: lcio_reader
      type(lcio_run_header_t) :: lcio_run_hdr
      type(lcio_event_t) :: lcio_event
      integer, dimension(:), allocatable :: proc_num_id
    contains
    <<EIO LCIO: eio lcio: TBP>>
   end type eio_lcio_t
 
 @ %def eio_lcio_t
 @
 \subsection{Specific Methods}
 Set parameters that are specifically used with LCIO.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: set_parameters => eio_lcio_set_parameters
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_set_parameters &
+         (eio, recover_beams, use_alphas_from_file, use_scale_from_file, &
+         extension, proc_as_run_id, lcio_run_id)
+      class(eio_lcio_t), intent(inout) :: eio
+      logical, intent(in), optional :: recover_beams
+      logical, intent(in), optional :: use_alphas_from_file
+      logical, intent(in), optional :: use_scale_from_file
+      logical, intent(in), optional :: proc_as_run_id
+      integer, intent(in), optional :: lcio_run_id
+      type(string_t), intent(in), optional :: extension
+    end subroutine eio_lcio_set_parameters
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_set_parameters &
+  module subroutine eio_lcio_set_parameters &
        (eio, recover_beams, use_alphas_from_file, use_scale_from_file, &
        extension, proc_as_run_id, lcio_run_id)
     class(eio_lcio_t), intent(inout) :: eio
     logical, intent(in), optional :: recover_beams
     logical, intent(in), optional :: use_alphas_from_file
     logical, intent(in), optional :: use_scale_from_file
     logical, intent(in), optional :: proc_as_run_id
     integer, intent(in), optional :: lcio_run_id
     type(string_t), intent(in), optional :: extension
     if (present (recover_beams))  eio%recover_beams = recover_beams
     if (present (use_alphas_from_file)) &
          eio%use_alphas_from_file = use_alphas_from_file
     if (present (use_scale_from_file)) &
          eio%use_scale_from_file = use_scale_from_file
     if (present (proc_as_run_id)) &
          eio%proc_as_run_id = proc_as_run_id
     if (present (lcio_run_id)) &
          eio%lcio_run_id = lcio_run_id
     if (present (extension)) then
        eio%extension = extension
     else
        eio%extension = "slcio"
     end if
   end subroutine eio_lcio_set_parameters
 
 @ %def eio_lcio_set_parameters
 @
 \subsection{Common Methods}
 Output.  This is not the actual event format, but a readable account
 of the current object status.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: write => eio_lcio_write
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_write (object, unit)
+      class(eio_lcio_t), intent(in) :: object
+      integer, intent(in), optional :: unit
+    end subroutine eio_lcio_write
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_write (object, unit)
+  module subroutine eio_lcio_write (object, unit)
     class(eio_lcio_t), intent(in) :: object
     integer, intent(in), optional :: unit
     integer :: u, i
     u = given_output_unit (unit)
     write (u, "(1x,A)")  "LCIO event stream:"
     if (object%writing) then
        write (u, "(3x,A,A)")  "Writing to file   = ", char (object%filename)
     else if (object%reading) then
        write (u, "(3x,A,A)")  "Reading from file = ", char (object%filename)
     else
        write (u, "(3x,A)")  "[closed]"
     end if
     write (u, "(3x,A,L1)")    "Recover beams     = ", object%recover_beams
     write (u, "(3x,A,L1)")    "Alpha_s from file = ", &
          object%use_alphas_from_file
     write (u, "(3x,A,L1)")    "Scale from file   = ", &
          object%use_scale_from_file
     write (u, "(3x,A,L1)")    "Process as run ID = ", &
          object%proc_as_run_id
     write (u, "(3x,A,I0)")    "LCIO run ID       = ", &
          object%lcio_run_id
     write (u, "(3x,A,A,A)")     "File extension    = '", &
          char (object%extension), "'"
     if (allocated (object%proc_num_id)) then
        write (u, "(3x,A)")  "Numerical process IDs:"
        do i = 1, size (object%proc_num_id)
           write (u, "(5x,I0,': ',I0)")  i, object%proc_num_id(i)
        end do
     end if
   end subroutine eio_lcio_write
 
 @ %def eio_lcio_write
 @ Finalizer: close any open file.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: final => eio_lcio_final
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_final (object)
+      class(eio_lcio_t), intent(inout) :: object
+    end subroutine eio_lcio_final
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_final (object)
+  module subroutine eio_lcio_final (object)
     class(eio_lcio_t), intent(inout) :: object
     if (allocated (object%proc_num_id))  deallocate (object%proc_num_id)
     if (object%writing) then
        write (msg_buffer, "(A,A,A)")  "Events: closing LCIO file '", &
             char (object%filename), "'"
        call msg_message ()
        call lcio_writer_close (object%lcio_writer)
        object%writing = .false.
     else if (object%reading) then
        write (msg_buffer, "(A,A,A)")  "Events: closing LCIO file '", &
             char (object%filename), "'"
        call msg_message ()
        call lcio_reader_close (object%lcio_reader)
        object%reading = .false.
     end if
   end subroutine eio_lcio_final
 
 @ %def eio_lcio_final
 @ Split event file: increment the counter, close the current file, open a new
 one.  If the file needs a header, repeat it for the new file.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: split_out => eio_lcio_split_out
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_split_out (eio)
+      class(eio_lcio_t), intent(inout) :: eio
+    end subroutine eio_lcio_split_out
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_split_out (eio)
+  module subroutine eio_lcio_split_out (eio)
     class(eio_lcio_t), intent(inout) :: eio
     if (eio%split) then
        eio%split_index = eio%split_index + 1
        call eio%set_filename ()
        write (msg_buffer, "(A,A,A)")  "Events: writing to LCIO file '", &
             char (eio%filename), "'"
        call msg_message ()
        call lcio_writer_close (eio%lcio_writer)
        call lcio_writer_open_out (eio%lcio_writer, eio%filename)
     end if
   end subroutine eio_lcio_split_out
 
 @ %def eio_lcio_split_out
 @ Common initialization for input and output.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: common_init => eio_lcio_common_init
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_common_init (eio, sample, data, extension)
+      class(eio_lcio_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+    end subroutine eio_lcio_common_init
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_common_init (eio, sample, data, extension)
+  module subroutine eio_lcio_common_init (eio, sample, data, extension)
     class(eio_lcio_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     if (.not. present (data)) &
          call msg_bug ("LCIO initialization: missing data")
     eio%data = data
     if (data%unweighted) then
        select case (data%norm_mode)
        case (NORM_UNIT)
        case default; call msg_fatal &
             ("LCIO: normalization for unweighted events must be '1'")
        end select
     else
        call msg_fatal ("LCIO: events must be unweighted")
     end if
     eio%n_alt = data%n_alt
     eio%sample = sample
     if (present (extension)) then
        eio%extension = extension
     end if
     call eio%set_filename ()
     allocate (eio%proc_num_id (data%n_proc), source = data%proc_num_id)
   end subroutine eio_lcio_common_init
 
 @ %def eio_lcio_common_init
 @ Initialize event writing.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: init_out => eio_lcio_init_out
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_init_out &
+         (eio, sample, data, success, extension)
+      class(eio_lcio_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(in), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_lcio_init_out
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_init_out (eio, sample, data, success, extension)
+  module subroutine eio_lcio_init_out &
+       (eio, sample, data, success, extension)
     class(eio_lcio_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(in), optional :: data
     logical, intent(out), optional :: success
     call eio%set_splitting (data)
     call eio%common_init (sample, data, extension)
     write (msg_buffer, "(A,A,A)")  "Events: writing to LCIO file '", &
          char (eio%filename), "'"
     call msg_message ()
     eio%writing = .true.
     call lcio_writer_open_out (eio%lcio_writer, eio%filename)
     call lcio_run_header_init (eio%lcio_run_hdr)
     call lcio_run_header_write (eio%lcio_writer, eio%lcio_run_hdr)
     if (present (success))  success = .true.
   end subroutine eio_lcio_init_out
 
 @ %def eio_lcio_init_out
 @ Initialize event reading. For input, we do not (yet) support split
 event files.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: init_in => eio_lcio_init_in
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_init_in (eio, sample, data, success, extension)
+      class(eio_lcio_t), intent(inout) :: eio
+      type(string_t), intent(in) :: sample
+      type(string_t), intent(in), optional :: extension
+      type(event_sample_data_t), intent(inout), optional :: data
+      logical, intent(out), optional :: success
+    end subroutine eio_lcio_init_in
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_init_in (eio, sample, data, success, extension)
+  module subroutine eio_lcio_init_in (eio, sample, data, success, extension)
     class(eio_lcio_t), intent(inout) :: eio
     type(string_t), intent(in) :: sample
     type(string_t), intent(in), optional :: extension
     type(event_sample_data_t), intent(inout), optional :: data
     logical, intent(out), optional :: success
     logical :: exist
     eio%split = .false.
     call eio%common_init (sample, data, extension)
     write (msg_buffer, "(A,A,A)")  "Events: reading from LCIO file '", &
          char (eio%filename), "'"
     call msg_message ()
     inquire (file = char (eio%filename), exist = exist)
     if (.not. exist)  call msg_fatal ("Events: LCIO file not found.")
     eio%reading = .true.
     call lcio_open_file (eio%lcio_reader, eio%filename)
     if (present (success))  success = .true.
   end subroutine eio_lcio_init_in
 
 @ %def eio_lcio_init_in
 @ Switch from input to output: reopen the file for reading.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: switch_inout => eio_lcio_switch_inout
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_switch_inout (eio, success)
+      class(eio_lcio_t), intent(inout) :: eio
+      logical, intent(out), optional :: success
+    end subroutine eio_lcio_switch_inout
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_switch_inout (eio, success)
+  module subroutine eio_lcio_switch_inout (eio, success)
     class(eio_lcio_t), intent(inout) :: eio
     logical, intent(out), optional :: success
     call msg_bug ("LCIO: in-out switch not supported")
     if (present (success))  success = .false.
   end subroutine eio_lcio_switch_inout
 
 @ %def eio_lcio_switch_inout
 @ Output an event to the allocated LCIO writer.
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: output => eio_lcio_output
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_output &
+         (eio, event, i_prc, reading, passed, pacify, event_handle)
+      class(eio_lcio_t), intent(inout) :: eio
+      class(generic_event_t), intent(in), target :: event
+      integer, intent(in) :: i_prc
+      logical, intent(in), optional :: reading, passed, pacify
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_lcio_output
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_output &
+  module subroutine eio_lcio_output &
        (eio, event, i_prc, reading, passed, pacify, event_handle)
     class(eio_lcio_t), intent(inout) :: eio
     class(generic_event_t), intent(in), target :: event
     integer, intent(in) :: i_prc
     logical, intent(in), optional :: reading, passed, pacify
     class(event_handle_t), intent(inout), optional :: event_handle
     type(particle_set_t), pointer :: pset_ptr
     real(default) :: sqme_prc, weight
     real(default), dimension(:), allocatable :: pol
     integer :: i
     if (present (passed)) then
        if (.not. passed)  return
     end if
     if (eio%writing) then
        pset_ptr => event%get_particle_set_ptr ()
        if (eio%proc_as_run_id) then
           call lcio_event_init (eio%lcio_event, &
                proc_id = eio%proc_num_id (i_prc), &
                event_id = event%get_index (), &
                run_id = eio%proc_num_id (i_prc))
        else
           call lcio_event_init (eio%lcio_event, &
                proc_id = eio%proc_num_id (i_prc), &
                event_id = event%get_index (), &
                run_id = eio%lcio_run_id)
        end if
        call lcio_event_from_particle_set (eio%lcio_event, pset_ptr)
        call lcio_event_set_weight (eio%lcio_event, event%weight_prc)
        call lcio_event_set_sqrts (eio%lcio_event, event%get_sqrts ())
        call lcio_event_set_sqme (eio%lcio_event, event%get_sqme_prc ())
        call lcio_event_set_scale (eio%lcio_event, event%get_fac_scale ())
        call lcio_event_set_alpha_qcd (eio%lcio_event, event%get_alpha_s ())
        if (eio%data%n_beam == 2) then
        call lcio_event_set_xsec (eio%lcio_event, eio%data%cross_section(i_prc), &
             eio%data%error(i_prc))
        end if
        pol = event%get_polarization ()
        do i = 1, eio%data%n_beam
           call lcio_event_set_polarization (eio%lcio_event, pol(i), i)
        end do
        call lcio_event_set_beam_file (eio%lcio_event, &
             event%get_beam_file ())
        call lcio_event_set_process_name (eio%lcio_event, &
             event%get_process_name ())
        do i = 1, eio%n_alt
            sqme_prc = event%get_sqme_alt(i)
            weight = event%get_weight_alt(i)
            call lcio_event_set_alt_sqme (eio%lcio_event, sqme_prc, i)
            call lcio_event_set_alt_weight (eio%lcio_event, weight, i)
        end do
        call lcio_event_write (eio%lcio_writer, eio%lcio_event)
        call maybe_transfer_event_to_handle (eio%lcio_event, &
             event_handle, .true.)
        call lcio_event_final (eio%lcio_event, .true.)
     else
        call eio%write ()
        call msg_fatal ("LCIO file is not open for writing")
     end if
   end subroutine eio_lcio_output
 
 @ %def eio_lcio_output
 @ Input an event.
 
 [WK 22-04-21] We do no longer fix the [[i_mci]] and [[i_term]] indices to 1,
 this can now be done by [[simulation_recalculate]].
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: input_i_prc => eio_lcio_input_i_prc
   procedure :: input_event => eio_lcio_input_event
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_input_i_prc (eio, i_prc, iostat)
+      class(eio_lcio_t), intent(inout) :: eio
+      integer, intent(out) :: i_prc
+      integer, intent(out) :: iostat
+    end subroutine eio_lcio_input_i_prc
+    module subroutine eio_lcio_input_event (eio, event, iostat, event_handle)
+      class(eio_lcio_t), intent(inout) :: eio
+      class(generic_event_t), intent(inout), target :: event
+      integer, intent(out) :: iostat
+      class(event_handle_t), intent(inout), optional :: event_handle
+    end subroutine eio_lcio_input_event
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_input_i_prc (eio, i_prc, iostat)
+  module subroutine eio_lcio_input_i_prc (eio, i_prc, iostat)
     class(eio_lcio_t), intent(inout) :: eio
     integer, intent(out) :: i_prc
     integer, intent(out) :: iostat
     logical :: ok
     integer :: i, proc_num_id
     iostat = 0
     call lcio_read_event (eio%lcio_reader, eio%lcio_event, ok)
     if (.not. ok) then
        iostat = -1
        return
     end if
     proc_num_id = lcio_event_get_process_id (eio%lcio_event)
     i_prc = 0
     FIND_I_PRC: do i = 1, size (eio%proc_num_id)
        if (eio%proc_num_id(i) == proc_num_id) then
           i_prc = i
           exit FIND_I_PRC
        end if
     end do FIND_I_PRC
     if (i_prc == 0)  call err_index
   contains
     subroutine err_index
       call msg_error ("LCIO: reading events: undefined process ID " &
            // char (str (proc_num_id)) // ", aborting read")
       iostat = 1
     end subroutine err_index
   end subroutine eio_lcio_input_i_prc
 
-  subroutine eio_lcio_input_event (eio, event, iostat, event_handle)
+  module subroutine eio_lcio_input_event (eio, event, iostat, event_handle)
     class(eio_lcio_t), intent(inout) :: eio
     class(generic_event_t), intent(inout), target :: event
     integer, intent(out) :: iostat
     class(event_handle_t), intent(inout), optional :: event_handle
     iostat = 0
     call event%reset_contents ()
     call event%select (0, 0, 1)
     call event%set_index (lcio_event_get_event_index (eio%lcio_event))
     call lcio_to_event (event, eio%lcio_event, eio%fallback_model, &
          recover_beams = eio%recover_beams, &
          use_alpha_s = eio%use_alphas_from_file, &
          use_scale = eio%use_scale_from_file)
     call maybe_transfer_event_to_handle (eio%lcio_event, &
          event_handle, .false.)
     call lcio_event_final (eio%lcio_event, .false.)
   end subroutine eio_lcio_input_event
 
 @ %def eio_lcio_input_i_prc
 @ %def eio_lcio_input_event
 @
 If an [[event_handle]] is in the argument list, and it is of the correct HepMC
 type, do not destroy the event but transfer it to the handle (i.e., the
 enclosed C pointer).  Nullify the original pointer, so the event does not get
 destroyed.
 <<EIO LCIO: procedures>>=
   subroutine maybe_transfer_event_to_handle (lcio_event, event_handle, delete)
     type(lcio_event_t), intent(inout) :: lcio_event
     class(event_handle_t), intent(inout), optional :: event_handle
     logical, intent(in) :: delete
     if (present (event_handle)) then
        select type (event_handle)
        type is (lcio_event_t)
           call lcio_event_final (event_handle, delete)  ! just in case
           event_handle = lcio_event
           call lcio_event_nullify (lcio_event) ! avoid destructor call
        end select
     end if
   end subroutine maybe_transfer_event_to_handle
 
 @ %def transfer_event_to_handle
 @
 <<EIO LCIO: eio lcio: TBP>>=
   procedure :: skip => eio_lcio_skip
+<<EIO LCIO: sub interfaces>>=
+    module subroutine eio_lcio_skip (eio, iostat)
+      class(eio_lcio_t), intent(inout) :: eio
+      integer, intent(out) :: iostat
+    end subroutine eio_lcio_skip
 <<EIO LCIO: procedures>>=
-  subroutine eio_lcio_skip (eio, iostat)
+  module subroutine eio_lcio_skip (eio, iostat)
     class(eio_lcio_t), intent(inout) :: eio
     integer, intent(out) :: iostat
     iostat = 0
   end subroutine eio_lcio_skip
 
 @ %def eio_lcio_skip
 @
 \subsection{Unit tests}
 Test module, followed by the corresponding implementation module.
 <<[[eio_lcio_ut.f90]]>>=
 <<File header>>
 
 module eio_lcio_ut
   use unit_tests
   use eio_lcio_uti
 
 <<Standard module head>>
 
 <<EIO LCIO: public test>>
 
 contains
 
 <<EIO LCIO: test driver>>
 
 end module eio_lcio_ut
 @ %def eio_lcio_ut
 @
 <<[[eio_lcio_uti.f90]]>>=
 <<File header>>
 
 module eio_lcio_uti
 
 <<Use kinds>>
 <<Use strings>>
   use io_units
   use model_data
   use particles
   use event_base
   use eio_data
   use eio_base
   use hep_events
   use lcio_interface
 
   use eio_lcio
 
   use eio_base_ut, only: eio_prepare_test, eio_cleanup_test
   use eio_base_ut, only: eio_prepare_fallback_model, eio_cleanup_fallback_model
 
 <<Standard module head>>
 
 <<EIO LCIO: test declarations>>
 
 contains
 
 <<EIO LCIO: tests>>
 
 end module eio_lcio_uti
 @ %def eio_lcio_ut
 @ API: driver for the unit tests below.
 <<EIO LCIO: public test>>=
   public :: eio_lcio_test
 <<EIO LCIO: test driver>>=
   subroutine eio_lcio_test (u, results)
     integer, intent(in) :: u
     type(test_results_t), intent(inout) :: results
   <<EIO LCIO: execute tests>>
   end subroutine eio_lcio_test
 
 @ %def eio_lcio_test
 @
 \subsubsection{Test I/O methods}
 We test the implementation of all I/O methods.
 <<EIO LCIO: execute tests>>=
   call test (eio_lcio_1, "eio_lcio_1", &
        "write event contents", &
        u, results)
 <<EIO LCIO: test declarations>>=
   public :: eio_lcio_1
 <<EIO LCIO: tests>>=
   subroutine eio_lcio_1 (u)
     integer, intent(in) :: u
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(particle_set_t), pointer :: pset_ptr
     type(string_t) :: sample
     integer :: u_file, iostat
     character(215) :: buffer
 
     write (u, "(A)")  "* Test output: eio_lcio_1"
     write (u, "(A)")  "*   Purpose: write a LCIO file"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     call eio_prepare_test (event)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_lcio_1"
 
     allocate (eio_lcio_t :: eio)
     select type (eio)
     type is (eio_lcio_t)
        call eio%set_parameters ()
     end select
 
     call eio%init_out (sample, data)
 
     call event%generate (1, [0._default, 0._default])
     call event%set_index (77)
     call event%pacify_particle_set ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Reset data"
     write (u, "(A)")
 
     deallocate (eio)
     allocate (eio_lcio_t :: eio)
 
     select type (eio)
     type is (eio_lcio_t)
        call eio%set_parameters ()
     end select
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Write LCIO file contents to ASCII file"
     write (u, "(A)")
 
     select type (eio)
     type is (eio_lcio_t)
        call lcio_event_init (eio%lcio_event, &
             proc_id = 42, &
             event_id = event%get_index ())
        pset_ptr => event%get_particle_set_ptr ()
        call lcio_event_from_particle_set &
             (eio%lcio_event,  pset_ptr)
        call write_lcio_event (eio%lcio_event, var_str ("test_file.slcio"))
        call lcio_event_final (eio%lcio_event, .true.)
     end select
 
     write (u, "(A)")
     write (u, "(A)")  "* Read in ASCII contents of LCIO file"
     write (u, "(A)")
 
     u_file = free_unit ()
     open (u_file, file = "test_file.slcio", &
          action = "read", status = "old")
     do
        read (u_file, "(A)", iostat = iostat)  buffer
        if (iostat /= 0)  exit
        if (trim (buffer) == "")  cycle
        if (buffer(1:12) == " - timestamp")  cycle
        if (buffer(1:6) == " date:")  cycle
        write (u, "(A)") trim (buffer)
     end do
     close (u_file)
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio_cleanup_test (event)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lcio_1"
 
   end subroutine eio_lcio_1
 
 @ %def eio_lcio_1
 @ Test also the reading of LCIO events.
 <<EIO LCIO: execute tests>>=
   call test (eio_lcio_2, "eio_lcio_2", &
        "read event contents", &
        u, results)
 <<EIO LCIO: test declarations>>=
   public :: eio_lcio_2
 <<EIO LCIO: tests>>=
   subroutine eio_lcio_2 (u)
     integer, intent(in) :: u
     class(model_data_t), pointer :: fallback_model
     class(generic_event_t), pointer :: event
     type(event_sample_data_t) :: data
     class(eio_t), allocatable :: eio
     type(string_t) :: sample
     integer :: iostat, i_prc
 
     write (u, "(A)")  "* Test output: eio_lcio_2"
     write (u, "(A)")  "*   Purpose: read a LCIO event"
     write (u, "(A)")
 
     write (u, "(A)")  "* Initialize test process"
 
     allocate (fallback_model)
     call eio_prepare_fallback_model (fallback_model)
     call eio_prepare_test (event)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     data%cross_section(1) = 100
     data%error(1) = 1
     data%total_cross_section = sum (data%cross_section)
 
     write (u, "(A)")
     write (u, "(A)")  "* Generate and write an event"
     write (u, "(A)")
 
     sample = "eio_lcio_2"
 
     allocate (eio_lcio_t :: eio)
     select type (eio)
     type is (eio_lcio_t)
        call eio%set_parameters (recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call eio%init_out (sample, data)
     call event%generate (1, [0._default, 0._default])
     call event%set_index (88)
     call event%evaluate_expressions ()
     call event%pacify_particle_set ()
 
     call eio%output (event, i_prc = 1)
     call eio%write (u)
     call eio%final ()
     deallocate (eio)
 
     call event%reset_contents ()
     call event%reset_index ()
 
     write (u, "(A)")
     write (u, "(A)")  "* Initialize"
     write (u, "(A)")
 
     allocate (eio_lcio_t :: eio)
     select type (eio)
     type is (eio_lcio_t)
        call eio%set_parameters (recover_beams = .false.)
     end select
     call eio%set_fallback_model (fallback_model)
 
     call data%init (1)
     data%n_beam = 2
     data%unweighted = .true.
     data%norm_mode = NORM_UNIT
     data%pdg_beam = 25
     data%energy_beam = 500
     data%proc_num_id = [42]
     call data%write (u)
     write (u, *)
 
     write (u, "(A)")  "* Initialize"
     write (u, "(A)")
 
     call eio%init_in (sample, data)
     call eio%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read event"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
 
     select type (eio)
     type is (eio_lcio_t)
        write (u, "(A,I0,A,I0)")  "Found process #", i_prc, &
             " with ID = ", eio%proc_num_id(i_prc)
     end select
 
     call eio%input_event (event, iostat)
     call event%select (1, 1, 1)
     call event%write (u)
 
     write (u, "(A)")
     write (u, "(A)")  "* Read closing"
     write (u, "(A)")
 
     call eio%input_i_prc (i_prc, iostat)
     write (u, "(A,I0)")  "iostat = ", iostat
 
     write (u, "(A)")
     write (u, "(A)")  "* Cleanup"
 
     call eio%final ()
 
     call eio_cleanup_test (event)
     call eio_cleanup_fallback_model (fallback_model)
     deallocate (fallback_model)
 
     write (u, "(A)")
     write (u, "(A)")  "* Test output end: eio_lcio_2"
 
   end subroutine eio_lcio_2
 
 @ %def eio_lcio_2
Index: trunk/src/events/Makefile.am
===================================================================
--- trunk/src/events/Makefile.am	(revision 8783)
+++ trunk/src/events/Makefile.am	(revision 8784)
@@ -1,232 +1,275 @@
 ## Makefile.am -- Makefile for WHIZARD
 ##
 ## Process this file with automake to produce Makefile.in
 #
 # Copyright (C) 1999-2022 by
 #     Wolfgang Kilian <kilian@physik.uni-siegen.de>
 #     Thorsten Ohl <ohl@physik.uni-wuerzburg.de>
 #     Juergen Reuter <juergen.reuter@desy.de>
 #     with contributions from
 #     cf. main AUTHORS file
 #
 # WHIZARD is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 2, or (at your option)
 # any later version.
 #
 # WHIZARD is distributed in the hope that it will be useful, but
 # WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 ########################################################################
 
 ## The files in this directory implement quantum field theory concepts
 ## such as model representation and quantum numbers.
 
 ## We create a library which is still to be combined with auxiliary libs.
 noinst_LTLIBRARIES = libevents.la
 check_LTLIBRARIES = libevents_ut.la
 
 libevents_la_SOURCES = \
+  $(EVENTS_MODULES) \
+  $(EVENTS_SUBMODULES)
+
+EVENTS_MODULES = \
   event_base.f90 \
   event_handles.f90 \
   eio_data.f90 \
   eio_base.f90 \
   eio_direct.f90 \
   eio_checkpoints.f90 \
   eio_callback.f90 \
   eio_weights.f90 \
   eio_dump.f90 \
   hep_common.f90 \
   hepmc_interface.f90 \
   lcio_interface.f90 \
   hep_events.f90 \
   eio_ascii.f90 \
   eio_lhef.f90 \
   eio_stdhep.f90 \
   eio_hepmc.f90 \
   eio_lcio.f90
 
+EVENTS_SUBMODULES = \
+  event_base_sub.f90 \
+  eio_data_sub.f90 \
+  eio_base_sub.f90 \
+  eio_direct_sub.f90 \
+  eio_checkpoints_sub.f90 \
+  eio_callback_sub.f90 \
+  eio_weights_sub.f90 \
+  eio_dump_sub.f90 \
+  hep_common_sub.f90 \
+  hepmc_interface_sub.f90 \
+  lcio_interface_sub.f90 \
+  hep_events_sub.f90 \
+  eio_ascii_sub.f90 \
+  eio_lhef_sub.f90 \
+  eio_stdhep_sub.f90 \
+  eio_hepmc_sub.f90 \
+  eio_lcio_sub.f90
+
 libevents_ut_la_SOURCES = \
   eio_data_uti.f90 eio_data_ut.f90 \
   eio_base_uti.f90 eio_base_ut.f90 \
   eio_direct_uti.f90 eio_direct_ut.f90 \
   eio_checkpoints_uti.f90 eio_checkpoints_ut.f90 \
   eio_weights_uti.f90 eio_weights_ut.f90 \
   eio_dump_uti.f90 eio_dump_ut.f90 \
   hepmc_interface_uti.f90 hepmc_interface_ut.f90 \
   lcio_interface_uti.f90 lcio_interface_ut.f90 \
   hep_events_uti.f90 hep_events_ut.f90 \
   eio_ascii_uti.f90 eio_ascii_ut.f90 \
   eio_lhef_uti.f90 eio_lhef_ut.f90 \
   eio_stdhep_uti.f90 eio_stdhep_ut.f90 \
   eio_hepmc_uti.f90 eio_hepmc_ut.f90 \
   eio_lcio_uti.f90 eio_lcio_ut.f90
 
 ## Omitting this would exclude it from the distribution
 dist_noinst_DATA = events.nw
 
 # Modules and installation
 # Dump module names into file Modules
 execmoddir = $(fmoddir)/whizard
 nodist_execmod_HEADERS = \
-  ${libevents_la_SOURCES:.f90=.$(FCMOD)}
+  ${EVENTS_MODULES:.f90=.$(FCMOD)}
 
+# Dump module names into file Modules
 libevents_Modules = \
-  ${libevents_la_SOURCES:.f90=} \
+  ${EVENTS_MODULES:.f90=} \
   ${libevents_ut_la_SOURCES:.f90=}
 Modules: Makefile
 	@for module in $(libevents_Modules); do \
           echo $$module >> $@.new; \
         done
 	@if diff $@ $@.new -q >/dev/null; then \
           rm $@.new; \
 	else \
           mv $@.new $@; echo "Modules updated"; \
         fi
 BUILT_SOURCES = Modules
 
 ## Fortran module dependencies
 # Get module lists from other directories
 module_lists = \
   ../basics/Modules \
   ../utilities/Modules \
   ../testing/Modules \
   ../system/Modules \
   ../parsing/Modules \
   ../physics/Modules \
   ../qft/Modules \
   ../types/Modules \
   ../particles/Modules \
   ../xdr/Modules
 
 $(module_lists):
 	$(MAKE) -C `dirname $@` Modules
 
 Module_dependencies.sed: $(libevents_la_SOURCES) $(libevents_ut_la_SOURCES)
 Module_dependencies.sed: $(module_lists)
 	@rm -f $@
 	echo 's/, *only:.*//' >> $@
 	echo 's/, *&//' >> $@
 	echo 's/, *.*=>.*//' >> $@
 	echo 's/$$/.lo/' >> $@
 	for list in $(module_lists); do \
 		dir="`dirname $$list`"; \
 		for mod in `cat $$list`; do \
 			echo 's!: '$$mod'.lo$$!': $$dir/$$mod'.lo!' >> $@; \
 		done \
 	done
 
 DISTCLEANFILES = Module_dependencies.sed
 
 # The following line just says
 #    include Makefile.depend
 # but in a portable fashion (depending on automake's AM_MAKE_INCLUDE
 @am__include@ @am__quote@Makefile.depend@am__quote@
 
 Makefile.depend: Module_dependencies.sed
 Makefile.depend: $(libevents_la_SOURCES) $(libevents_ut_la_SOURCES)
 	@rm -f $@
 	for src in $^; do \
 	  module="`basename $$src | sed 's/\.f[90][0358]//'`"; \
 	  grep '^ *use ' $$src \
 	    | grep -v '!NODEP!' \
 	    | sed -e 's/^ *use */'$$module'.lo: /' \
 	          -f Module_dependencies.sed; \
 	done > $@
 
 DISTCLEANFILES += Makefile.depend
 
 libevents_la_LIBADD = \
    ../../mcfio/libwo_mcfio.la \
    ../../stdhep/libwo_stdhep.la
 
 # Fortran90 module files are generated at the same time as object files
 .lo.$(FCMOD):
 	@:
 #	touch $@
 
 AM_FCFLAGS = -I../basics -I../utilities -I../testing -I../system -I../combinatorics -I../parsing -I../physics -I../qft -I../expr_base -I../types -I../fastjet -I../particles -I../xdr
 
+########################################################################
+# For the moment, the submodule dependencies will be hard-coded
+event_base_sub.lo: event_base.lo
+eio_data_sub.lo: eio_data.lo
+eio_base_sub.lo: eio_base.lo
+eio_direct_sub.lo: eio_direct.lo
+eio_checkpoints_sub.lo: eio_checkpoints.lo
+eio_callback_sub.lo: eio_callback.lo
+eio_weights_sub.lo: eio_weights.lo
+eio_dump_sub.lo: eio_dump.lo
+hep_common_sub.lo: hep_common.lo
+hepmc_interface_sub.lo: hepmc_interface.lo
+lcio_interface_sub.lo: lcio_interface.lo
+hep_events_sub.lo: hep_events.lo
+eio_ascii_sub.lo: eio_ascii.lo
+eio_lhef_sub.lo: eio_lhef.lo
+eio_stdhep_sub.lo: eio_stdhep.lo
+eio_hepmc_sub.lo: eio_hepmc.lo
+eio_lcio_sub.lo: eio_lcio.lo
 
 ########################################################################
 ## Default Fortran compiler options
 
 ## Profiling
 if FC_USE_PROFILING
 AM_FCFLAGS += $(FCFLAGS_PROFILING)
 endif
 
 ## OpenMP
 if FC_USE_OPENMP
 AM_FCFLAGS += $(FCFLAGS_OPENMP)
 endif
 
 # MPI
 if FC_USE_MPI
 AM_FCFLAGS += $(FCFLAGS_MPI)
 endif
 
 ########################################################################
 ## Non-standard targets and dependencies
 
 ## (Re)create F90 sources from NOWEB source.
 if NOWEB_AVAILABLE
 
 PRELUDE = $(top_srcdir)/src/noweb-frame/whizard-prelude.nw
 POSTLUDE = $(top_srcdir)/src/noweb-frame/whizard-postlude.nw
 
 events.stamp: $(PRELUDE) $(srcdir)/events.nw $(POSTLUDE)
 	@rm -f events.tmp
 	@touch events.tmp
 	for src in $(libevents_la_SOURCES) $(libevents_ut_la_SOURCES); do \
 	  $(NOTANGLE) -R[[$$src]] $^ | $(CPIF) $$src; \
         done
 	@mv -f events.tmp events.stamp
 
 $(libevents_la_SOURCES) $(libevents_ut_la_SOURCES): events.stamp
 ## Recover from the removal of $@
 	@if test -f $@; then :; else \
 	  rm -f events.stamp; \
 	  $(MAKE) $(AM_MAKEFLAGS) events.stamp; \
 	fi
 
 endif
 
 
 ########################################################################
 ## Non-standard cleanup tasks
 ## Remove sources that can be recreated using NOWEB
 if NOWEB_AVAILABLE
 maintainer-clean-noweb:
 	-rm -f *.f90 *.c
 endif
 .PHONY: maintainer-clean-noweb
 
 ## Remove those sources also if builddir and srcdir are different
 if NOWEB_AVAILABLE
 clean-noweb:
 	test "$(srcdir)" != "." && rm -f *.f90 *.c || true
 endif
 .PHONY: clean-noweb
 
 ## Remove F90 module files
 clean-local: clean-noweb
 	-rm -f events.stamp events.tmp
 	-rm -f *.$(FCMOD)
 if FC_SUBMODULES
 	-rm -f *.smod *.sub
 endif
 
 ## Remove backup files
 maintainer-clean-backup:
 	-rm -f *~
 .PHONY: maintainer-clean-backup
 
 ## Register additional clean targets
 maintainer-clean-local: maintainer-clean-noweb maintainer-clean-backup
Index: trunk/share/debug/Makefile_full
===================================================================
--- trunk/share/debug/Makefile_full	(revision 8783)
+++ trunk/share/debug/Makefile_full	(revision 8784)
@@ -1,587 +1,605 @@
 FC=pgfortran_2019
 FCFLAGS=-Mbackslash
 CC=gcc
 CCFLAGS=
 
 MODELS = \
 	SM.mdl \
 	SM_hadrons.mdl \
 	Test.mdl
 
 CC_SRC = \
 	sprintf_interface.c \
 	signal_interface.c
 
 F77_SRC = \
 	pythia.F \
 	pythia_pdf.f \
 	pythia6_up.f \
 	toppik.f \
 	toppik_axial.f
 
 FC0_SRC = 
 
 FC_SRC = \
 	format_defs.f90 \
 	io_units.f90 \
 	kinds.f90 \
 	constants.f90 \
 	iso_varying_string.f90 \
 	unit_tests.f90 \
 	unit_tests_sub.f90 \
 	numeric_utils.f90 \
 	numeric_utils_sub.f90 \
 	system_dependencies.f90 \
 	string_utils.f90 \
 	string_utils_sub.f90 \
 	system_defs.f90 \
 	system_defs_sub.f90 \	
 	debug_master.f90 \
 	diagnostics.f90 \
 	diagnostics_sub.f90 \
 	sorting.f90 \
 	physics_defs.f90 \
 	physics_defs_sub.f90 \
 	pdg_arrays.f90 \
 	bytes.f90 \
 	hashes.f90 \
 	md5.f90 \
 	model_data.f90 \
 	model_data_sub.f90 \
 	auto_components.f90 \
 	var_base.f90 \
 	model_testbed.f90 \
 	auto_components_uti.f90 \
 	auto_components_ut.f90 \
 	os_interface.f90 \
 	os_interface_sub.f90 \
 	c_particles.f90 \
 	c_particles_sub.f90 \
 	format_utils.f90 \
 	lorentz.f90 \
 	lorentz_sub.f90 \
 	phs_points.f90 \
 	phs_points_sub.f90 \
 	colors.f90 \
 	colors_sub.f90 \
 	flavors.f90 \
 	flavors_sub.f90 \
 	helicities.f90 \
 	helicities_sub.f90 \
 	quantum_numbers.f90 \
 	quantum_numbers_sub.f90 \
 	state_matrices.f90 \
 	state_matrices_sub.f90 \
 	interactions.f90 \
 	interactions_sub.f90 \
 	CppStringsWrap_dummy.f90 \
 	FastjetWrap_dummy.f90 \
 	cpp_strings.f90 \
 	cpp_strings_sub.f90 \
 	fastjet.f90 \
 	fastjet_sub.f90 \
 	jets.f90 \
 	subevents.f90 \
 	su_algebra.f90 \
 	su_algebra_sub.f90 \
 	bloch_vectors.f90 \
 	bloch_vectors_sub.f90 \
 	polarizations.f90 \
 	polarizations_sub.f90 \
 	particles.f90 \
 	particles_sub.f90 \
 	event_base.f90 \
+	event_base_sub.f90 \
 	eio_data.f90 \
+	eio_data_sub.f90 \
 	event_handles.f90 \
 	eio_base.f90 \
+	eio_base_sub.f90 \
 	eio_base_uti.f90 \
 	eio_base_ut.f90 \
 	variables.f90 \
 	variables_sub.f90 \
 	rng_base.f90 \
 	tao_random_numbers.f90 \
 	rng_tao.f90 \
 	rng_stream.f90 \
 	rng_base_uti.f90 \
 	rng_base_ut.f90 \
 	dispatch_rng.f90 \
 	dispatch_rng_uti.f90 \
 	dispatch_rng_ut.f90 \
 	beam_structures.f90 \
 	evaluators.f90 \
 	evaluators_sub.f90 \
 	beams.f90 \
 	sm_physics.f90 \
 	sm_physics_sub.f90 \
 	file_registries.f90 \
 	file_registries_sub.f90 \
 	sf_aux.f90 \
 	sf_mappings.f90 \
 	sf_base.f90 \
 	electron_pdfs.f90 \
 	sf_isr.f90 \
 	sf_epa.f90 \
 	sf_ewa.f90 \
 	sf_escan.f90 \
 	sf_gaussian.f90 \
 	sf_beam_events.f90 \
 	circe1.f90 \
 	sf_circe1.f90 \
 	circe2.f90 \
 	selectors.f90 \
 	sf_circe2.f90 \
 	sm_qcd.f90 \
 	sm_qcd_sub.f90 \
 	sm_qed.f90 \
 	sm_qed_sub.f90 \
 	mrst2004qed.f90 \
 	cteq6pdf.f90 \
 	mstwpdf.f90 \
 	ct10pdf.f90 \
 	CJpdf.f90 \
 	ct14pdf.f90 \
 	pdf_builtin.f90 \
 	pdf_builtin_sub.f90 \
 	LHAPDFWrap_dummy.f90 \
 	lhapdf5_full_dummy.f90 \
 	lhapdf5_has_photon_dummy.f90 \
 	lhapdf.f90 \
 	hoppet_dummy.f90 \
 	hoppet_interface.f90 \
 	sf_pdf_builtin.f90 \
 	sf_lhapdf.f90 \
 	dispatch_beams.f90 \
 	process_constants.f90 \
 	process_constants_sub.f90 \
 	prclib_interfaces.f90 \
 	prc_core_def.f90 \
 	prc_core_def_sub.f90 \
 	particle_specifiers.f90 \
 	particle_specifiers_sub.f90 \
 	process_libraries.f90 \
 	process_libraries_sub.f90 \
 	prc_test.f90 \
 	prc_test_sub.f90 \
 	prc_core.f90 \
 	prc_test_core.f90 \
 	sm_qed.f90 \
 	prc_omega.f90 \
 	phs_base.f90 \
 	ifiles.f90 \
 	lexers.f90 \
 	syntax_rules.f90 \
 	parser.f90 \
 	expr_base.f90 \
 	formats.f90 \
 	formats_sub.f90 \
 	analysis.f90 \
 	user_code_interface.f90 \
 	observables.f90 \
+	observables_sub.f90 \
 	eval_trees.f90 \
 	interpolation.f90 \
 	interpolation_sub.f90 \
 	nr_tools.f90 \
 	ttv_formfactors.f90 \
 	ttv_formfactors_use.f90 \
 	ttv_formfactors_uti.f90 \
 	ttv_formfactors_ut.f90 \
 	models.f90 \
 	prclib_stacks.f90 \
 	prclib_stacks_sub.f90 \
 	user_files.f90 \
 	cputime.f90 \
 	cputime_sub.f90 \
 	mci_base.f90 \
 	integration_results.f90 \
 	integration_results_uti.f90 \
 	integration_results_ut.f90 \
 	mappings.f90 \
 	permutations.f90 \
 	resonances.f90 \
 	phs_trees.f90 \
 	phs_forests.f90 \
 	prc_external.f90 \
 	blha_config.f90 \
 	blha_olp_interfaces.f90 \
 	prc_openloops.f90 \
 	prc_threshold.f90 \
 	process_config.f90 \
 	process_counter.f90 \
 	process_mci.f90 \
 	pcm_base.f90 \
 	nlo_data.f90 \
 	cascades.f90 \
 	cascades2_lexer.f90 \
 	cascades2_lexer_uti.f90 \
 	cascades2_lexer_ut.f90 \
 	cascades2.f90 \
 	cascades2_uti.f90 \
 	cascades2_ut.f90 \
 	phs_none.f90 \
 	phs_rambo.f90 \
 	phs_wood.f90 \
 	phs_fks.f90 \
 	phs_single.f90 \
 	fks_regions.f90 \
 	virtual.f90 \
 	pdf.f90 \
 	real_subtraction.f90 \
 	dglap_remnant.f90 \
 	dispatch_fks.f90 \
 	dispatch_phase_space.f90 \
 	pcm.f90 \
 	recola_wrapper_dummy.f90 \
 	prc_recola.f90 \
 	subevt_expr.f90 \
 	parton_states.f90 \
 	prc_template_me.f90 \
 	process.f90 \
 	process_stacks.f90 \
 	iterations.f90 \
 	rt_data.f90 \
 	file_utils.f90 \
 	file_utils_sub.f90 \
 	prc_gosam.f90 \
 	dispatch_me_methods.f90 \
 	sf_base_uti.f90 \
 	sf_base_ut.f90 \
 	dispatch_uti.f90 \
 	dispatch_ut.f90 \
 	formats_uti.f90 \
 	formats_ut.f90 \
 	md5_uti.f90 \
 	md5_ut.f90 \
 	os_interface_uti.f90 \
 	os_interface_ut.f90 \
 	sorting_uti.f90 \
 	sorting_ut.f90 \
 	grids.f90 \
 	grids_uti.f90 \
 	grids_ut.f90 \
 	solver.f90 \
 	solver_uti.f90 \
 	solver_ut.f90 \
 	cputime_uti.f90 \
 	cputime_ut.f90 \
 	sm_qcd_uti.f90 \
 	sm_qcd_ut.f90 \
 	sm_physics_uti.f90 \
 	sm_physics_ut.f90 \
 	lexers_uti.f90 \
 	lexers_ut.f90 \
 	parser_uti.f90 \
 	parser_ut.f90 \
 	xml.f90 \
 	xml_uti.f90 \
 	xml_ut.f90 \
 	colors_uti.f90 \
 	colors_ut.f90 \
 	state_matrices_uti.f90 \
 	state_matrices_ut.f90 \
 	analysis_uti.f90 \
 	analysis_ut.f90 \
 	particles_uti.f90 \
 	particles_ut.f90 \
 	radiation_generator.f90 \
 	radiation_generator_uti.f90 \
 	radiation_generator_ut.f90 \
 	blha_uti.f90 \
 	blha_ut.f90 \
 	evaluators_uti.f90 \
 	evaluators_ut.f90 \
 	models_uti.f90 \
 	models_ut.f90 \
 	eval_trees_uti.f90 \
 	eval_trees_ut.f90 \
 	resonances_uti.f90 \
 	resonances_ut.f90 \
 	phs_trees_uti.f90 \
 	phs_trees_ut.f90 \
 	phs_forests_uti.f90 \
 	phs_forests_ut.f90 \
 	beams_uti.f90 \
 	beams_ut.f90 \
 	su_algebra_uti.f90 \
 	su_algebra_ut.f90 \
 	bloch_vectors_uti.f90 \
 	bloch_vectors_ut.f90 \
 	polarizations_uti.f90 \
 	polarizations_ut.f90 \
 	sf_aux_uti.f90 \
 	sf_aux_ut.f90 \
 	sf_mappings_uti.f90 \
 	sf_mappings_ut.f90 \
 	sf_pdf_builtin_uti.f90 \
 	sf_pdf_builtin_ut.f90 \
 	sf_lhapdf_uti.f90 \
 	sf_lhapdf_ut.f90 \
 	sf_isr_uti.f90 \
 	sf_isr_ut.f90 \
 	sf_epa_uti.f90 \
 	sf_epa_ut.f90 \
 	sf_ewa_uti.f90 \
 	sf_ewa_ut.f90 \
 	sf_circe1_uti.f90 \
 	sf_circe1_ut.f90 \
 	sf_circe2_uti.f90 \
 	sf_circe2_ut.f90 \
 	sf_gaussian_uti.f90 \
 	sf_gaussian_ut.f90 \
 	sf_beam_events_uti.f90 \
 	sf_beam_events_ut.f90 \
 	sf_escan_uti.f90 \
 	sf_escan_ut.f90 \
 	phs_base_uti.f90 \
 	phs_base_ut.f90 \
 	phs_none_uti.f90 \
 	phs_none_ut.f90 \
 	phs_single_uti.f90 \
 	phs_single_ut.f90 \
 	phs_rambo_uti.f90 \
 	phs_rambo_ut.f90 \
 	phs_wood_uti.f90 \
 	phs_wood_ut.f90 \
 	phs_fks_uti.f90 \
 	phs_fks_ut.f90 \
 	fks_regions_uti.f90 \
 	fks_regions_ut.f90 \
 	mci_midpoint.f90 \
 	mci_base_uti.f90 \
 	mci_base_ut.f90 \
 	mci_midpoint_uti.f90 \
 	mci_midpoint_ut.f90 \
 	kinematics.f90 \
 	instances.f90 \
 	mci_none.f90 \
 	mci_none_uti.f90 \
 	mci_none_ut.f90 \
 	processes_uti.f90 \
 	processes_ut.f90 \
 	process_stacks_uti.f90 \
 	process_stacks_ut.f90 \
 	prc_recola_uti.f90 \
 	prc_recola_ut.f90 \
 	rng_tao_uti.f90 \
 	rng_tao_ut.f90 \
 	rng_stream_uti.f90 \
 	rng_stream_ut.f90 \
 	selectors_uti.f90 \
 	selectors_ut.f90 \
 	vegas.f90 \
 	vegas_uti.f90 \
 	vegas_ut.f90 \
 	vamp2.f90 \
 	vamp2_uti.f90 \
 	vamp2_ut.f90 \
 	exceptions.f90 \
 	vamp_stat.f90 \
 	utils.f90 \
 	divisions.f90 \
 	linalg.f90 \
 	vamp.f90 \
 	mci_vamp.f90 \
 	mci_vamp_uti.f90 \
 	mci_vamp_ut.f90 \
 	mci_vamp2.f90 \
 	mci_vamp2_uti.f90 \
 	mci_vamp2_ut.f90 \
 	prclib_interfaces_uti.f90 \
 	prclib_interfaces_ut.f90 \
 	particle_specifiers_uti.f90 \
 	particle_specifiers_ut.f90 \
 	process_libraries_uti.f90 \
 	process_libraries_ut.f90 \
 	prclib_stacks_uti.f90 \
 	prclib_stacks_ut.f90 \
 	slha_interface.f90 \
 	slha_interface_uti.f90 \
 	slha_interface_ut.f90 \
 	cascades_uti.f90 \
 	cascades_ut.f90 \
 	prc_test_uti.f90 \
 	prc_test_ut.f90 \
 	prc_template_me_uti.f90 \
 	prc_template_me_ut.f90 \
 	prc_omega_uti.f90 \
 	prc_omega_ut.f90 \
 	event_transforms.f90 \
 	event_transforms_uti.f90 \
 	event_transforms_ut.f90 \
 	hep_common.f90 \
+	hep_common_sub.f90 \
 	hepev4_aux.f90 \
 	tauola_dummy.f90 \
 	tauola_interface.f90 \
 	shower_base.f90 \
 	shower_partons.f90 \
 	muli.f90 \
 	matching_base.f90 \
 	powheg_matching.f90 \
 	shower_core.f90 \
 	shower_base_uti.f90 \
 	shower_base_ut.f90 \
 	shower.f90 \
 	shower_uti.f90 \
 	shower_ut.f90 \
 	shower_pythia6.f90 \
 	whizard_lha.f90 \
 	whizard_lha_uti.f90 \
 	whizard_lha_ut.f90 \
 	LHAWhizard_dummy.f90 \
 	Pythia8Wrap_dummy.f90 \
 	pythia8.f90 \
 	pythia8_uti.f90 \
 	pythia8_ut.f90 \
 	shower_pythia8.f90 \
 	hadrons.f90 \
 	ktclus.f90 \
 	mlm_matching.f90 \
 	ckkw_matching.f90 \
 	jets_uti.f90 \
 	jets_ut.f90 \
 	pdg_arrays_uti.f90 \
 	pdg_arrays_ut.f90 \
 	interactions_uti.f90 \
 	interactions_ut.f90 \
 	decays.f90 \
 	decays_uti.f90 \
 	decays_ut.f90 \
 	evt_nlo.f90 \
 	events.f90 \
 	events_uti.f90 \
 	events_ut.f90 \
 	HepMCWrap_dummy.f90 \
 	hepmc_interface.f90 \
+	hepmc_interface_sub.f90 \
 	hepmc_interface_uti.f90 \
 	hepmc_interface_ut.f90 \
 	LCIOWrap_dummy.f90 \
 	lcio_interface.f90 \
+	lcio_interface_sub.f90 \
 	lcio_interface_uti.f90 \
 	lcio_interface_ut.f90 \
 	hep_events.f90 \
+	hep_events_sub.f90 \
 	hep_events_uti.f90 \
 	hep_events_ut.f90 \
 	expr_tests_uti.f90 \
 	expr_tests_ut.f90 \
 	parton_states_uti.f90 \
 	parton_states_ut.f90 \
 	eio_data_uti.f90 \
 	eio_data_ut.f90 \
 	eio_raw.f90 \
 	eio_raw_uti.f90 \
 	eio_raw_ut.f90 \
 	eio_checkpoints.f90 \
+	eio_checkpoints_sub.f90 \
 	eio_checkpoints_uti.f90 \
 	eio_checkpoints_ut.f90 \
 	eio_lhef.f90 \
+	eio_lhef_sub.f90 \
 	eio_lhef_uti.f90 \
 	eio_lhef_ut.f90 \
 	eio_hepmc.f90 \
+	eio_hepmc_sub.f90 \
 	eio_hepmc_uti.f90 \
 	eio_hepmc_ut.f90 \
 	eio_lcio.f90 \
+	eio_lcio_sub.f90 \
 	eio_lcio_uti.f90 \
 	eio_lcio_ut.f90 \
 	stdhep_dummy.f90 \
 	xdr_wo_stdhep.f90 \
 	eio_stdhep.f90 \
+	eio_stdhep_sub.f90 \
 	eio_stdhep_uti.f90 \
 	eio_stdhep_ut.f90 \
 	eio_ascii.f90 \
+	eio_ascii_sub.f90 \
 	eio_ascii_uti.f90 \
 	eio_ascii_ut.f90 \
 	eio_weights.f90 \
+	eio_weights_sub.f90 \
 	eio_weights_uti.f90 \
 	eio_weights_ut.f90 \
 	eio_dump.f90 \
+	eio_dump_sub.f90 \
 	eio_dump_uti.f90 \
 	eio_dump_ut.f90 \
 	eio_callback.f90 \
+	eio_callback_sub.f90 \
 	real_subtraction_uti.f90 \
 	real_subtraction_ut.f90 \
 	iterations_uti.f90 \
 	iterations_ut.f90 \
 	rt_data_uti.f90 \
 	rt_data_ut.f90 \
 	dispatch_mci.f90 \
 	dispatch_mci_uti.f90 \
 	dispatch_mci_ut.f90 \
 	dispatch_phs_uti.f90 \
 	dispatch_phs_ut.f90 \
 	resonance_insertion.f90 \
 	resonance_insertion_uti.f90 \
 	resonance_insertion_ut.f90 \
 	recoil_kinematics.f90 \
 	recoil_kinematics_uti.f90 \
 	recoil_kinematics_ut.f90 \
 	isr_epa_handler.f90 \
 	isr_epa_handler_uti.f90 \
 	isr_epa_handler_ut.f90 \
 	dispatch_transforms.f90 \
 	dispatch_transforms_uti.f90 \
 	dispatch_transforms_ut.f90 \
 	beam_structures_uti.f90 \
 	beam_structures_ut.f90 \
 	process_configurations.f90 \
 	process_configurations_uti.f90 \
 	process_configurations_ut.f90 \
 	compilations.f90 \
 	compilations_uti.f90 \
 	compilations_ut.f90 \
 	integrations.f90 \
 	integrations_uti.f90 \
 	integrations_ut.f90 \
 	event_streams.f90 \
 	event_streams_uti.f90 \
 	event_streams_ut.f90 \
 	restricted_subprocesses.f90 \
 	eio_direct.f90 \
+	eio_direct_sub.f90 \
 	eio_direct_uti.f90 \
 	eio_direct_ut.f90 \
 	simulations.f90 \
 	restricted_subprocesses_uti.f90 \
 	restricted_subprocesses_ut.f90 \
 	simulations_uti.f90 \
 	simulations_ut.f90 \
 	commands.f90 \
 	commands_uti.f90 \
 	commands_ut.f90 \
 	cmdline_options.f90 \
 	libmanager.f90 \
 	features.f90 \
 	whizard.f90 \
 	api.f90 \
 	api_hepmc_uti.f90 \
 	api_hepmc_ut.f90 \
 	api_lcio_uti.f90 \
 	api_lcio_ut.f90 \
 	api_uti.f90 \
 	api_ut.f90
 
 FC_OBJ = $(FC0_SRC:.f90=.o) $(F77_SRC:.f=.o) $(FC_SRC:.f90=.o) 
 CC_OBJ = $(CC_SRC:.c=.o)
 
 all: whizard_test 
 check: whizard_test
 	./whizard_test --check resonances
 
 whizard_test: $(FC_OBJ) $(CC_OBJ) main_ut.f90
 	$(FC) $(FC_OBJ) $(CC_OBJ) -ldl -o $@ main_ut.f90
 
 whizard: $(FC_OBJ) $(CC_OBJ) main.f90
 	$(FC) $(FC_OBJ) $(CC_OBJ) -ldl -o $@ main.f90
 
 %.o: %.f90
 	$(FC) $(FCFLAGS) -c $<
 
 %.o: %.f
 	$(FC) $(FCFLAGS) -c $<
 
 %.o: %.c
 	$(CC) $(CCFLAGS) -c $<
 
 tar: $(FC_SRC) $(F77_SRC) $(FC0_SRC) $(CC_SRC) $(MODELS)
 	tar cvvzf whizard-`date +%y%m%d`-`date +%H%M`.tar.gz $(FC_SRC) $(FC0_SRC) \
 	$(F77_SRC) $(CC_SRC) main_ut.f90 Makefile $(MODELS)
 
 clean:
 	rm -f *.mod *.o whizard_test