Skip to content

Commit 1414178

Browse files
committed
feat(MathUtil): add modular arithmetic utilities
1 parent 5b12e3d commit 1414178

File tree

8 files changed

+112
-1
lines changed

8 files changed

+112
-1
lines changed

autotest/TestMathUtil.f90

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module TestMathUtil
2+
use KindModule, only: I4B, DP
3+
use testdrive, only: check, error_type, new_unittest, test_failed, &
4+
to_string, unittest_type
5+
use MathUtilModule, only: is_same, is_close
6+
implicit none
7+
private
8+
public :: collect_mathutil
9+
10+
contains
11+
12+
subroutine collect_mathutil(testsuite)
13+
type(unittest_type), allocatable, intent(out) :: testsuite(:)
14+
allocate(testsuite(0))
15+
end subroutine collect_mathutil
16+
17+
end module TestMathUtil

autotest/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ if test_drive.found() and not fc_id.contains('intel')
55
'DevFeature',
66
'GeomUtil',
77
'InputOutput',
8+
'MathUtil',
89
'Sim'
910
]
1011

autotest/tester.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ program tester
66
use TestDevFeature, only: collect_dev_feature
77
use TestGeomUtil, only: collect_geomutil
88
use TestInputOutput, only: collect_inputoutput
9+
use TestMathUtil, only: collect_mathutil
910
use TestSim, only: collect_sim
1011
implicit none
1112
integer :: stat, is
@@ -19,6 +20,7 @@ program tester
1920
new_testsuite("DevFeature", collect_dev_feature), &
2021
new_testsuite("GeomUtil", collect_geomutil), &
2122
new_testsuite("InputOutput", collect_inputoutput), &
23+
new_testsuite("MathUtil", collect_mathutil), &
2224
new_testsuite("Sim", collect_sim) &
2325
]
2426

make/makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ $(OBJDIR)/version.o \
8686
$(OBJDIR)/Message.o \
8787
$(OBJDIR)/Sim.o \
8888
$(OBJDIR)/OpenSpec.o \
89+
$(OBJDIR)/MathUtil.o \
8990
$(OBJDIR)/InputOutput.o \
9091
$(OBJDIR)/TableTerm.o \
9192
$(OBJDIR)/Table.o \

msvs/mf6core.vfproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@
395395
<File RelativePath="..\src\Utilities\List.f90"/>
396396
<File RelativePath="..\src\Utilities\ListReader.f90"/>
397397
<File RelativePath="..\src\Utilities\LongLineReader.f90"/>
398+
<File RelativePath="..\src\Utilities\MathUtil.f90"/>
398399
<File RelativePath="..\src\Utilities\Message.f90"/>
399400
<File RelativePath="..\src\Utilities\OpenSpec.f90"/>
400401
<File RelativePath="..\src\Utilities\PackageBudget.f90"/>

src/Solution/NumericalSolution.f90

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ module NumericalSolutionModule
1313
LENMEMPATH
1414
use MemoryHelperModule, only: create_mem_path
1515
use TableModule, only: TableType, table_cr
16-
use GenericUtilitiesModule, only: is_same, sim_message
16+
use GenericUtilitiesModule, only: sim_message
17+
use MathUtilModule, only: is_same
1718
use VersionModule, only: IDEVELOPMODE
1819
use BaseModelModule, only: BaseModelType
1920
use BaseExchangeModule, only: BaseExchangeType

src/Utilities/MathUtil.f90

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
module MathUtilModule
2+
use KindModule, only: DP, I4B, LGP
3+
use ErrorUtilModule, only: pstop
4+
use ConstantsModule, only: MAXCHARLEN, LENHUGELINE, &
5+
DZERO, DPREC, DSAME, &
6+
LINELENGTH, LENHUGELINE, VSUMMARY
7+
8+
implicit none
9+
private
10+
11+
public :: add_wrap, subtr_wrap, incr_wrap, decr_wrap
12+
13+
contains
14+
15+
!> @brief Add a given integer to another, "wrapping around" if needed.
16+
!!
17+
!! This function implements modular addition on the non-negative open interval
18+
!! from 0 to ilimit. If (istart - iadd) > ilimit, the result wraps around to 1.
19+
!<
20+
function add_wrap(istart, iadd, ilimit) result(iwrapped)
21+
integer(I4B) :: istart, iadd, ilimit, iwrapped
22+
23+
! -- A few conditions must hold to ensure only one wraparound is needed
24+
if (istart > ilimit) &
25+
call pstop(1, 'istart must not exceed ilimit')
26+
if (iadd < 0 .or. iadd > ilimit) &
27+
call pstop(1, 'iadd most neither be negative nor exceed ilimit')
28+
29+
! -- Add iadd to istart. If the result exceeds ilimit, wrap around
30+
! -- starting with 1.
31+
iwrapped = istart + iadd
32+
if (iwrapped .gt. ilimit) iwrapped = iwrapped - ilimit
33+
end function add_wrap
34+
35+
!> @brief Subtract a given integer from another, "wrapping around" if needed.
36+
!!
37+
!! This function implements modular subtraction on the non-negative open interval
38+
!! from 0 to ilimit. If (istart - isubtr) < 0, the result wraps around to ilimit.
39+
!<
40+
function subtr_wrap(istart, isubtr, ilimit) result(iwrapped)
41+
integer(I4B) :: istart, isubtr, ilimit, iwrapped
42+
43+
! -- A few conditions must hold to ensure only one wraparound is needed:
44+
if (istart < 1) &
45+
call pstop(1, 'istart must be positive')
46+
if (isubtr < 0 .or. isubtr > ilimit) &
47+
call pstop(1, 'isubtr must neither be negative nor exceed ilimit')
48+
49+
! -- Subtract isubtr from istart. If the result is less than 1, wrap
50+
! -- around starting with ilimit.
51+
iwrapped = istart - isubtr
52+
if (iwrapped .lt. 1) iwrapped = iwrapped + ilimit
53+
end function subtr_wrap
54+
55+
!> @brief Increments an index, "wrapping around" if needed
56+
function incr_wrap(istart, ilimit) result(iwrapped)
57+
integer(I4B) :: istart, ilimit, iwrapped
58+
59+
! -- Require istart <= ilimit
60+
if (istart > ilimit) &
61+
call pstop(1, 'istart must be less than or equal to ilimit')
62+
63+
! -- Increment istart. If istart is at ilimit, wrap around to 1.
64+
if (istart .ne. ilimit) then
65+
iwrapped = istart + 1
66+
else
67+
iwrapped = 1
68+
end if
69+
end function incr_wrap
70+
71+
!> @brief Decrements an index, "wrapping around" if needed
72+
function decr_wrap(istart, ilimit) result(iwrapped)
73+
integer(I4B) :: istart, ilimit, iwrapped
74+
75+
! -- Require istart >= 1
76+
if (istart < 1) &
77+
call pstop(1, 'istart must be greater than or equal to 1')
78+
79+
! -- Decrement istart. If istart is 1, wrap around to ilimit.
80+
if (istart .ne. 1) then
81+
iwrapped = istart - 1
82+
else
83+
iwrapped = ilimit
84+
end if
85+
end function decr_wrap
86+
87+
end module MathUtilModule

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ modflow_sources = files(
237237
'Utilities' / 'List.f90',
238238
'Utilities' / 'ListReader.f90',
239239
'Utilities' / 'LongLineReader.f90',
240+
'Utilities' / 'MathUtil.f90',
240241
'Utilities' / 'Message.f90',
241242
'Utilities' / 'OpenSpec.f90',
242243
'Utilities' / 'PackageBudget.f90',

0 commit comments

Comments
 (0)