diff --git a/build/makefile b/build/makefile
index d9915c5..df7c65d 100644
--- a/build/makefile
+++ b/build/makefile
@@ -87,14 +87,9 @@ endif
 
 name    = amun
 
-files   = algebra blocks boundaries constants coordinates domains driver       \
-          equations evolution gravity integrals interpolations io mesh         \
-          mpitools operators parameters problems random refinement schemes     \
-          shapes sources timers user_problem
-
-sources := $(addprefix $(SRCSDIR)/,$(addsuffix .F90, $(files)))
-objects := $(addprefix $(OBJSDIR)/,$(addsuffix .o,   $(files)))
-modules := $(addprefix $(OBJSDIR)/,$(addsuffix .mod, $(files)))
+sources := $(wildcard $(SRCSDIR)/*.F90)
+objects := $(sources:$(SRCSDIR)/%.F90=$(OBJSDIR)/%.o)
+modules := $(sources:$(SRCSDIR)/%.F90=$(OBJSDIR)/%.mod)
 
 all: $(name).x
 
diff --git a/sources/boundaries.F90 b/sources/boundaries.F90
index c5708a4..2d7e293 100644
--- a/sources/boundaries.F90
+++ b/sources/boundaries.F90
@@ -358,6 +358,7 @@ module boundaries
 
 ! import external procedures and variables
 !
+    use helpers   , only : print_section, print_parameter
     use parameters, only : get_parameter
 
 ! local variables are not implicit by default
@@ -370,7 +371,8 @@ module boundaries
 
 ! local variables
 !
-    character(len=64) :: sfmts
+    character(len=80) :: msg
+    character(len=64) :: sfmt
     character(len=32) :: xlbndry = "periodic"
     character(len=32) :: xubndry = "periodic"
     character(len=32) :: ylbndry = "periodic"
@@ -389,13 +391,15 @@ module boundaries
       call get_parameter("zlbndry", zlbndry)
       call get_parameter("zubndry", zubndry)
 
-      write(*,*)
-      write(*,"(1x,a)") "Boundaries:"
-      sfmts = "(4x,a10,13x,'=',2(1x,a))"
-      write(*,sfmts) "X-boundary", trim(xlbndry), trim(xubndry)
-      write(*,sfmts) "Y-boundary", trim(ylbndry), trim(yubndry)
+      call print_section(verbose, "Boundaries")
+      sfmt = "(a,1x,'...',1x,a)"
+      write(msg,sfmt) trim(xlbndry), trim(xubndry)
+      call print_parameter(verbose, "X-boundary", msg)
+      write(msg,sfmt) trim(ylbndry), trim(yubndry)
+      call print_parameter(verbose, "Y-boundary", msg)
 #if NDIMS == 3
-      write(*,sfmts) "Z-boundary", trim(zlbndry), trim(zubndry)
+      write(msg,sfmt) trim(zlbndry), trim(zubndry)
+      call print_parameter(verbose, "Z-boundary", msg)
 #endif /* NDIMS == 3 */
 
     end if
diff --git a/sources/coordinates.F90 b/sources/coordinates.F90
index 33d0980..2c019ce 100644
--- a/sources/coordinates.F90
+++ b/sources/coordinates.F90
@@ -805,6 +805,10 @@ module coordinates
 !
   subroutine print_coordinates(verbose)
 
+! include external procedures
+!
+    use helpers  , only : print_section, print_parameter
+
 ! local variables are not implicit by default
 !
     implicit none
@@ -815,8 +819,9 @@ module coordinates
 
 ! local variables
 !
-    character(len=80) :: sfmts
-    integer           :: p, q
+    character(len= 80) :: sfmt
+    character(len=255) :: msg
+    integer            :: p, q
 
 ! local arrays
 !
@@ -833,30 +838,33 @@ module coordinates
       cm(:) = bm(:) * nc
       fm(:) = rm(:) * nc
 
-      write(*,*)
-      write(*,"(1x,a)") "Geometry:"
-      sfmts = "(4x,a,1x,i0)"
-      write(*,sfmts) "refinement to level    =", maxlev
-      write(*,sfmts) "number of block cells  =", nc
-      write(*,sfmts) "number of ghost zones  =", ng
-      write(sfmts,"(i0)") maxval(fm(1:NDIMS))
-      p = len(trim(adjustl(sfmts)))
-      write(sfmts,"(i0)") maxval(rm(1:NDIMS))
-      q = len(trim(adjustl(sfmts)))
+      call print_section(verbose, "Geometry")
+      call print_parameter(verbose, "refinement to level"  , maxlev)
+      call print_parameter(verbose, "number of block cells", nc    )
+      call print_parameter(verbose, "number of ghost zones", ng    )
+      write(msg,"(i0)") maxval(fm(1:NDIMS))
+      p = len(trim(adjustl(msg)))
+      write(msg,"(i0)") maxval(rm(1:NDIMS))
+      q = len(trim(adjustl(msg)))
 #if NDIMS == 3
-      write(sfmts,'(6(a,i0),a)') "(4x,a,1x,i", p, ",' x ',i", p, ",' x ',i", p,&
-                    ",'  (',i", q, ",' x ',i", q, ",' x ',i", q, ",' blocks)')"
+      write(sfmt,"(6(a,i0),a)") "('[',i", p, ",' x ',i", p, ",' x ',i", p,     &
+                 ",'] ([',i", q, ",' x ',i", q, ",' x ',i", q, ",'] blocks)')"
 #else /* NDIMS == 3 */
-      write(sfmts,'(4(a,i0),a)') "(4x,a,1x,i", p, ",' x ',i", p,               &
-                                   ",'  (',i", q, ",' x ',i", q, ",' blocks)')"
+      write(sfmt,"(4(a,i0),a)") "('[',i", p, ",' x ',i", p,                    &
+                 ",'] ([',i", q, ",' x ',i", q, ",'] blocks)')"
 #endif /* NDIMS == 3 */
-      write(*,sfmts) "base resolution        =", cm(1:NDIMS), bm(1:NDIMS)
-      write(*,sfmts) "effective resolution   =", fm(1:NDIMS), rm(1:NDIMS)
-      sfmts = "(4x,a,1x,1es12.5,1x,'...',1x,1es12.5)"
-      write(*,sfmts) "X-bounds               =", xmin, xmax
-      write(*,sfmts) "Y-bounds               =", ymin, ymax
+      write(msg,sfmt) cm(1:NDIMS), bm(1:NDIMS)
+      call print_parameter(verbose, "base resolution"      , msg   )
+      write(msg,sfmt) fm(1:NDIMS), rm(1:NDIMS)
+      call print_parameter(verbose, "effective resolution" , msg   )
+      sfmt = "(1es12.5,1x,'...',1x,1es12.5)"
+      write(msg,sfmt) xmin, xmax
+      call print_parameter(verbose, "X-bounds"             , msg   )
+      write(msg,sfmt) ymin, ymax
+      call print_parameter(verbose, "Y-bounds"             , msg   )
 #if NDIMS == 3
-      write(*,sfmts) "Z-bounds               =", zmin, zmax
+      write(msg,sfmt) zmin, zmax
+      call print_parameter(verbose, "Z-bounds"             , msg   )
 #endif /* NDIMS */
 
     end if
diff --git a/sources/driver.F90 b/sources/driver.F90
index 8b27ec9..1ed4f28 100644
--- a/sources/driver.F90
+++ b/sources/driver.F90
@@ -51,6 +51,7 @@ program amun
   use evolution      , only : advance, new_time_step
   use evolution      , only : step, time, dt
   use gravity        , only : initialize_gravity, finalize_gravity
+  use helpers        , only : print_welcome, print_section, print_parameter
   use integrals      , only : initialize_integrals, finalize_integrals
   use integrals      , only : store_integrals
   use interpolations , only : initialize_interpolations, finalize_interpolations
@@ -218,28 +219,14 @@ program amun
     go to 400
   end if
 
-! print the welcome message
+! print welcome messages
 !
-  if (master) then
-
-    write(*,"(1x,78('-'))")
-    write(*,"(1x,18('='),17x,a,17x,19('='))") 'A M U N'
-    write(*,"(1x,16('='),4x,a,4x,16('='))")                                    &
-                                      'Copyright (C) 2008-2019 Grzegorz Kowal'
-    write(*,"(1x,18('='),9x,a,9x,19('='))")                                    &
-                                        'under GNU GPLv3 license'
-    write(*,"(1x,78('-'))")
-
+  call print_welcome(master)
+  call print_section(master, "Parallelization")
 #ifdef MPI
-! print the parallelization type and the number of parallel processes
-!
-    write(*,*)
-    write(*,"(1x,a)") "Parallelization:"
-    write(*,"(4x,a,1x,i0)") "MPI processes          =", nprocs
+  call print_parameter(master, "MPI processes", nprocs)
 #endif /* MPI */
 
-  end if
-
 ! initialize and read parameters from the parameter file
 !
   if (master) call read_parameters(iterm)
@@ -390,6 +377,8 @@ program amun
 
 ! print module information
 !
+  call print_section(master, "Problem")
+  call print_parameter(master, "problem name", trim(problem))
   call print_equations(master)
   call print_sources(master)
   call print_coordinates(master)
diff --git a/sources/equations.F90 b/sources/equations.F90
index 87249f7..ab76e09 100644
--- a/sources/equations.F90
+++ b/sources/equations.F90
@@ -1029,7 +1029,7 @@ module equations
 
 ! include external procedures and variables
 !
-    use parameters, only : get_parameter
+    use helpers, only : print_section, print_parameter
 
 ! local variables are not implicit by default
 !
@@ -1041,35 +1041,31 @@ module equations
 
 ! local variables
 !
-    character(len=64) :: sfmts, sfmti
+    character(len= 80) :: sfmt
+    character(len=255) :: msg
 !
 !-------------------------------------------------------------------------------
-!
-! print information about the equation module
 !
     if (verbose) then
 
-      write(*,*)
-      write(*,"(1x,a)") "Physics:"
-      sfmts = "(4x,a,1x,a)"
-      write(*,sfmts) "equation system        =", trim(name_eqsys)
-      write(*,sfmts) "equation of state      =", trim(name_eos)
-      sfmti = "(4x,a,1x,i0)"
-      write(*,sfmti) "number of variables    =", nv
-      write(sfmti,"(a,i0,a)") "(4x,a,", nv, "(1x,a))"
-      write(*,sfmti) "conservative variables =", cvars
-      write(*,sfmti) "primitive variables    =", pvars
+      call print_section(verbose, "Physics")
+      call print_parameter(verbose, "equation system"       , name_eqsys)
+      call print_parameter(verbose, "equation of state"     , name_eos  )
+      call print_parameter(verbose, "number of variables"   , nv        )
+      write(sfmt,"(a,i0,a)") "(", nv, "(1x,a))"
+      write(msg,sfmt) cvars
+      call print_parameter(verbose, "conservative variables", msg       )
+      write(msg,sfmt) pvars
+      call print_parameter(verbose, "primitive variables"   , msg       )
       if (relativistic) then
-        write(*,sfmts) "variable conversion    =", trim(name_c2p)
+        call print_parameter(verbose, "variable conversion"   , name_c2p  )
       end if
-      sfmts = "(4x,a20,3x,'=',1x,a)"
       if (fix_unphysical_cells) then
-        write(*,sfmts) "fix unphysical cells", "on"
-        sfmti = "(4x,a20,3x,'=',1x,i0)"
-        write(*,sfmti) "ngavg               ", ngavg
-        write(*,sfmti) "npavg               ", npavg
+        call print_parameter(verbose, "fix unphysical cells"  , "on"      )
+        call print_parameter(verbose, "ngavg"                 , ngavg     )
+        call print_parameter(verbose, "npavg"                 , npavg     )
       else
-        write(*,sfmts) "fix unphysical cells", "off"
+        call print_parameter(verbose, "fix unphysical cells"  , "off"     )
       end if
 
     end if
diff --git a/sources/evolution.F90 b/sources/evolution.F90
index b8780ba..3957e91 100644
--- a/sources/evolution.F90
+++ b/sources/evolution.F90
@@ -284,6 +284,7 @@ module evolution
 ! import external procedures and variables
 !
     use equations, only : magnetized
+    use helpers  , only : print_section, print_parameter
 
 ! local variables are not implicit by default
 !
@@ -292,23 +293,16 @@ module evolution
 ! subroutine arguments
 !
     logical, intent(in) :: verbose
-
-! local variables
-!
-    character(len=64) :: sfmts
 !
 !-------------------------------------------------------------------------------
 !
     if (verbose) then
 
-      write(*,*)
-      write(*,"(1x,a)") "Evolution:"
-      sfmts = "(4x,a,1x,a)"
-      write(*,sfmts) "time advance           =", trim(name_int)
-      sfmts = "(4x,a,es9.2)"
-      write(*,sfmts) "CFL coefficient        =", cfl
+      call print_section(verbose, "Evolution")
+      call print_parameter(verbose, "time advance"         , name_int)
+      call print_parameter(verbose, "CFL coefficient"      , cfl     )
       if (magnetized) then
-        write(*,sfmts) "GLM alpha coefficient  =", alpha
+        call print_parameter(verbose, "GLM alpha coefficient", alpha   )
       end if
 
     end if
diff --git a/sources/helpers.F90 b/sources/helpers.F90
new file mode 100644
index 0000000..03aee1b
--- /dev/null
+++ b/sources/helpers.F90
@@ -0,0 +1,267 @@
+!!******************************************************************************
+!!
+!!  This file is part of the AMUN source code, a program to perform
+!!  Newtonian or relativistic magnetohydrodynamical simulations on uniform or
+!!  adaptive mesh.
+!!
+!!  Copyright (C) 2019 Grzegorz Kowal <grzegorz@amuncode.org>
+!!
+!!  This program 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 3 of the License, or
+!!  (at your option) any later version.
+!!
+!!  This program 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, see <http://www.gnu.org/licenses/>.
+!!
+!!******************************************************************************
+!!
+!! module: HELPERS
+!!
+!!  This module provides miscellaneous support subroutines.
+!!
+!!
+!!******************************************************************************
+!
+module helpers
+
+! module variables are not implicit by default
+!
+  implicit none
+
+! MODULE INTERFACES:
+! =================
+!
+  interface print_parameter
+    module procedure print_parameter_integer
+    module procedure print_parameter_double
+    module procedure print_parameter_string
+  end interface
+
+! by default everything is private
+!
+  private
+
+! declare public subroutines
+!
+  public :: print_welcome, print_section, print_parameter
+
+!- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+!
+  contains
+!
+!===============================================================================
+!!
+!!***  PUBLIC SUBROUTINES  *****************************************************
+!!
+!===============================================================================
+!
+!===============================================================================
+!
+! subroutine PRINT_WELCOME:
+! ------------------------
+!
+!   Subroutine prints welcome message.
+!
+!   Arguments:
+!
+!     verbose - if true, the subroutine is executed, otherwise it is skipped;
+!
+!===============================================================================
+!
+  subroutine print_welcome(verbose)
+
+! local variables are not implicit by default
+!
+    implicit none
+
+! subroutine arguments
+!
+    logical, intent(in) :: verbose
+!
+!-------------------------------------------------------------------------------
+!
+    if (.not. verbose) return
+
+    write(*,"(1x,78('-'))")
+    write(*,"(1x,18('='),17x,a,17x,19('='))") 'A M U N'
+    write(*,"(1x,16('='),4x,a,4x,16('='))")                                    &
+                                      'Copyright (C) 2008-2019 Grzegorz Kowal'
+    write(*,"(1x,18('='),9x,a,9x,19('='))")                                    &
+                                        'under GNU GPLv3 license'
+    write(*,"(1x,78('-'))")
+
+!-------------------------------------------------------------------------------
+!
+  end subroutine print_welcome
+!
+!===============================================================================
+!
+! subroutine PRINT_SECTION:
+! ------------------------
+!
+!   Subroutine prints section lines.
+!
+!   Arguments:
+!
+!     verbose - if true, the subroutine is executed, otherwise it is skipped;
+!     title   - the section title;
+!
+!===============================================================================
+!
+  subroutine print_section(verbose, title)
+
+! local variables are not implicit by default
+!
+    implicit none
+
+! subroutine arguments
+!
+    logical         , intent(in) :: verbose
+    character(len=*), intent(in) :: title
+!
+!-------------------------------------------------------------------------------
+!
+    if (.not. verbose) return
+
+    write(*,*)
+    write(*,"(1x,a,':')") trim(adjustl(title))
+
+!-------------------------------------------------------------------------------
+!
+  end subroutine print_section
+!
+!===============================================================================
+!
+! subroutine PRINT_PARAMETER_INTEGER:
+! ----------------------------------
+!
+!   Subroutine prints integer parameter.
+!
+!   Arguments:
+!
+!     verbose    - if true, the subroutine is executed, otherwise it is skipped;
+!     desciption - the parameter description;
+!     value      - the parameter value;
+!
+!===============================================================================
+!
+  subroutine print_parameter_integer(verbose, description, value)
+
+! local variables are not implicit by default
+!
+    implicit none
+
+! subroutine arguments
+!
+    logical         , intent(in) :: verbose
+    character(len=*), intent(in) :: description
+    integer         , intent(in) :: value
+
+! local variables
+!
+    character(len=26) :: msg
+!
+!-------------------------------------------------------------------------------
+!
+    if (.not. verbose) return
+
+    msg = trim(adjustl(description))
+    write(*,"(4x,a26,1x,'=',1x,i0)") msg, value
+
+!-------------------------------------------------------------------------------
+!
+  end subroutine print_parameter_integer
+!
+!===============================================================================
+!
+! subroutine PRINT_PARAMETER_DOUBLE:
+! ----------------------------------
+!
+!   Subroutine prints double precision parameter.
+!
+!   Arguments:
+!
+!     verbose    - if true, the subroutine is executed, otherwise it is skipped;
+!     desciption - the parameter description;
+!     value      - the parameter value;
+!
+!===============================================================================
+!
+  subroutine print_parameter_double(verbose, description, value)
+
+! local variables are not implicit by default
+!
+    implicit none
+
+! subroutine arguments
+!
+    logical         , intent(in) :: verbose
+    character(len=*), intent(in) :: description
+    real(kind=8)    , intent(in) :: value
+
+! local variables
+!
+    character(len=26) :: msg
+!
+!-------------------------------------------------------------------------------
+!
+    if (.not. verbose) return
+
+    msg = trim(adjustl(description))
+    write(*,"(4x,a26,1x,'=',1x,es9.2)") msg, value
+
+!-------------------------------------------------------------------------------
+!
+  end subroutine print_parameter_double
+!
+!===============================================================================
+!
+! subroutine PRINT_PARAMETER_STRING:
+! ---------------------------------
+!
+!   Subroutine prints string parameter.
+!
+!   Arguments:
+!
+!     verbose    - if true, the subroutine is executed, otherwise it is skipped;
+!     desciption - the parameter description;
+!     value      - the parameter value;
+!
+!===============================================================================
+!
+  subroutine print_parameter_string(verbose, description, value)
+
+! local variables are not implicit by default
+!
+    implicit none
+
+! subroutine arguments
+!
+    logical         , intent(in) :: verbose
+    character(len=*), intent(in) :: description
+    character(len=*), intent(in) :: value
+
+! local variables
+!
+    character(len=26) :: msg
+!
+!-------------------------------------------------------------------------------
+!
+    if (.not. verbose) return
+
+    msg = trim(adjustl(description))
+    write(*,"(4x,a26,1x,'=',1x,a)") msg, trim(adjustl(value))
+
+!-------------------------------------------------------------------------------
+!
+  end subroutine print_parameter_string
+
+!===============================================================================
+!
+end module helpers
diff --git a/sources/interpolations.F90 b/sources/interpolations.F90
index 3f6350d..048408b 100644
--- a/sources/interpolations.F90
+++ b/sources/interpolations.F90
@@ -547,6 +547,10 @@ module interpolations
 !
   subroutine print_interpolations(verbose)
 
+! import external procedures and variables
+!
+    use helpers, only : print_section, print_parameter
+
 ! local variables are not implicit by default
 !
     implicit none
@@ -554,36 +558,29 @@ module interpolations
 ! subroutine arguments
 !
     logical, intent(in) :: verbose
-
-! local variables
-!
-    character(len=64) :: sfmts
 !
 !-------------------------------------------------------------------------------
 !
     if (verbose) then
-
-      write(*,*)
-      write(*,"(1x,a)") "Interpolations:"
-      sfmts = "(4x,a,1x,a)"
-      write(*,sfmts) "reconstruction         =", trim(name_rec)
-      write(*,sfmts) "TVD limiter            =", trim(name_tlim)
-      write(*,sfmts) "prolongation limiter   =", trim(name_plim)
+      call print_section(verbose, "Interpolations")
+      call print_parameter(verbose, "reconstruction"      , name_rec )
+      call print_parameter(verbose, "TVD limiter"         , name_tlim)
+      call print_parameter(verbose, "prolongation limiter", name_plim)
       if (mlp) then
-        write(*,sfmts) "MLP limiting           =", "on"
+        call print_parameter(verbose, "MLP limiting"        , "on"     )
       else
-        write(*,sfmts) "MLP limiting           =", "off"
+        call print_parameter(verbose, "MLP limiting"        , "off"    )
       end if
       if (positivity) then
-        write(*,sfmts) "fix positivity         =", "on"
+        call print_parameter(verbose, "fix positivity"      , "on"     )
       else
-        write(*,sfmts) "fix positivity         =", "off"
+        call print_parameter(verbose, "fix positivity"      , "off"    )
       end if
       if (clip) then
-        write(*,sfmts) "clip extrema           =", "on"
-        write(*,sfmts) "extrema limiter        =", trim(name_clim)
+        call print_parameter(verbose, "clip extrema"        , "on"     )
+        call print_parameter(verbose, "extrema limiter"     , name_clim)
       else
-        write(*,sfmts) "clip extrema           =", "off"
+        call print_parameter(verbose, "clip extrema"        , "off"    )
       end if
 
     end if
diff --git a/sources/io.F90 b/sources/io.F90
index c6792d2..a52bb95 100644
--- a/sources/io.F90
+++ b/sources/io.F90
@@ -469,72 +469,69 @@ module io
 !
   subroutine print_io(verbose)
 
+! import external procedures and variables
+!
+    use helpers, only : print_section, print_parameter
+
 ! local variables are not implicit by default
 !
     implicit none
 
 ! subroutine arguments
 !
-    logical, intent(in)    :: verbose
+    logical, intent(in) :: verbose
 
 ! local variables
 !
-    character(len=64) :: sfmts, sfmtc, sfmti
+    character(len=80) :: sfmt, msg
     integer           :: dd, hh, mm, ss
 !
 !-------------------------------------------------------------------------------
 !
     if (verbose) then
-
-      write(*,*)
-      write(*,"(1x,a)") "Snapshots:"
-      sfmts = "(4x,a22,1x,'=',1x,a)"
+      call print_section(verbose, "Snapshots")
       if (precise_snapshots) then
-        write(*,sfmts) "precise snapshot times", "on"
+        call print_parameter(verbose, "precise snapshot intervals", "on" )
       else
-        write(*,sfmts) "precise snapshot times", "off"
+        call print_parameter(verbose, "precise snapshot intervals", "off")
       end if
-      write(*,sfmts) "snapshot type         ", ftype_name
+      call print_parameter(verbose, "snapshot type", ftype_name)
       if (with_ghosts) then
-        write(*,sfmts) "with ghosts cells     ", "on"
+        call print_parameter(verbose, "with ghosts cells", "on" )
       else
-        write(*,sfmts) "with ghosts cells     ", "off"
+        call print_parameter(verbose, "with ghosts cells", "off")
       end if
-      sfmti = "(4x,a21,2x,'=',1x,i0)"
 #ifdef HDF5
-      sfmtc = "(4x,a21,2x,'=',1x,a)"
       select case(compression)
       case(H5Z_ZSTANDARD)
-        write(*,sfmtc) "HDF5 compression     ", "zstd"
-        write(*,sfmti) "compression level    ", clevel
+        call print_parameter(verbose, "HDF5 compression" , "zstd"   )
+        call print_parameter(verbose, "compression level", clevel   )
       case(H5Z_DEFLATE)
-        write(*,sfmtc) "HDF5 compression     ", "deflate"
-        write(*,sfmti) "compression level    ", clevel
+        call print_parameter(verbose, "HDF5 compression" , "deflate")
+        call print_parameter(verbose, "compression level", clevel   )
       case default
-        write(*,sfmtc) "HDF5 compression     ", "none"
+        call print_parameter(verbose, "HDF5 compression" , "none"   )
       end select
 #endif /* HDF5 */
       if (with_xdmf) then
-        write(*,sfmts) "generate XDMF files   ", "on"
+        call print_parameter(verbose, "generate XDMF files", "on" )
       else
-        write(*,sfmts) "generate XDMF files   ", "off"
+        call print_parameter(verbose, "generate XDMF files", "off")
       end if
-      sfmtc = "(4x,a22,1x,'=',es9.2)"
-      write(*,sfmtc) "snapshot interval     ", hsnap
+        call print_parameter(verbose, "snapshot interval"  , hsnap)
       if (hrest > 0.0d+00) then
         dd = int(hrest / 2.4d+01)
         hh = int(mod(hrest, 2.4d+01))
         mm = int(mod(6.0d+01 * hrest, 6.0d+01))
         ss = int(mod(3.6d+03 * hrest, 6.0d+01))
-        sfmtc = "(4x,a16,7x,'=',1x,i2.2,'d',i2.2,'h',i2.2,'m',i2.2,'s')"
-        write(*,sfmtc) "restart interval", dd, hh, mm, ss
+        sfmt = "(i2.2,'d',i2.2,'h',i2.2,'m',i2.2,'s')"
+        write(msg,sfmt) dd, hh, mm, ss
+        call print_parameter(verbose, "restart interval"     , msg    )
       end if
       if (restart_from_snapshot()) then
-        sfmtc = "(4x,a18,5x,'=',1x,'[',a,']')"
-        write(*,sfmtc) "restart from path ", trim(respath)
-        write(*,sfmti) "restart from snapshot", nrest
+        call print_parameter(verbose, "restart from path"    , respath)
+        call print_parameter(verbose, "restart from snapshot", nrest  )
       end if
-
     end if
 
 !-------------------------------------------------------------------------------
diff --git a/sources/parameters.F90 b/sources/parameters.F90
index 204b5c6..eabd230 100644
--- a/sources/parameters.F90
+++ b/sources/parameters.F90
@@ -109,6 +109,7 @@ module parameters
 
 ! include external procedures and variables
 !
+    use helpers        , only : print_section, print_parameter
     use iso_fortran_env, only : error_unit
 
 ! local variables are not implicit by default
@@ -151,9 +152,8 @@ module parameters
 
 ! print the name of parameter file
 !
-    write (*,*)
-    write (*,"(1x,a)"     ) "Configuration:"
-    write (*,"(4x,a,1x,a)") "parameter file         =", trim(fname)
+    call print_section(.true., "Configuration")
+    call print_parameter(.true., "parameter file", fname)
 
 ! check if the file exists
 !
diff --git a/sources/refinement.F90 b/sources/refinement.F90
index e973f31..b7ff4f8 100644
--- a/sources/refinement.F90
+++ b/sources/refinement.F90
@@ -237,6 +237,7 @@ module refinement
 
 ! import external procedures and variables
 !
+    use helpers  , only : print_section, print_parameter
     use equations, only : magnetized, pvars, nv
 
 ! local variables are not implicit by default
@@ -249,9 +250,9 @@ module refinement
 
 ! local variables
 !
-    character(len=64)  :: sfmts
-    character(len=255) :: rvars = ""
-    integer            :: p
+    character(len=80) :: rvars = "", msg
+    character(len=64) :: sfmt
+    integer           :: p
 !
 !-------------------------------------------------------------------------------
 !
@@ -268,17 +269,18 @@ module refinement
         rvars = adjustl(trim(rvars) // ' jabs')
       end if
 
-      write(*,*)
-      write(*,"(1x,a)") "Refinement:"
-      sfmts = "(4x,a,1x,a)"
-      write(*,sfmts) "refined variables      =", trim(rvars)
-      sfmts = "(4x,a,2es9.2)"
-      write(*,sfmts) "2nd order error limits =", crefmin, crefmax
+      call print_section(verbose, "Refinement")
+      call print_parameter(verbose, "refined variables", rvars)
+      sfmt = "(es9.2,1x,'...',1x,es9.2)"
+      write(msg,sfmt) crefmin, crefmax
+      call print_parameter(verbose, "2nd order error limits", msg)
       if (vort_ref) then
-        write(*,sfmts) "vorticity limits       =", vortmin, vortmax
+        write(msg,sfmt) vortmin, vortmax
+        call print_parameter(verbose, "vorticity limits"      , msg)
       end if
       if (magnetized .and. jabs_ref) then
-        write(*,sfmts) "current density limits =", jabsmin, jabsmax
+        write(msg,sfmt) jabsmin, jabsmax
+        call print_parameter(verbose, "current density limits", msg)
       end if
 
     end if
diff --git a/sources/schemes.F90 b/sources/schemes.F90
index 64aaa4a..f38044d 100644
--- a/sources/schemes.F90
+++ b/sources/schemes.F90
@@ -576,6 +576,10 @@ module schemes
 !
   subroutine print_schemes(verbose)
 
+! import external procedures and variables
+!
+    use helpers, only : print_section, print_parameter
+
 ! local variables are not implicit by default
 !
     implicit none
@@ -583,21 +587,13 @@ module schemes
 ! subroutine arguments
 !
     logical, intent(in) :: verbose
-
-! local variables
-!
-    character(len=64) :: sfmts
 !
 !-------------------------------------------------------------------------------
 !
     if (verbose) then
-
-      write(*,*)
-      write(*,"(1x,a)") "Schemes:"
-      sfmts = "(4x,a,1x,a)"
-      write(*,sfmts) "Riemann solver         =", trim(name_sol)
-      write(*,sfmts) "state variables        =", trim(name_sts)
-
+      call print_section(verbose, "Schemes")
+      call print_parameter(verbose, "Riemann solver" , name_sol)
+      call print_parameter(verbose, "state variables", name_sts)
     end if
 
 !-------------------------------------------------------------------------------
diff --git a/sources/shapes.F90 b/sources/shapes.F90
index 60bfafb..7b9df2f 100644
--- a/sources/shapes.F90
+++ b/sources/shapes.F90
@@ -240,6 +240,10 @@ module shapes
 !
   subroutine print_shapes(verbose)
 
+! import external procedures and variables
+!
+    use helpers, only : print_section, print_parameter
+
 ! local variables are not implicit by default
 !
     implicit none
@@ -251,13 +255,11 @@ module shapes
 !-------------------------------------------------------------------------------
 !
     if (verbose) then
-
       if (enabled) then
-        write (*,"(4x,a,1x,a)") "embedded shapes        =", "on"
+        call print_parameter(verbose, "embedded shapes", "on" )
       else
-        write (*,"(4x,a,1x,a)") "embedded shapes        =", "off"
+        call print_parameter(verbose, "embedded shapes", "off")
       end if
-
     end if
 
 !-------------------------------------------------------------------------------
diff --git a/sources/sources.F90 b/sources/sources.F90
index 1e1b1f9..6d48a69 100644
--- a/sources/sources.F90
+++ b/sources/sources.F90
@@ -221,6 +221,7 @@ module sources
 ! include external procedures
 !
     use equations, only : magnetized
+    use helpers  , only : print_section, print_parameter
 
 ! local variables are not implicit by default
 !
@@ -229,25 +230,16 @@ module sources
 ! subroutine arguments
 !
     logical, intent(in) :: verbose
-
-! local variables
-!
-    character(len=64) :: sfmts
 !
 !-------------------------------------------------------------------------------
 !
     if (verbose) then
 
-      write(*,*)
-      write(*,"(1x,a)") "Source terms:"
+      call print_section(verbose, "Source terms")
+      call print_parameter(verbose, "viscosity"       , viscosity  )
       if (magnetized) then
-        sfmts = "(4x,a,1x,a)"
-        write(*,sfmts) "glm source terms       =", trim(glm_name)
-      end if
-      sfmts = "(4x,a,1es9.2)"
-      write(*,sfmts) "viscosity              =", viscosity
-      if (magnetized) then
-        write(*,sfmts) "resistivity            =", resistivity
+        call print_parameter(verbose, "resistivity"     , resistivity)
+        call print_parameter(verbose, "glm source terms", glm_name   )
       end if
 
     end if