Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
203 changes: 203 additions & 0 deletions f90/UTILS/ModEM_logger.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
!
! 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(0,*) fid_lcl
Comment thread
MiCurry marked this conversation as resolved.
Outdated
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
Loading