Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions f90/UTILS/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ target_sources(${MODEM_EXE}
PRIVATE fields_orientation.f90
PRIVATE file_units.f90
PRIVATE math_constants.f90
#PRIVATE ModEM_machine_timers.c
PRIVATE ModEM_timers.f90
#PRIVATE ModEM_utils.f90
PRIVATE polpak.f90
PRIVATE utilities.f90
PRIVATE ModEM_logger.f90
)

if (USE_C_TIMERS)
Expand Down
202 changes: 202 additions & 0 deletions f90/UTILS/ModEM_logger.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
!
! ModEM_logger
!
! This logger, along with `expand_message` in the utilities modular, offer
! some very helpful mechanisms for logging messages in Fortran. It offers:
!
! 1. Easily allow each MPI task the ability to open and log to its own seperate
! logging file.
! * Very Helpful in debugging MPI Issues
! 2. The ability to use printf-like string formatting.
! * Reduces the need to use Fortran's ... unique string formatting mechanism
!
! To use, ensure you call ModEM_log_init() first before doing calling ModEM_log().
! For examples, please see the code comments in ModEM_log below.
!
! By default, only the main task will log out tasks. Likewise, you might not see
! messages immediate during execution, so you might want to use flush_log=.true. when
! calling ModEM_log.
!
! Note: The code in the section was adapted from MPAS-Model code: see the
! license disclosure below.
module ModEM_logger

use utilities
use Declaration_MPI

implicit none

character (len=512), private :: log_fname
integer, private :: log_fid = 0

contains

subroutine ModEM_log_init(mainOnly)

implicit none

logical, optional, intent(in) :: mainOnly
character(len=*), parameter :: log_str_fmt = '(A,I4.4,A)'

logical :: mainOnly_lcl

if (present(mainOnly)) then
mainOnly_lcl = mainOnly
else
mainOnly_lcl = .true.
end if

if ((taskid == 0 .and. mainOnly_lcl) .or. (.not. mainOnly_lcl)) then
write(log_fname, log_str_fmt) 'log.', taskid, '.modem.out'
open(newunit=log_fid, file=log_fname, status='replace')
call ModEM_log("Log Initalized $i - "//trim(log_fname), intArgs=(/taskid/), mainOnly=mainOnly)
end if

end Subroutine ModEM_log_init

! The following License applies to ModEM_Log:
!
! Copyright (c) 2013-2019, Los Alamos National Security, LLC (LANS) (Ocean: LA-CC-13-047;
! Land Ice: LA-CC-13-117) and the University Corporation for Atmospheric Research (UCAR).
!
! All rights reserved.
!
! LANS is the operator of the Los Alamos National Laboratory under Contract No.
! DE-AC52-06NA25396 with the U.S. Department of Energy. UCAR manages the National
! Center for Atmospheric Research under Cooperative Agreement ATM-0753581 with the
! National Science Foundation. The U.S. Government has rights to use, reproduce,
! and distribute this software. NO WARRANTY, EXPRESS OR IMPLIED IS OFFERED BY
! LANS, UCAR OR THE GOVERNMENT AND NONE OF THEM ASSUME ANY LIABILITY FOR THE USE
! OF THIS SOFTWARE. If software is modified to produce derivative works, such
! modified software should be clearly marked, so as not to confuse it with the
! version available from LANS and UCAR.
!
! Additionally, redistribution and use in source and binary forms, with or without
! modification, are permitted provided that the following conditions are met:
!
! 1) Redistributions of source code must retain the above copyright notice, this
! list of conditions and the following disclaimer.
!
! 2) Redistributions in binary form must reproduce the above copyright notice,
! this list of conditions and the following disclaimer in the documentation and/or
! other materials provided with the distribution.
!
! 3) None of the names of LANS, UCAR or the names of its contributors, if any, may
! be used to endorse or promote products derived from this software without
! specific prior written permission.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
! ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
! ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
! ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

!***********************************************************************
!
! routine ModEM_log
!
!> \brief Writes a message to the log file
!> \author Matt Hoffman - Modified for ModEM by Miles Curry
!> \date 14 February 2017, 5 Feburary 2026
!> \details
!> This routine writes a message to the log file. The message is the only
!> required argument. A number of optional arguments control additional
!> behavior:
!> intArgs, int8Args, realArgs, logicArgs: arrays of variable values to be inserted into the
!> message to replace the following characters: $i, $j, $r, $l
!> See routine expand_string below for details.
!> fid: (Optional) Instead of using the log created/opened in ModEM_log_init, write to the unit
!> in found in fid
!> mainOnly: flag indicating only the master task should write this message,
!> regardless of if all tasks have open log files.
!> flush_log: flag indicating that the log should be flushed after writing
!>
!> For more information see the expand_string subroutine in the utilities module
!>
!> | examples
!>
!> ```Fortran
!> real :: a, b, c ! Of course you can also use other real kinds
!> integer :: int1, int2,
!> logical :: bool_false, bool_true
!>
!> ! Ensure you call ModEM_log_init() first!
!> call ModEM_log_init()
!>
!> ! Printing several real numbers:
!> call ModEM_log("Reals: a: $r b: $r c: $r", realArgs=(/a, b, c/)))
!>
!> ! Printing several integer numbers
!> call ModEM_log("Integers: ($i, $i)", intArgs=(/int1, int2/)))
!>
!> ! Printing logicals
!> bool_false = .false.
!> bool_true = .true.
!> call ModEM_log("Logical: $l $l", logicArgs=(/bool_false, bool_true/))
!>
!> ! Mix and match as you see fit!
!> ! Note: You don't need to have the arguments (intArgs, logicArgs etc.) in any particular order!
!> call ModEM_log("Bool: $l - Int: $i - Reals: $r $r $r", intArgs=(/int1/), logicArgs=(/bool_true/), &
!> realArgs=(/a, b, c/))
!>
!> ! Appending Strings
!> myString = "JOB_NAME"
!> call ModEM_log("We are in the: '"//trim(myString)//"' function with args: $i, $i", intArgs=(/int1, int2/))
!> ```
!-----------------------------------------------------------------------
subroutine ModEM_log(msg, intArgs, realArgs, logicArgs, fid, mainOnly, flush_log)

implicit none

character(len=*), intent(in) :: msg
logical, intent(in), optional :: mainOnly
integer, dimension(:), intent(in), optional :: intArgs !< Input: integer variable values to insert into message
real(kind=prec), dimension(:), intent(in), optional :: realArgs !< Input: real variable values to insert into message
!< Input: exponential notation variable values to insert into message
logical, dimension(:), intent(in), optional :: logicArgs !< Input: logical variable values to insert into message
integer, intent(in), optional :: fid
logical, intent(in), optional :: flush_log

logical :: mainOnly_lcl
logical :: flush_lcl
integer :: fid_lcl

character(len=512) :: messageExpanded !< message after expansion of $ variable insertions

if (present(mainOnly)) then
mainOnly_lcl = mainOnly
else
mainOnly_lcl = .true.
end if

if (present(fid)) then
fid_lcl = fid
else
fid_lcl = log_fid
end if

if (present(flush_log)) then
flush_lcl = flush_log
else
flush_lcl = .false.
end if

call expand_string(msg, messageExpanded, intArgs, logicArgs, realArgs)

if ((mainOnly_lcl .and. taskid == 0) .or. (.not. mainOnly_lcl)) then
write(fid_lcl,*) trim(messageExpanded)

if (flush_lcl) then
call flush(fid_lcl)
end if
end if

end subroutine ModEM_log

end module ModEM_logger

Loading