diff --git a/demo/app/tensor-statistics.f90 b/demo/app/tensor-statistics.F90
similarity index 87%
rename from demo/app/tensor-statistics.f90
rename to demo/app/tensor-statistics.F90
index 9a99d1e7d..c00f74c1a 100644
--- a/demo/app/tensor-statistics.f90
+++ b/demo/app/tensor-statistics.F90
@@ -1,6 +1,8 @@
 ! Copyright (c), The Regents of the University of California
 ! Terms of use are as specified in LICENSE.txt
 
+#include "assert_macros.h"
+
 module ubounds_m
   !! This module serves only to support array bounds checking in the main program below
   implicit none
@@ -25,29 +27,29 @@ elemental function equals(lhs, rhs) result(lhs_equals_rhs)
 program tensor_statistics
   !! This program
   !! 1. Computes the ranges and histograms of input and output tensors saved by
-  !!    the neural-net branch of the Berkeley Lab fork of [ICAR](https://berkeleylab.github/icar).
+  !!    the neural-net branch of the Berkeley Lab fork of [ICAR](https://go.lbl.gov/icar).
   !! 2. Saves the resulting statistics to text files with space-separated columns and column labels.
 
   ! External dependencies:
   use julienne_m, only : command_line_t, file_t, string_t
-  use assert_m, only : assert, intrinsic_array_t
+  use assert_m
   use ubounds_m, only : ubounds_t
   use ieee_arithmetic, only : ieee_is_nan
   use iso_fortran_env, only : int64, real64
     
   ! Internal dependencies:
   use NetCDF_file_m, only: NetCDF_file_t
-  use histogram_m, only : histogram_t, to_file
+  use histogram_m, only: histogram_t, to_file
   implicit none
 
-  character(len=*), parameter :: usage = &
-    new_line('a') // new_line('a') // &
-    'Usage: ' // new_line('a') // new_line('a') // &
-    './build/run-fpm.sh run tensor-statistics -- \' // new_line('a') // &
-    '  --base <string> --bins <integer> \' // new_line('a') // &
+  character(len=*), parameter :: usage =    new_line('a') // new_line('a') // & 
+    'Usage: '                            // new_line('a') // new_line('a') // &
+    './build/run-fpm.sh run tensor-statistics -- \'       // new_line('a') // &
+    '  --base <string> --bins <integer> \'                // new_line('a') // &
     '  [--raw] [--start <integer>] [--end <integer>] [--stride <integer>]' // &
-    new_line('a') // new_line('a') // &
-    'where angular brackets denote user-provided values and square brackets denote optional arguments.' // new_line('a')
+                                            new_line('a') // new_line('a') // &
+    'where angular brackets denote user-provided values and square brackets denote optional arguments.' &
+                                                          // new_line('a')
 
   integer(int64) t_start, t_finish, clock_rate
   integer num_bins, start_step, stride
@@ -85,7 +87,7 @@ subroutine get_command_line_arguments(base_name, num_bins, start_step, end_step,
     type(command_line_t) command_line
     character(len=:), allocatable :: stride_string, bins_string, start_string, end_string
 
-    base_name = command_line%flag_value("--base") ! gfortran 13 seg faults if this is an association
+    base_name = command_line%flag_value("--base")
     bins_string = command_line%flag_value("--bins")
     start_string = command_line%flag_value("--start")
     end_string = command_line%flag_value("--end")
@@ -204,9 +206,9 @@ subroutine compute_histograms(base_name, raw)
         lbounds = [lbounds, lbound(qv_out), lbound(qc_out), lbound(qr_out), lbound(qs_out)]
         ubounds = [ubounds, ubounds_t(ubound(qv_out)), ubounds_t(ubound(qc_out)), &
           ubounds_t(ubound(qr_out)), ubounds_t(ubound(qs_out))]
-        call assert(all(lbounds == 1), "main: default input/output lower bounds", intrinsic_array_t(lbounds))
-        call assert(all(ubounds == ubounds(1)), "main: matching input/output upper bounds")
-        call assert(all(abs(time_in(2:t_end) - time_out(1:t_end-1))<tolerance), "main: matching time stamps")
+        call_assert_diagnose(all(lbounds == 1), "main: default input/output lower bounds", intrinsic_array_t(lbounds))
+        call_assert_describe(all(ubounds == ubounds(1)), "main: matching input/output upper bounds")
+        call_assert_describe(all(abs(time_in(2:t_end) - time_out(1:t_end-1))<tolerance), "main: matching time stamps")
       end associate
 
       print *,"Calculating time derivatives"
@@ -227,11 +229,11 @@ subroutine compute_histograms(base_name, raw)
         end do
       end associate
 
-      call assert(.not. any(ieee_is_nan(dpt_dt)), ".not. any(ieee_is_nan(dpt_dt)")
-      call assert(.not. any(ieee_is_nan(dqv_dt)), ".not. any(ieee_is_nan(dqv_dt)")
-      call assert(.not. any(ieee_is_nan(dqc_dt)), ".not. any(ieee_is_nan(dqc_dt)")
-      call assert(.not. any(ieee_is_nan(dqr_dt)), ".not. any(ieee_is_nan(dqr_dt)")
-      call assert(.not. any(ieee_is_nan(dqs_dt)), ".not. any(ieee_is_nan(dqs_dt)")
+      call_assert(.not. any(ieee_is_nan(dpt_dt)))
+      call_assert(.not. any(ieee_is_nan(dqv_dt)))
+      call_assert(.not. any(ieee_is_nan(dqc_dt)))
+      call_assert(.not. any(ieee_is_nan(dqr_dt)))
+      call_assert(.not. any(ieee_is_nan(dqs_dt)))
 
       print *,"Calculating output tensor histograms."
       call system_clock(t_histo_start, clock_rate)
diff --git a/demo/app/train-cloud-microphysics.F90 b/demo/app/train-cloud-microphysics.F90
index 93ad7b79d..23428c857 100644
--- a/demo/app/train-cloud-microphysics.F90
+++ b/demo/app/train-cloud-microphysics.F90
@@ -1,16 +1,18 @@
 ! Copyright (c), The Regents of the University of California
 ! Terms of use are as specified in LICENSE.txt
+
+# include "assert_macros.h"
+
 program train_cloud_microphysics
-  !! Train a neural network to represent the simplest cloud microphysics model from
-  !! the Intermediate Complexity Atmospheric Research Model (ICAR) at
-  !! https://github.com/BerkeleyLab/icar.
+  !! Train a neural network to represent a cloud microphysics model from
+  !! [ICAR](https://go.lbl.gov/icar))
 
-  !! Intrinic modules :
+  !! Intrinsic modules :
   use iso_fortran_env, only : int64, real64
 
   !! External dependencies:
   use julienne_m, only : string_t, file_t, command_line_t, bin_t
-  use assert_m, only : assert, intrinsic_array_t
+  use assert_m
   use fiats_m, only : &
     neural_network_t, mini_batch_t, input_output_pair_t, tensor_t, trainable_network_t, tensor_map_t, training_configuration_t, &
     shuffle
@@ -20,16 +22,18 @@ program train_cloud_microphysics
   use NetCDF_file_m, only: NetCDF_file_t
   use NetCDF_variable_m, only: NetCDF_variable_t, tensors
   use occupancy_m, only : occupancy_t
+  use default_m, only: default_or_internal_read
+
   implicit none
 
-  character(len=*), parameter :: usage =                                                        new_line('a') // new_line('a') // &
-    'Usage: ' //                                                                                new_line('a') // new_line('a') // &
-    './build/run-fpm.sh run train-cloud-microphysics -- \'                                                    // new_line('a') // &
-    '  --base <string> --epochs <integer> \'                                                                  // new_line('a') // &
+  character(len=*), parameter :: usage =                                                          new_line('') // new_line('') // &
+    'Usage: ' //                                                                                  new_line('') // new_line('') // &
+    './build/run-fpm.sh run train-cloud-microphysics -- \'                                                     // new_line('') // &
+    '  --base <string> --epochs <integer> \'                                                                   // new_line('') // &
     '  [--start <integer>] [--end <integer>] [--stride <integer>] [--bins <integer>] [--report <integer>] [--tolerance <real>]'// &
-                                                                                                new_line('a') // new_line('a') // &
-    'where angular brackets denote user-provided values and square brackets denote optional arguments.'       // new_line('a') // &
-    'The presence of a file named "stop" halts execution gracefully.'
+                                                                                                  new_line('') // new_line('') // &
+    'where angular brackets denote user-provided values and square brackets denote optional arguments.'        // new_line('') // &
+    'The presence of a file named "stop" halts execution gracefully.'                                          // new_line('')
 
   type command_line_arguments_t 
     integer num_epochs, start_step, stride, num_bins, report_step
@@ -108,7 +112,7 @@ function get_command_line_arguments() result(command_line_arguments)
     integer, allocatable :: end_step
     integer num_epochs, num_bins, start_step, stride, report_step
 
-    base_name = command_line%flag_value("--base") ! gfortran 13 seg faults if this is an association
+    base_name = command_line%flag_value("--base")
     epochs_string = command_line%flag_value("--epochs")
     start_string = command_line%flag_value("--start")
     end_string = command_line%flag_value("--end")
@@ -123,11 +127,11 @@ function get_command_line_arguments() result(command_line_arguments)
 
     read(epochs_string,*) num_epochs
 
-    stride         = default_integer_or_read(1,    stride_string)
-    start_step     = default_integer_or_read(1,     start_string)
-    report_step    = default_integer_or_read(1,    report_string)
-    num_bins       = default_integer_or_read(3,      bins_string)
-    cost_tolerance = default_real_or_read(5E-8, tolerance_string)
+    stride         = default_or_internal_read(1,    stride_string)
+    start_step     = default_or_internal_read(1,     start_string)
+    report_step    = default_or_internal_read(1,    report_string)
+    num_bins       = default_or_internal_read(3,      bins_string)
+    cost_tolerance = default_or_internal_read(5E-8, tolerance_string)
 
     if (len(end_string)/=0) then
       allocate(end_step)
@@ -183,7 +187,7 @@ subroutine read_train_write(training_configuration, args, plot_file)
           end do
 
           do v = 2, size(input_variable)
-            call assert(input_variable(v)%conformable_with(input_variable(1)), "train_cloud_microphysics: input variable conformance")
+            call_assert(input_variable(v)%conformable_with(input_variable(1)))
           end do
 
           print *,"- reading time"
@@ -212,13 +216,13 @@ subroutine read_train_write(training_configuration, args, plot_file)
           end do
 
           do v = 1, size(output_variable)
-            call assert(output_variable(v)%conformable_with(input_variable(1)), "train_cloud_microphysics: output variable conformance")
+            call_assert(output_variable(v)%conformable_with(input_variable(1)))
           end do
 
           print *,"- reading time"
           call output_time%input("time", output_file, rank=1)
 
-          call assert(output_time%conformable_with(input_time), "train_cloud_microphysics: input/output time conformance")
+          call_assert(output_time%conformable_with(input_time))
 
         end associate output_file
       end associate output_file_name
@@ -234,7 +238,7 @@ subroutine read_train_write(training_configuration, args, plot_file)
           associate(derivative_name => "d" // output_names(v)%string() // "/dt")
             print *,"- " // derivative_name
             derivative(v) = NetCDF_variable_t( (input_variable(v) - output_variable(v)) / dt, derivative_name)
-            call assert(.not. derivative(v)%any_nan(), "train_cloud_microhphysics: non NaN's")
+            call_assert(.not. derivative(v)%any_nan())
           end associate derivative_name
         end do
       end associate dt
@@ -436,30 +440,4 @@ subroutine read_train_write(training_configuration, args, plot_file)
 
   end subroutine read_train_write
 
-  pure function default_integer_or_read(default, string) result(set_value)
-    integer, intent(in) :: default
-    character(len=*), intent(in) :: string
-    integer set_value
-    
-    if (len(string)==0) then
-      set_value = default
-    else
-      read(string,*) set_value
-    end if
-
-  end function
-
-  pure function default_real_or_read(default, string) result(set_value)
-    real, intent(in) :: default
-    character(len=*), intent(in) :: string
-    real set_value
-    
-    if (len(string)==0) then
-      set_value = default
-    else
-      read(string,*) set_value
-    end if
-
-  end function
-
 end program train_cloud_microphysics
diff --git a/demo/fpm.toml b/demo/fpm.toml
index 729eb03ac..01aa82e17 100644
--- a/demo/fpm.toml
+++ b/demo/fpm.toml
@@ -4,7 +4,7 @@ author     = "(Please see fiats/fpm.toml.)"
 maintainer = "(Please see fiats/fpm.toml.)"
 
 [dependencies]
-assert = {git = "https://github.com/sourceryinstitute/assert", tag = "1.7.0"}
+assert = {git = "https://github.com/sourceryinstitute/assert", tag = "2.0.0"}
 julienne = {git = "https://github.com/berkeleylab/julienne", tag = "1.5.3"}
 fiats = {path = "../"}
 netcdf-interfaces = {git = "https://github.com/LKedward/netcdf-interfaces.git", rev = "d2bbb71ac52b4e346b62572b1ca1620134481096"}
diff --git a/demo/src/NetCDF_file_s.f90 b/demo/src/NetCDF_file_s.F90
similarity index 53%
rename from demo/src/NetCDF_file_s.f90
rename to demo/src/NetCDF_file_s.F90
index e1b40908a..cd5926a87 100644
--- a/demo/src/NetCDF_file_s.f90
+++ b/demo/src/NetCDF_file_s.F90
@@ -1,11 +1,14 @@
 ! Copyright (c), The Regents of the University of California
 ! Terms of use are as specified in LICENSE.txt
+
+#include "assert_macros.h"
+
 submodule(netCDF_file_m) netCDF_file_s
   use netcdf, only : &
      nf90_create, nf90_def_dim, nf90_def_var, nf90_enddef, nf90_put_var, nf90_inquire_dimension, & ! functions
      nf90_close, nf90_open, nf90_inq_varid, nf90_get_var, nf90_inquire_variable, &
      nf90_clobber, nf90_noerr, nf90_strerror, nf90_int, nf90_nowrite ! constants
-  use assert_m, only : assert, intrinsic_array_t
+  use assert_m
   implicit none
 
 contains
@@ -25,21 +28,18 @@ function get_shape(ncid, varname) result(array_shape)
     integer,dimension(max_rank+1) :: dims, dimIds
     associate(nf_status => nf90_inq_varid(ncid, varname, varid))
       write(varid_string, *) varid
-      call assert(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inq_varid " // trim(nf90_strerror(nf_status)), &
-        diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
+      call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inq_varid " // trim(nf90_strerror(nf_status)), diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
     end associate
     associate(nf_status => nf90_inquire_variable(ncid, varid, ndims = var_rank))
-      call assert(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inquire_variable" // trim(nf90_strerror(nf_status)), &
-        trim(nf90_strerror(nf_status)) // "(" // varname // ")")
+      call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inquire_variable" // trim(nf90_strerror(nf_status)), trim(nf90_strerror(nf_status)) // "(" // varname // ")")
+        
     end associate
     associate(nf_status => nf90_inquire_variable(ncid, varid, dimids = dimIds(:var_rank)))
-      call assert(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inquire_variable" // trim(nf90_strerror(nf_status)), &
-        trim(nf90_strerror(nf_status)) // "(" // varname // ")")
+      call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inquire_variable" // trim(nf90_strerror(nf_status)), trim(nf90_strerror(nf_status)) // "(" // varname // ")")
     end associate
     do i=1,var_rank
       associate(nf_status => nf90_inquire_dimension(ncid, dimIds(i), len = dimlen))
-        call assert(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inquire_dimension" // trim(nf90_strerror(nf_status)),&
-          trim(nf90_strerror(nf_status)) // "(" // varname // ")")
+        call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(get_shape): nf90_inquire_dimension" // trim(nf90_strerror(nf_status)), trim(nf90_strerror(nf_status)) // "(" // varname // ")")
       end associate
       dims(i+1)=dimlen
     end do
@@ -52,48 +52,46 @@ function get_shape(ncid, varname) result(array_shape)
     integer ncid, varid
 
     associate( nf_status => nf90_open(self%file_name_, nf90_nowrite, ncid) ) ! open file with read-only acces
-      call assert(nf_status == nf90_noerr, &
-        "Net_CDF_file_m(input_integer): nf90_open" // trim(nf90_strerror(nf_status)), &
-        diagnostic_data = trim(nf90_strerror(nf_status)) // self%file_name_)
+      call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(input_integer): nf90_open" // trim(nf90_strerror(nf_status)), diagnostic_data = trim(nf90_strerror(nf_status)) // self%file_name_)
     end associate
 
     associate( nf_status => nf90_inq_varid(ncid, varname, varid)) ! get variable's ID
       write(varid_string, *) varid
-      call assert(nf_status == nf90_noerr, "Net_CDF_file_m(input_integer): nf90_inq_varid " // trim(nf90_strerror(nf_status)), &
-        diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
+      call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(input_integer): nf90_inq_varid " // trim(nf90_strerror(nf_status)), diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
+        
     end associate
 
     select rank(values)
       rank(1)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_integer): size(array_shape)==rank(values)")
+          call_assert(size(array_shape)==rank(values))
           allocate(values(array_shape(1)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(2)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_integer): size(array_shape)==rank(values)")
+          call_assert(size(array_shape)==rank(values))
           allocate(values(array_shape(1), array_shape(2)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(3)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_integer): size(array_shape)==rank(values)")
+          call_assert(size(array_shape)==rank(values))
           allocate(values(array_shape(1), array_shape(2), array_shape(3)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(4)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_integer): size(array_shape)==rank(values)")
+          call_assert(size(array_shape)==rank(values))
           allocate(values(array_shape(1), array_shape(2), array_shape(3), array_shape(4)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "NetCDF_file_s(input_integer): nf90_get_var", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank default
@@ -107,51 +105,45 @@ function get_shape(ncid, varname) result(array_shape)
     integer ncid, varid
 
     associate( nf_status => nf90_open(self%file_name_, nf90_nowrite, ncid) ) ! open file with read-only acces
-      call assert(nf_status == nf90_noerr, "nf90_open(self%file_name_, NF90_NOWRITE, ncid)", &
-        trim(nf90_strerror(nf_status)) // self%file_name_)
+      call_assert_diagnose(nf_status == nf90_noerr, "nf90_open(self%file_name_, NF90_NOWRITE, ncid)", trim(nf90_strerror(nf_status)) // self%file_name_)
     end associate
 
     associate( nf_status => nf90_inq_varid(ncid, varname, varid)) ! get variable's ID
       write(varid_string, *) varid
-      call assert(nf_status == nf90_noerr, "Net_CDF_file_m(input_double): nf90_inq_varid " // trim(nf90_strerror(nf_status)), &
-        diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
+      call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(input_double): nf90_inq_varid " // trim(nf90_strerror(nf_status)), diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
     end associate
 
     select rank(values)
       rank(1)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert_diagnose(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(2)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert_diagnose(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1),array_shape(2)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(3)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1),array_shape(2),array_shape(3)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(4)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert_diagnose(size(array_shape)==rank(values), "netCDF_file_s(input_double): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1),array_shape(2),array_shape(3),array_shape(4)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank default
@@ -165,56 +157,50 @@ function get_shape(ncid, varname) result(array_shape)
     integer ncid, varid
 
     associate( nf_status => nf90_open(self%file_name_, nf90_nowrite, ncid) ) ! open file with read-only acces
-      call assert(nf_status == nf90_noerr, "nf90_open(self%file_name_, NF90_NOWRITE, ncid)", &
-        trim(nf90_strerror(nf_status)) // self%file_name_)
+      call_assert_diagnose(nf_status == nf90_noerr, "nf90_open(self%file_name_, NF90_NOWRITE, ncid)", trim(nf90_strerror(nf_status)) // self%file_name_)
     end associate
 
     associate( nf_status => nf90_inq_varid(ncid, varname, varid)) ! get variable's ID
       write(varid_string, *) varid
-      call assert(nf_status == nf90_noerr, "Net_CDF_file_m(input_real): nf90_inq_varid " // trim(nf90_strerror(nf_status)), &
-        diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
+      call_assert_diagnose(nf_status == nf90_noerr, "Net_CDF_file_m(input_real): nf90_inq_varid " // trim(nf90_strerror(nf_status)), diagnostic_data = "varname '" // varname // "', varid " // trim(adjustl(varid_string)))
     end associate
 
     select rank(values)
       rank(0)
         allocate(values)
         associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-          call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, values)", trim(nf90_strerror(nf_status)))
+          call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, values)", trim(nf90_strerror(nf_status)))
         end associate
       rank(1)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert_diagnose(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(2)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert_diagnose(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1), array_shape(2)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(3)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert_diagnose(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1), array_shape(2), array_shape(3)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank(4)
         associate(array_shape => get_shape(ncid, varname))
-          call assert(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", &
-            intrinsic_array_t([size(array_shape),rank(values)]))
+          call_assert_diagnose(size(array_shape)==rank(values), "netCDF_file_s(input_real): size(array_shape)==rank(values)", intrinsic_array_t([size(array_shape),rank(values)]))
           allocate(values(array_shape(1), array_shape(2), array_shape(3), array_shape(4)))
           associate( nf_status => nf90_get_var(ncid, varid, values)) ! read data
-            call assert(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
+            call_assert_diagnose(nf_status == nf90_noerr, "nf90_get_var(ncid, varid, array)", trim(nf90_strerror(nf_status)))
           end associate
         end associate
       rank default
diff --git a/demo/src/NetCDF_variable_s.f90 b/demo/src/NetCDF_variable_s.F90
similarity index 86%
rename from demo/src/NetCDF_variable_s.f90
rename to demo/src/NetCDF_variable_s.F90
index 6c18e0f98..c2a3d5c68 100644
--- a/demo/src/NetCDF_variable_s.f90
+++ b/demo/src/NetCDF_variable_s.F90
@@ -1,9 +1,13 @@
 ! Copyright (c), The Regents of the University of California
 ! Terms of use are as specified in LICENSE.txt
+
+#include "assert_macros.h"
+
 submodule(NetCDF_variable_m) NetCDF_variable_s
   use ieee_arithmetic, only : ieee_is_nan
   use kind_parameters_m, only : default_real
-  use assert_m, only : assert, intrinsic_array_t
+  use assert_m
+  use default_m, only : default_or_present_value
   implicit none
 
   interface components_allocated
@@ -21,11 +25,6 @@
     module procedure double_precision_upper_bounds
   end interface
 
-  interface default_if_not_present
-    module procedure default_integer_if_not_present
-    module procedure default_real_if_not_present
-  end interface
-
 contains
 
   module procedure default_real_copy
@@ -142,14 +141,14 @@ pure function double_precision_components_allocated(NetCDF_variable) result(allo
 
   module procedure default_real_rank
     associate(allocation_vector => components_allocated(self))
-      call assert(count(allocation_vector) == 1, "NetCDF_variable_s(default_real_rank): allocation count")
+      call_assert(count(allocation_vector) == 1)
       my_rank = findloc(allocation_vector, .true., dim=1)
     end associate
   end procedure
 
   module procedure double_precision_rank
     associate(allocation_vector => components_allocated(self))
-      call assert(count(allocation_vector) == 1, "NetCDF_variable_s(double_precision_rank): allocation count")
+      call_assert(count(allocation_vector) == 1)
       my_rank = findloc(allocation_vector, .true., dim=1)
     end associate
   end procedure
@@ -266,8 +265,8 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
 
   module procedure default_real_subtract
 
-    call assert(lhs%conformable_with(rhs), "NetCDF_variable_s(default_real_subtract): lhs%conformable_with(rhs)")
-    call assert(lhs%name_==rhs%name_, "NetCDF_variable_s(default_real_subtract): lhs%name_==rhs%name_", lhs%name_//"/="//rhs%name_)
+    call_assert(lhs%conformable_with(rhs))
+    call_assert_diagnose(lhs%name_==rhs%name_, "NetCDF_variable_s(default_real_subtract): lhs%name_==rhs%name_", lhs%name_//"/="//rhs%name_)
 
     difference%name_ = lhs%name_
 
@@ -287,8 +286,8 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
 
   module procedure double_precision_subtract
 
-    call assert(lhs%conformable_with(rhs), "NetCDF_variable_s(double_precision_subtract): lhs%conformable_with(rhs)")
-    call assert(lhs%name_ == rhs%name_, "NetCDF_variable_s(double_precision_subtract): lhs%name_==rhs%name_",lhs%name_//"/="//rhs%name_)
+    call_assert(lhs%conformable_with(rhs))
+    call_assert_diagnose(lhs%name_ == rhs%name_, "NetCDF_variable_s(double_precision_subtract): lhs%name_==rhs%name_",lhs%name_//"/="//rhs%name_)
 
     difference%name_ = lhs%name_
 
@@ -310,14 +309,14 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
 
     integer t
 
-    call assert(rhs%rank()==1, "NetCDF_variable_s(default_real_divide): rhs%rank()==1")
+    call_assert(rhs%rank()==1)
 
     associate(t_end => size(rhs%values_1D_))
 
       select case(lhs%rank())
       case(4)
 
-        call assert(size(rhs%values_1D_) == size(lhs%values_4D_,4), "NetCDF_variable_s(default_real_divide): conformable numerator/denominator")
+        call_assert_describe(size(rhs%values_1D_) == size(lhs%values_4D_,4), "NetCDF_variable_s(default_real_divide): conformable numerator/denominator")
         allocate(ratio%values_4D_, mold = lhs%values_4D_)
 
         do concurrent(t = 1:t_end)
@@ -336,14 +335,14 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
 
     integer t
 
-    call assert(rhs%rank()==1, "NetCDF_variable_s(double_precision_divide): rhs%rank()==1")
+    call_assert(rhs%rank()==1)
 
     associate(t_end => size(rhs%values_1D_))
 
       select case(lhs%rank())
       case(4)
 
-        call assert(size(rhs%values_1D_) == size(lhs%values_4D_,4), "NetCDF_variable_s(double_precision_divide): conformable numerator/denominator")
+        call_assert_describe(size(rhs%values_1D_) == size(lhs%values_4D_,4), "NetCDF_variable_s(double_precision_divide): conformable numerator/denominator")
         allocate(ratio%values_4D_, mold = lhs%values_4D_)
 
         do concurrent(t = 1:t_end)
@@ -371,7 +370,7 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
     case default
       error stop "NetCDF_variable_s(default_real_assign): unsupported rank)"
     end select
-    call assert(lhs%rank()==rhs%rank(), "NetCDF_variable_s(default_real_assign): ranks match)")
+    call_assert(lhs%rank()==rhs%rank())
   end procedure
 
   module procedure double_precision_assign
@@ -387,7 +386,7 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
     case default
       error stop "NetCDF_variable_s(double_precision_assign): unsupported rank)"
     end select
-    call assert(lhs%rank()==rhs%rank(), "NetCDF_variable_s(double_precision_assign): ranks match)")
+    call_assert(lhs%rank()==rhs%rank())
   end procedure
 
   module procedure default_real_any_nan
@@ -429,9 +428,9 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
     select case(NetCDF_variables(1)%rank())
     case(4)
 
-      t_start  = default_if_not_present(1, step_start )
-      t_stride = default_if_not_present(1, step_stride)
-      t_end    = default_if_not_present(size(NetCDF_variables(1)%values_4D_,4), step_end)
+      t_start  = default_or_present_value(1, step_start )
+      t_stride = default_or_present_value(1, step_stride)
+      t_end    = default_or_present_value(size(NetCDF_variables(1)%values_4D_,4), step_end)
 
       associate( longitudes => size(NetCDF_variables(1)%values_4D_,1) &
                 ,latitudes  => size(NetCDF_variables(1)%values_4D_,2) &
@@ -541,28 +540,4 @@ pure function double_precision_upper_bounds(NetCDF_variable) result(ubounds)
     end select 
   end procedure
 
-  pure function default_integer_if_not_present(default_value, optional_argument) result(set_value)
-    integer, intent(in) :: default_value
-    integer, intent(in), optional :: optional_argument
-    integer set_value
-    
-    if (present(optional_argument)) then
-      set_value = optional_argument
-    else
-      set_value = default_value
-    end if
-  end function
-
-  pure function default_real_if_not_present(default_value, optional_argument) result(set_value)
-    real, intent(in) :: default_value
-    real, intent(in), optional :: optional_argument
-    real set_value
-    
-    if (present(optional_argument)) then
-      set_value = optional_argument
-    else
-      set_value = default_value
-    end if
-  end function
-
 end submodule NetCDF_variable_s
\ No newline at end of file
diff --git a/demo/src/default_m.f90 b/demo/src/default_m.f90
new file mode 100644
index 000000000..de6f6153c
--- /dev/null
+++ b/demo/src/default_m.f90
@@ -0,0 +1,51 @@
+! Copyright (c), The Regents of the University of California
+! Terms of use are as specified in LICENSE.txt
+module default_m
+  !! Define functions to choose between default values and alternative values
+  implicit none     
+
+  private
+  public :: default_or_internal_read
+  public :: default_or_present_value
+
+  interface default_or_internal_read
+
+    pure module function default_integer_or_internal_read(default_value, string) result(set_value)
+      !! result is read from string if len(string)/=0, default_value otherwise
+      implicit none
+      integer, intent(in) :: default_value
+      character(len=*), intent(in) :: string
+      integer set_value
+    end function 
+
+    pure module function default_real_or_internal_read(default_value, string) result(set_value)
+      !! result is read from string if len(string)/=0, default_value otherwise
+      implicit none
+      real, intent(in) :: default_value
+      character(len=*), intent(in) :: string
+      real set_value
+    end function
+
+  end interface
+
+  interface default_or_present_value
+
+    pure module function default_integer_or_present_value(default_value, optional_value) result(set_value)
+      !! result is default_value if optional_value not present, optional_value otherwise
+      implicit none
+      integer, intent(in) :: default_value
+      integer, intent(in), optional :: optional_value
+      integer set_value
+    end function 
+
+    pure module function default_real_or_present_value(default_value, optional_value) result(set_value)
+      !! result is default_value if optional_value not present, optional_value otherwise
+      implicit none
+      real, intent(in) :: default_value
+      real, intent(in), optional :: optional_value
+      real set_value
+    end function
+
+  end interface
+
+end module
diff --git a/demo/src/default_s.f90 b/demo/src/default_s.f90
new file mode 100644
index 000000000..bb29142bc
--- /dev/null
+++ b/demo/src/default_s.f90
@@ -0,0 +1,48 @@
+! Copyright (c), The Regents of the University of California
+! Terms of use are as specified in LICENSE.txt
+submodule(default_m) default_s
+  implicit none
+
+contains
+
+  module procedure default_integer_or_present_value
+    
+    if (present(optional_value)) then
+      set_value = optional_value
+    else
+      set_value = default_value
+    end if
+
+  end procedure
+
+  module procedure default_real_or_present_value
+    
+    if (present(optional_value)) then
+      set_value = optional_value
+    else
+      set_value = default_value
+    end if
+
+  end procedure
+
+  module procedure default_integer_or_internal_read
+    
+    if (len(string)/=0) then
+      read(string,*) set_value
+    else
+      set_value = default_value
+    end if
+
+  end procedure
+
+  module procedure default_real_or_internal_read
+    
+    if (len(string)/=0) then
+      read(string,*) set_value
+    else
+      set_value = default_value
+    end if
+
+  end procedure
+
+end submodule default_s
\ No newline at end of file
diff --git a/demo/src/histogram_s.f90 b/demo/src/histogram_s.F90
similarity index 90%
rename from demo/src/histogram_s.f90
rename to demo/src/histogram_s.F90
index a8936118d..59d18af17 100644
--- a/demo/src/histogram_s.f90
+++ b/demo/src/histogram_s.F90
@@ -1,7 +1,10 @@
 ! Copyright (c), The Regents of the University of California
 ! Terms of use are as specified in LICENSE.txt
+
+#include "assert_macros.h"
+
 submodule(histogram_m) histogram_s
-  use assert_m, only : assert, intrinsic_array_t
+  use assert_m
   use julienne_m, only : string_t, operator(.cat.)
   implicit none
 
@@ -73,10 +76,9 @@
         block 
           integer h, b ! histogram number, bin number
 
-          call assert(num_bins > 0, "histogram_s(to_file): num_bins > 0")
-          call assert(all(histograms(1)%num_bins() == [(histograms(h)%num_bins() , h=1,size(histograms))]), &
-            "histogram_s(to_file): uniform number of bins")
-
+          call_assert(num_bins > 0)
+          call_assert_describe(all(histograms(1)%num_bins() == [(histograms(h)%num_bins() , h=1,size(histograms))]), "histogram_s(to_file): uniform number of bins")
+            
           allocate(columns(num_bins))
           do b = 1, num_bins
             columns(b) =  string_t(histograms(1)%bin_value_(b)) // &
@@ -95,7 +97,7 @@
   pure function normalize(x, x_min, x_max) result(x_normalized)
     real, intent(in) :: x(:,:,:,:), x_min, x_max
     real, allocatable :: x_normalized(:,:,:,:)
-    call assert(x_min/=x_max, "histogram_m(normalize): x_min/=x_max", intrinsic_array_t([x_min, x_max]))
+    call_assert_diagnose(x_min/=x_max, "histogram_m(normalize): x_min/=x_max", intrinsic_array_t([x_min, x_max]))
     x_normalized = (x - x_min)/(x_max - x_min)
   end function
 
@@ -150,7 +152,7 @@ pure function normalize(x, x_min, x_max) result(x_normalized)
         end associate
       end associate
       associate(binned => sum(bin_count))
-        call assert(cardinality == binned, "histogram_s(construct): lossless binning", intrinsic_array_t([cardinality, binned]))
+        call_assert_diagnose(cardinality == binned, "histogram_s(construct): lossless binning", intrinsic_array_t([cardinality, binned]))
       end associate
     end associate
 
diff --git a/demo/src/occupancy_m.f90 b/demo/src/occupancy_m.f90
index 15b2ef247..e095c19c9 100644
--- a/demo/src/occupancy_m.f90
+++ b/demo/src/occupancy_m.f90
@@ -1,3 +1,5 @@
+! Copyright (c), The Regents of the University of California
+! Terms of use are as specified in LICENSE.txt
 module occupancy_m
   use iso_fortran_env, only : int64
   implicit none
diff --git a/demo/src/occupancy_s.f90 b/demo/src/occupancy_s.F90
similarity index 96%
rename from demo/src/occupancy_s.f90
rename to demo/src/occupancy_s.F90
index 3b4e4a44e..a8720d0b5 100644
--- a/demo/src/occupancy_s.f90
+++ b/demo/src/occupancy_s.F90
@@ -1,5 +1,10 @@
+! Copyright (c), The Regents of the University of California
+! Terms of use are as specified in LICENSE.txt
+
+#include "assert_macros.h"
+
 submodule(occupancy_m) occupancy_s
-  use assert_m, only : assert, intrinsic_array_t
+  use assert_m
   implicit none
 
 contains
@@ -81,7 +86,7 @@ end function allocations
       error stop "occupancy_s(vacate): unsupported rank"
     end select
 
-    call assert(self%allocated_dim()==size(dims), "occupancy_s(vacate): count(self%allocations()) == 1")
+    call_assert(self%allocated_dim()==size(dims))
   
   end procedure vacate
 
@@ -171,7 +176,7 @@ end function allocations
 
   module procedure num_occupied
 
-      call assert(count(allocations(self))==1, "occupancy_s(allocated_dim): count(self%allocations()) == 1")
+      call_assert(count(allocations(self))==1)
 
       select case(self%allocated_dim())
       case(1)
@@ -252,7 +257,7 @@ end function allocations
   module procedure allocated_dim
 
     associate(my_allocations => allocations(self))
-      call assert(count(my_allocations)==1, "occupancy_s(allocated_dim): count(self%allocations()) == 1")
+      call_assert(count(my_allocations)==1)
       my_dim = findloc(my_allocations, .true., dim=1)
     end associate
 
diff --git a/demo/test/main.F90 b/demo/test/main.F90
new file mode 100644
index 000000000..142657420
--- /dev/null
+++ b/demo/test/main.F90
@@ -0,0 +1,42 @@
+! Copyright (c), The Regents of the University of California
+! Terms of use are as specified in LICENSE.txt
+
+#include "language-support.F90"
+
+program main
+  use netCDF_file_test_m, only : netCDF_file_test_t
+  use iso_fortran_env, only : int64, real64
+  use julienne_m, only : command_line_t
+  implicit none
+
+  integer(int64) t_start, t_finish, clock_rate
+  type(netCDF_file_test_t) netCDF_file_test
+  integer :: passes=0, tests=0
+
+  print_usage_if_help_requested: &
+  block
+    type(command_line_t) command_line
+    character(len=*), parameter :: usage = &
+      new_line('') // new_line('') // &
+      'Usage: fpm test -- [--help] | [--contains <substring>]' // &
+      new_line('') // new_line('') // &
+      'where square brackets ([]) denote optional arguments, a pipe (|) separates alternative arguments,' // new_line('') // &
+      'angular brackets (<>) denote a user-provided value, and passing a substring limits execution to' // new_line('') // &
+      'the tests with test subjects or test descriptions containing the user-specified substring.' // new_line('')
+    if (command_line%argument_present([character(len=len("--help"))::"--help","-h"])) stop usage
+  end block print_usage_if_help_requested
+
+  call system_clock(t_start, clock_rate)
+  call netCDF_file_test%report(passes, tests)
+  call system_clock(t_finish)
+
+  print *
+  print *,"Test suite execution time: ", real(t_finish - t_start, real64)/real(clock_rate, real64)
+  print *
+  print '(*(a,:,g0))',"_________ In total, ",passes," of ",tests, " tests pass. _________"
+#if defined(MULTI_IMAGE_SUPPORT)
+  sync all
+#endif
+  print *
+  if (passes/=tests) error stop "-------- One or more tests failed. See the above report. ---------"
+end program
diff --git a/demo/test/main.f90 b/demo/test/main.f90
deleted file mode 100644
index 43792108b..000000000
--- a/demo/test/main.f90
+++ /dev/null
@@ -1,30 +0,0 @@
-! Copyright (c), The Regents of the University of California
-! Terms of use are as specified in LICENSE.txt
-
-#include "language-support.F90"
-
-program main
-  use netCDF_file_test_m, only : netCDF_file_test_t
-  implicit none
-
-  real t_start, t_finish
-
-  integer :: passes=0, tests=0
-
-  call cpu_time(t_start)
-  block 
-    type(netCDF_file_test_t) netCDF_file_test
-    call netCDF_file_test%report(passes, tests)
-  end block
-  call cpu_time(t_finish)
-
-  print *
-  print *,"Test suite execution time: ",t_finish - t_start
-  print *
-  print '(*(a,:,g0))',"_________ In total, ",passes," of ",tests, " tests pass. _________"
-#if defined(MULTI_IMAGE_SUPPORT)
-  sync all
-#endif
-  print *
-  if (passes/=tests) error stop "-------- One or more tests failed. See the above report. ---------"
-end program
diff --git a/demo/test/netCDF_file_test_m.f90 b/demo/test/netCDF_file_test_m.F90
similarity index 61%
rename from demo/test/netCDF_file_test_m.f90
rename to demo/test/netCDF_file_test_m.F90
index 536e92e92..9eddc1655 100644
--- a/demo/test/netCDF_file_test_m.f90
+++ b/demo/test/netCDF_file_test_m.F90
@@ -1,14 +1,14 @@
 ! Copyright (c), The Regents of the University of California
 ! Terms of use are as specified in LICENSE.txt
-#ifndef __INTEL_FORTRAN
-!! Due to a suspected bug in the Intel ifx compiler, the above C preprocessor macro
-!! effectively eliminates this file's source code when building with an Intel compiler.
+
+#include "assert_macros.h"
+
 module NetCDF_file_test_m
   !! Define asymmetric tests for the NetCDF file interface
 
   ! External dependencies
-  use assert_m, only : assert
-  use julienne_m, only : string_t, test_t, test_result_t
+  use assert_m
+  use julienne_m, only : test_t, test_result_t, test_description_t, test_description_substring, string_t
   use netcdf, only : &
      nf90_create, nf90_def_dim, nf90_def_var, nf90_enddef, nf90_put_var, nf90_inquire_dimension, & ! functions
      nf90_close, nf90_open, nf90_inq_varid, nf90_get_var, nf90_inquire_variable, &
@@ -41,24 +41,22 @@ pure function subject() result(specimen)
 
   function results() result(test_results)
     type(test_result_t), allocatable :: test_results(:)
+    type(test_description_t), allocatable :: test_descriptions(:)
 
     character(len=*), parameter :: longest_description = &
           "writing and then reading gives input matching the output for a 1D double precision array"
 
+    test_descriptions = &
+      [ test_description_t("writing and then reading gives input matching the output for a 2D integer array", write_then_read_2D_integer), &
+        test_description_t("writing and then reading gives input matching the output for a 1D double precision array", write_then_read_1D_double) &
+      ]
     associate( &
-      descriptions => &
-        [ character(len=len(longest_description)) :: &
-          "writing and then reading gives input matching the output for a 2D integer array", &
-          "writing and then reading gives input matching the output for a 1D double precision array" &
-        ], &
-      outcomes => &
-        [ write_then_read_2D_integer(), & 
-          write_then_read_1D_double() &
-        ] & 
+      substring_in_subject => index(subject(), test_description_substring) /= 0, &
+      substring_in_description => test_descriptions%contains_text(string_t(test_description_substring)) &
     )
-      call assert(size(descriptions) == size(outcomes),"asymmetric_engine_test_m(results): size(descriptions) == size(outcomes)")
-      test_results = test_result_t(descriptions, outcomes)
+      test_descriptions = pack(test_descriptions, substring_in_subject .or. substring_in_description)
     end associate
+    test_results = test_descriptions%run()
        
   end function
 
@@ -69,26 +67,25 @@ subroutine output_2D_integer(file_name, data_out)
     integer ncid, varid, x_dimid, y_dimid
 
     associate(nf_status => nf90_create(file_name, nf90_clobber, ncid)) ! create or ovewrite file
-      call assert(nf_status == nf90_noerr, "nf90_create(file_name, nf90_clobber, ncid) succeeds",trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, "nf90_create(file_name, nf90_clobber, ncid) succeeds",trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_def_dim(ncid, "x", size(data_out,2), x_dimid)) ! define x dimension & get its ID
-      call assert(nf_status == nf90_noerr,'nf90_def_dim(ncid,"x",size(data_out,2),x_dimid) succeeds',trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr,'nf90_def_dim(ncid,"x",size(data_out,2),x_dimid) succeeds',trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_def_dim(ncid, "y", size(data_out,1), y_dimid)) ! define y dimension & get its ID
-      call assert(nf_status==nf90_noerr, 'nf90_def_dim(ncid,"y",size(data_out,2),y_dimid) succeeds', trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status==nf90_noerr, 'nf90_def_dim(ncid,"y",size(data_out,2),y_dimid) succeeds', trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_def_var(ncid, "data", nf90_int, [y_dimid, x_dimid], varid))!define integer 'data' variable & get ID
-      call assert(nf_status == nf90_noerr, 'nf90_def_var(ncid,"data",nf90_int,[y_dimid,x_dimid],varid) succeds', &
-        trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nf90_def_var(ncid,"data",nf90_int,[y_dimid,x_dimid],varid) succeds', trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_enddef(ncid)) ! exit define mode: tell NetCDF we are done defining metadata
-      call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_enddef(ncid)', trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nff90_noerr == nf90_enddef(ncid)', trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_put_var(ncid, varid, data_out)) ! write all data to file
-      call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_put_var(ncid, varid, data_out)', trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nff90_noerr == nf90_put_var(ncid, varid, data_out)', trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_close(ncid)) ! close file to free associated NetCDF resources and flush buffers
-      call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_close(ncid)', trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nff90_noerr == nf90_close(ncid)', trim(nf90_strerror(nf_status)))
     end associate
   end subroutine
 
@@ -99,28 +96,27 @@ subroutine output_1D_double(file_name, data_out)
     integer ncid, varid, x_dimid, y_dimid
 
     associate(nf_status => nf90_create(file_name, nf90_clobber, ncid)) ! create or ovewrite file
-      call assert(nf_status == nf90_noerr, "nf90_create(file_name, nf90_clobber, ncid) succeeds",trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, "nf90_create(file_name, nf90_clobber, ncid) succeeds",trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_def_dim(ncid, "x", size(data_out,1), x_dimid)) ! define x dimension & get its ID
-      call assert(nf_status == nf90_noerr,'nf90_def_dim(ncid,"x",size(data_out,2),x_dimid) succeeds',trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr,'nf90_def_dim(ncid,"x",size(data_out,2),x_dimid) succeeds',trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_def_var(ncid, "data", nf90_int, [x_dimid], varid))!define integer 'data' variable & get ID
-      call assert(nf_status == nf90_noerr, 'nf90_def_var(ncid,"data",nf90_int,[y_dimid,x_dimid],varid) succeds', &
-        trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nf90_def_var(ncid,"data",nf90_int,[y_dimid,x_dimid],varid) succeds', trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_enddef(ncid)) ! exit define mode: tell NetCDF we are done defining metadata
-      call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_enddef(ncid)', trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nff90_noerr == nf90_enddef(ncid)', trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_put_var(ncid, varid, data_out)) ! write all data to file
-      call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_put_var(ncid, varid, data_out)', trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nff90_noerr == nf90_put_var(ncid, varid, data_out)', trim(nf90_strerror(nf_status)))
     end associate
     associate(nf_status => nf90_close(ncid)) ! close file to free associated NetCDF resources and flush buffers
-      call assert(nf_status == nf90_noerr, 'nff90_noerr == nf90_close(ncid)', trim(nf90_strerror(nf_status)))
+      call_assert_diagnose(nf_status == nf90_noerr, 'nff90_noerr == nf90_close(ncid)', trim(nf90_strerror(nf_status)))
     end associate
   end subroutine
 
   function write_then_read_2D_integer() result(test_passes)
-    logical, allocatable :: test_passes(:)
+    logical test_passes
     integer i, j
     integer, parameter :: ny = 12,  nx = 6
     integer, parameter :: data_written(*,*) = reshape([((i*j, i=1,nx), j=1,ny)], [ny,nx])
@@ -133,12 +129,12 @@ function write_then_read_2D_integer() result(test_passes)
       call NetCDF_file%input("data", data_read)
     end associate
 
-    test_passes = [all(data_written == data_read)]
+    test_passes = all(data_written == data_read)
 
   end function
 
   function write_then_read_1D_double() result(test_passes)
-    logical, allocatable :: test_passes(:)
+    logical test_passes
     integer i
     integer, parameter :: nx = 6
     double precision, parameter :: data_written(*) = dble([(i, i=1,nx)]), tolerance = 1.E-15
@@ -151,9 +147,8 @@ function write_then_read_1D_double() result(test_passes)
       call NetCDF_file%input("data", data_read)
     end associate
 
-    test_passes = [all(abs(data_written - data_read)<tolerance)]
+    test_passes = all(abs(data_written - data_read)<tolerance)
 
   end function
 
-end module NetCDF_file_test_m
-#endif // __INTEL_FORTRAN
\ No newline at end of file
+end module NetCDF_file_test_m
\ No newline at end of file
