Skip to content

Commit

Permalink
ci(api): add autotest to test API routines (e.g. get_version) (MODFLO…
Browse files Browse the repository at this point in the history
…W-USGS#2082)

* - add general libmf6 test

* - unused module

* - python format

* - one more fprettify

* - ruff
  • Loading branch information
mjr-deltares authored Dec 4, 2024
1 parent 7f1180f commit f590f42
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 20 deletions.
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_evt01.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_ghb01.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_ifmod01.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_ifmod02.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_ifmod03.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_rch01.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_rch02.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_riv01.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_riv02.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
2 changes: 1 addition & 1 deletion autotest/test_gwf_libmf6_sto01.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
172 changes: 172 additions & 0 deletions autotest/test_libmf6_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
"""
Test the MODFLOW API with a basic 1x1x5 model:
[ BC | 1 | 2 | 3 | BC ]
"""

import os

import flopy
import pytest
from framework import TestFramework
from modflow_devtools.markers import requires_pkg

cases = ["libmf6_api"]


def get_model(dir):
# parameters and spd
# tdis
nper = 1
tdis_rc = []
for i in range(nper):
tdis_rc.append((1.0, 1, 1))

# solver data
nouter, ninner = 100, 300
hclose, rclose = 10e-9, 1e-3

# model spatial discretization
nlay = 1
nrow = 1
ncol = 5

# cell spacing
delr = 1.0
delc = 1.0

# top/bot of the aquifer
tops = [0.0, -1.0]

# hydraulic conductivity
k11 = 1.0

# boundary stress period data
h_left = 0.0
h_right = 5.0

# initial head
h_start = 0.0

sim = flopy.mf6.MFSimulation(
sim_name="sim", version="mf6", exe_name="mf6", sim_ws=dir
)

tdis = flopy.mf6.ModflowTdis(sim, time_units="DAYS", nper=nper, perioddata=tdis_rc)

ims = flopy.mf6.ModflowIms(
sim,
print_option="SUMMARY",
outer_dvclose=hclose,
outer_maximum=nouter,
inner_maximum=ninner,
inner_dvclose=hclose,
rcloserecord=rclose,
linear_acceleration="CG",
)

# submodel on the left:
chd_data = [[(0, 0, 0), h_left], [(0, 0, ncol - 1), h_right]]
chd_spd = {0: chd_data}

gwf = flopy.mf6.ModflowGwf(sim, modelname="model", save_flows=True)
dis = flopy.mf6.ModflowGwfdis(
gwf,
nlay=nlay,
nrow=nrow,
ncol=ncol,
delr=delr,
delc=delc,
top=tops[0],
botm=tops[1:],
)
ic = flopy.mf6.ModflowGwfic(gwf, strt=h_start)
npf = flopy.mf6.ModflowGwfnpf(
gwf,
save_specific_discharge=True,
save_flows=True,
icelltype=0,
k=k11,
)
chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd)
oc = flopy.mf6.ModflowGwfoc(
gwf,
head_filerecord="model.hds",
budget_filerecord="model.cbc",
headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")],
saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")],
)

return sim


def build_models(idx, test):
# build MODFLOW 6 files
ws = test.workspace
name = cases[idx]
sim = get_model(ws)

# build comparison model
ws = os.path.join(test.workspace, "libmf6")
sim_compare = get_model(ws)

return sim, sim_compare


def api_func(exe, idx, model_ws=None):
from modflowapi import ModflowApi

if model_ws is None:
model_ws = "."
output_file_path = os.path.join(model_ws, "mfsim.stdout")

try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

# initialize the model
try:
mf6.initialize()
except:
return False, open(output_file_path).readlines()

# testing API
comp_str = mf6.get_component_name()
version_str = mf6.get_version()
print(f"Loaded {comp_str} with version {version_str}")

# time loop
current_time = mf6.get_current_time()
end_time = mf6.get_end_time()
while current_time < end_time:
try:
mf6.update()
except:
return False, open(output_file_path).readlines()
current_time = mf6.get_current_time()

# finish
try:
mf6.finalize()
except:
return False, open(output_file_path).readlines()

# cleanup and return
return True, open(output_file_path).readlines()


@requires_pkg("modflowapi")
@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
test = TestFramework(
name=name,
workspace=function_tmpdir,
build=lambda t: build_models(idx, t),
targets=targets,
api_func=lambda exe, ws: api_func(exe, idx, ws),
)
test.run()
2 changes: 1 addition & 1 deletion autotest/test_prt_libmf6_budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def api_func(exe, idx, model_ws=None):
try:
mf6 = ModflowApi(exe, working_directory=model_ws)
except Exception as e:
print("Failed to load " + exe)
print("Failed to load " + str(exe))
print("with message: " + str(e))
return False, open(output_file_path).readlines()

Expand Down
1 change: 0 additions & 1 deletion src/Utilities/Idm/mf6blockfile/StructVector.f90
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module StructVectorModule
use InputDefinitionModule, only: InputParamDefinitionType
use CharacterStringModule, only: CharacterStringType
use STLVecIntModule, only: STLVecInt
use ArrayHandlersModule, only: expandarray

implicit none
private
Expand Down
9 changes: 1 addition & 8 deletions srcbmi/mf6xmi.F90
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,8 @@ function xmi_get_version(mf_version) result(bmi_status) &
! -- dummy variables
character(kind=c_char), intent(inout) :: mf_version(BMI_LENVERSION)
integer(kind=c_int) :: bmi_status !< BMI status code
! -- local variables
character(len=BMI_LENVERSION) :: vstr

if (IDEVELOPMODE == 1) then
vstr = VERSIONNUMBER//'-dev'
else
vstr = VERSIONNUMBER
end if
mf_version = string_to_char_array(vstr, len_trim(vstr))
mf_version = string_to_char_array(VERSIONNUMBER, len_trim(VERSIONNUMBER))
bmi_status = BMI_SUCCESS

end function xmi_get_version
Expand Down

0 comments on commit f590f42

Please sign in to comment.