diff --git a/autotest/t050_test.py b/autotest/t050_test.py
index 02eb9fc684..bbcd77428b 100644
--- a/autotest/t050_test.py
+++ b/autotest/t050_test.py
@@ -1,116 +1,207 @@
import shutil
import os
-import numpy as np
import flopy
from flopy.export import vtk
+# Test vtk export
+# Note: initially thought about asserting that exported file size in bytes is
+# unchanged, but this seems to be sensitive to the running environment.
+# Thus, only asserting that the number of lines is unchanged.
+# Still keeping the file size check commented for now.
+
# create output directory
cpth = os.path.join('temp', 't050')
if os.path.isdir(cpth):
shutil.rmtree(cpth)
os.makedirs(cpth)
-# binary output directory
-binot = os.path.join(cpth, 'bin')
-if os.path.isdir(binot):
- shutil.rmtree(binot)
-os.makedirs(binot)
+def count_lines_in_file(filepath):
+ f = open(filepath, 'r')
+ n = len(f.readlines())
+ return n
+def count_lines_in_file_bin(filepath):
+ f = open(filepath, 'rb')
+ n = len(f.readlines())
+ return n
def test_vtk_export_array2d():
- """Export 2d array"""
+ # test mf 2005 freyberg
mpath = os.path.join('..', 'examples', 'data',
'freyberg_multilayer_transient')
namfile = 'freyberg.nam'
- m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False)
- m.dis.top.export(os.path.join(cpth, 'array_2d_test'), fmt='vtk')
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False,
+ load_only=['dis', 'bas6'])
+ output_dir = os.path.join(cpth, 'array_2d_test')
+
+ # export and check
+ m.dis.top.export(output_dir, name='top', fmt='vtk')
+ filetocheck = os.path.join(output_dir, 'top.vtu')
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==352026)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==2846)
+
# with smoothing
- m.dis.top.export(os.path.join(cpth, 'array_2d_test'), fmt='vtk',
- name='top_smooth', smooth=True)
+ m.dis.top.export(output_dir, fmt='vtk', name='top_smooth', smooth=True)
+ filetocheck = os.path.join(output_dir, 'top_smooth.vtu')
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==351829)
+ nlines1 = count_lines_in_file(filetocheck)
+ assert(nlines1==2846)
+ return
def test_vtk_export_array3d():
- """Vtk export 3d array"""
+ # test mf 2005 freyberg
mpath = os.path.join('..', 'examples', 'data',
'freyberg_multilayer_transient')
namfile = 'freyberg.nam'
- m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False)
- m.upw.hk.export(os.path.join(cpth, 'array_3d_test'), fmt='vtk')
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False,
+ load_only=['dis', 'bas6', 'upw'])
+ output_dir = os.path.join(cpth, 'array_3d_test')
+
+ # export and check
+ m.upw.hk.export(output_dir, fmt='vtk', name='hk')
+ filetocheck = os.path.join(output_dir, 'hk.vtu')
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==992576)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==8486)
+
# with point scalars
- m.upw.hk.export(os.path.join(cpth, 'array_3d_test'), fmt='vtk',
- name='hk_points', point_scalars=True)
- # binary test
- m.upw.hk.export(os.path.join(binot, 'array_3d_test'), fmt='vtk',
- name='hk_points', point_scalars=True, binary=True)
+ m.upw.hk.export(output_dir, fmt='vtk', name='hk_points',
+ point_scalars=True)
+ filetocheck = os.path.join(output_dir, 'hk_points.vtu')
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==1321292)
+ nlines1 = count_lines_in_file(filetocheck)
+ assert(nlines1==10605)
+
+ # with point scalars and binary
+ m.upw.hk.export(output_dir, fmt='vtk', name='hk_points_bin',
+ point_scalars=True, binary=True)
+ filetocheck = os.path.join(output_dir, 'hk_points_bin.vtu')
+ # totalbytes2 = os.path.getsize(filetocheck)
+ # assert(totalbytes2==637861)
+ nlines2 = count_lines_in_file_bin(filetocheck)
+ assert(nlines2==1848)
return
-
def test_vtk_transient_array_2d():
- """VTK export transient 2d array"""
+ # test mf 2005 freyberg
mpath = os.path.join('..', 'examples', 'data',
'freyberg_multilayer_transient')
namfile = 'freyberg.nam'
- m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False)
- m.rch.rech.export(os.path.join(cpth, 'transient_2d_test'), fmt='vtk')
-
- # binary test
- m.rch.rech.export(os.path.join(binot, 'transient_2d_test'), fmt='vtk',
- binary=True)
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False,
+ load_only=['dis', 'bas6', 'rch'])
+ output_dir = os.path.join(cpth, 'transient_2d_test')
+ output_dir_bin = os.path.join(cpth, 'transient_2d_test_bin')
+
+ # export and check
+ r = m.rch.rech
+ m.rch.rech.export(output_dir, fmt='vtk')
+ filetocheck = os.path.join(output_dir, 'rech_01.vtu')
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==355324)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==2851)
+ filetocheck = os.path.join(output_dir, 'rech_01097.vtu')
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==354622)
+ nlines1 = count_lines_in_file(filetocheck)
+ assert(nlines1==2851)
+
+ # with binary
+ m.rch.rech.export(output_dir_bin, fmt='vtk', binary=True)
+ filetocheck = os.path.join(output_dir_bin, 'rech_01.vtu')
+ # totalbytes2 = os.path.getsize(filetocheck)
+ # assert(totalbytes2==168339)
+ nlines2 = count_lines_in_file_bin(filetocheck)
+ assert(nlines2==762)
+ filetocheck = os.path.join(output_dir_bin, 'rech_01097.vtu')
+ # totalbytes3 = os.path.getsize(filetocheck)
+ # assert(totalbytes3==168339)
+ nlines3 = count_lines_in_file_bin(filetocheck)
+ assert(nlines3==762)
return
-
def test_vtk_export_packages():
- """testing vtk package export"""
+ # test mf 2005 freyberg
mpath = os.path.join('..', 'examples', 'data',
'freyberg_multilayer_transient')
namfile = 'freyberg.nam'
- m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False)
- # test dis export
- m.dis.export(os.path.join(cpth, 'DIS'), fmt='vtk')
- # upw with point scalar output
- m.upw.export(os.path.join(cpth, 'UPW'), fmt='vtk', point_scalars=True)
- # bas with smoothing on
- m.bas6.export(os.path.join(cpth, 'BAS'), fmt='vtk', smooth=True)
- # transient package drain
- m.drn.export(os.path.join(cpth, 'DRN'), fmt='vtk')
- # binary test
- m.dis.export(os.path.join(binot, 'DIS'), fmt='vtk', binary=True)
- # upw with point scalar output
- m.upw.export(os.path.join(binot, 'UPW'), fmt='vtk', point_scalars=True,
- binary=True)
-
- return
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpath, verbose=False,
+ load_only=['dis', 'bas6', 'upw', 'DRN'])
+
+ # dis export and check
+ output_dir = os.path.join(cpth, 'DIS')
+ m.dis.export(output_dir, fmt='vtk')
+ filetocheck = os.path.join(output_dir, 'DIS.vtu')
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==1010527)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==8496)
+ # upw with point scalar output
+ output_dir = os.path.join(cpth, 'UPW')
+ m.upw.export(output_dir, fmt='vtk', point_scalars=True)
+ filetocheck = os.path.join(output_dir, 'UPW.vtu')
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==2485295)
+ nlines1 = count_lines_in_file(filetocheck)
+ assert(nlines1==21215)
-# add mf2005 model exports
-def test_export_mf2005_vtk():
- """test vtk model export mf2005"""
- pth = os.path.join('..', 'examples', 'data', 'mf2005_test')
- namfiles = [namfile for namfile in os.listdir(pth) if
- namfile.endswith('.nam')]
- skip = ['bcf2ss.nam']
- for namfile in namfiles:
- if namfile in skip:
- continue
- print('testing namefile', namfile)
- m = flopy.modflow.Modflow.load(namfile, model_ws=pth, verbose=False)
- m.export(os.path.join(cpth, m.name), fmt='vtk')
+ # bas with smoothing on
+ output_dir = os.path.join(cpth, 'BAS')
+ m.bas6.export(output_dir, fmt='vtk', smooth=True)
+ filetocheck = os.path.join(output_dir, 'BAS6.vtu')
+ # totalbytes2 = os.path.getsize(filetocheck)
+ # assert(totalbytes2==1002054)
+ nlines2 = count_lines_in_file(filetocheck)
+ assert(nlines2==8491)
- # binary test
- m.export(os.path.join(binot, m.name), fmt='vtk', binary=True)
+ # transient package drain
+ output_dir = os.path.join(cpth, 'DRN')
+ m.drn.export(output_dir, fmt='vtk')
+ filetocheck = os.path.join(output_dir, 'DRN_01.vtu')
+ # totalbytes3 = os.path.getsize(filetocheck)
+ # assert(totalbytes3==20702)
+ nlines3 = count_lines_in_file(filetocheck)
+ assert(nlines3==191)
+ filetocheck = os.path.join(output_dir, 'DRN_01097.vtu')
+ # totalbytes4 = os.path.getsize(filetocheck)
+ # assert(totalbytes4==20702)
+ nlines4 = count_lines_in_file(filetocheck)
+ assert(nlines4==191)
+
+ # dis with binary
+ output_dir = os.path.join(cpth, 'DIS_bin')
+ m.dis.export(output_dir, fmt='vtk', binary=True)
+ filetocheck = os.path.join(output_dir, 'DIS.vtu')
+ # totalbytes5 = os.path.getsize(filetocheck)
+ # assert(totalbytes5==536436)
+ nlines5 = count_lines_in_file_bin(filetocheck)
+ assert(nlines5==1545)
+
+ # upw with point scalars and binary
+ output_dir = os.path.join(cpth, 'UPW_bin')
+ m.upw.export(output_dir, fmt='vtk', point_scalars=True, binary=True)
+ filetocheck = os.path.join(output_dir, 'UPW.vtu')
+ # totalbytes6 = os.path.getsize(filetocheck)
+ # assert(totalbytes6==1400561)
+ nlines6 = count_lines_in_file_bin(filetocheck)
+ assert(nlines6==1868)
return
-
def test_vtk_mf6():
+ # test mf6
mf6expth = os.path.join('..', 'examples', 'data', 'mf6')
- # test vtk mf6 export
- mf6sims = ['test045_lake1ss_table',
- 'test036_twrihfb', 'test045_lake2tr', 'test006_2models_mvr']
- # mf6sims = ['test005_advgw_tidal']
- # mf6sims = ['test036_twrihfb']
+ mf6sims = ['test045_lake1ss_table', 'test036_twrihfb', 'test045_lake2tr',
+ 'test006_2models_mvr']
for simnm in mf6sims:
print(simnm)
@@ -124,91 +215,234 @@ def test_vtk_mf6():
m = loaded_sim.get_model(mname)
m.export(os.path.join(cpth, m.name), fmt='vtk')
+ # check one
+ filetocheck = os.path.join(cpth, 'twrihfb2015', 'npf.vtr')
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==21609)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==76)
+
return
def test_vtk_binary_head_export():
+ # test mf 2005 freyberg
+ mpth = os.path.join('..', 'examples', 'data',
+ 'freyberg_multilayer_transient')
+ namfile = 'freyberg.nam'
+ hdsfile = os.path.join(mpth, 'freyberg.hds')
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpth, verbose=False,
+ load_only=['dis', 'bas6'])
+ filenametocheck = 'freyberg_Heads_KPER455_KSTP1.vtu'
- """test vet export of heads"""
-
- freyberg_pth = os.path.join('..', 'examples', 'data',
- 'freyberg_multilayer_transient')
-
- hdsfile = os.path.join(freyberg_pth, 'freyberg.hds')
-
- m = flopy.modflow.Modflow.load('freyberg.nam', model_ws=freyberg_pth,
- verbose=False)
+ # export and check
otfolder = os.path.join(cpth, 'heads_test')
-
vtk.export_heads(m, hdsfile, otfolder, nanval=-999.99, kstpkper=[(0, 0),
(0, 199),
(0, 354),
(0, 454),
(0,
1089)])
- # test with points
+ filetocheck = os.path.join(otfolder, filenametocheck)
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==993755)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==8486)
+
+ # with point scalars
otfolder = os.path.join(cpth, 'heads_test_1')
vtk.export_heads(m, hdsfile, otfolder,
kstpkper=[(0, 0), (0, 199), (0, 354), (0, 454), (0,
1089)],
point_scalars=True, nanval=-999.99)
+ filetocheck = os.path.join(otfolder, filenametocheck)
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==1332346)
+ nlines1 = count_lines_in_file(filetocheck)
+ assert(nlines1==10605)
- # test vtk export heads with smoothing and no point scalars
+ # with smoothing
otfolder = os.path.join(cpth, 'heads_test_2')
vtk.export_heads(m, hdsfile, otfolder,
kstpkper=[(0, 0), (0, 199), (0, 354), (0, 454), (0,
1089)],
- point_scalars=False, smooth=True, nanval=-999.99)
-
- # test binary output
+ smooth=True, nanval=-999.99)
+ filetocheck = os.path.join(otfolder, filenametocheck)
+ # totalbytes2 = os.path.getsize(filetocheck)
+ # assert(totalbytes2==993551)
+ nlines2 = count_lines_in_file(filetocheck)
+ assert(nlines2==8486)
+
+ # with smoothing and binary
otfolder = os.path.join(cpth, 'heads_test_3')
vtk.export_heads(m, hdsfile, otfolder,
kstpkper=[(0, 0), (0, 199), (0, 354), (0, 454), (0,
1089)],
- point_scalars=False, smooth=True, binary=True,
- nanval=-999.99)
+ smooth=True, binary=True, nanval=-999.99)
+ filetocheck = os.path.join(otfolder, filenametocheck)
+ # totalbytes3 = os.path.getsize(filetocheck)
+ # assert(totalbytes3==502313)
+ nlines3 = count_lines_in_file_bin(filetocheck)
+ assert(nlines3==1538)
+ # with smoothing and binary, single time
otfolder = os.path.join(cpth, 'heads_test_4')
vtk.export_heads(m, hdsfile, otfolder, kstpkper=(0, 0),
- point_scalars=False,
- smooth=True, binary=True, nanval=-999.99)
+ point_scalars=False, smooth=True, binary=True,
+ nanval=-999.99)
+ filetocheck = os.path.join(otfolder, 'freyberg_Heads_KPER1_KSTP1.vtu')
+ # totalbytes4 = os.path.getsize(filetocheck)
+ # assert(totalbytes4==502313)
+ nlines4 = count_lines_in_file_bin(filetocheck)
+ assert(nlines4==1528)
return
-
def test_vtk_cbc():
# test mf 2005 freyberg
- freyberg_cbc = os.path.join('..', 'examples', 'data',
- 'freyberg_multilayer_transient',
- 'freyberg.cbc')
-
- freyberg_mpth = os.path.join('..', 'examples', 'data',
- 'freyberg_multilayer_transient')
-
- m = flopy.modflow.Modflow.load('freyberg.nam', model_ws=freyberg_mpth,
- verbose=False)
+ mpth = os.path.join('..', 'examples', 'data',
+ 'freyberg_multilayer_transient')
+ namfile = 'freyberg.nam'
+ cbcfile = os.path.join(mpth, 'freyberg.cbc')
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpth, verbose=False)
+ filenametocheck = 'freyberg_CBC_KPER1_KSTP1.vtu'
- vtk.export_cbc(m, freyberg_cbc, os.path.join(cpth, 'freyberg_CBCTEST'),
+ # export and check with point scalar
+ otfolder = os.path.join(cpth, 'freyberg_CBCTEST')
+ vtk.export_cbc(m, cbcfile, otfolder,
kstpkper=[(0, 0), (0, 1), (0, 2)], point_scalars=True)
-
- vtk.export_cbc(m, freyberg_cbc, os.path.join(cpth, 'freyberg_CBCTEST_bin'),
+ filetocheck = os.path.join(otfolder, filenametocheck)
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==2496132)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==19093)
+
+ # with point scalars and binary
+ otfolder = os.path.join(cpth, 'freyberg_CBCTEST_bin')
+ vtk.export_cbc(m, cbcfile, otfolder,
kstpkper=[(0, 0), (0, 1), (0, 2)], point_scalars=True,
binary=True)
-
- vtk.export_cbc(m, freyberg_cbc, os.path.join(cpth,
- 'freyberg_CBCTEST_bin2'),
+ filetocheck = os.path.join(otfolder, filenametocheck)
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==1248118)
+ nlines1 = count_lines_in_file_bin(filetocheck)
+ assert(nlines1==2609)
+
+ # with point scalars and binary, only one budget component
+ otfolder = os.path.join(cpth, 'freyberg_CBCTEST_bin2')
+ vtk.export_cbc(m, cbcfile, otfolder,
kstpkper=(0, 0), text='CONSTANT HEAD',
point_scalars=True, binary=True)
+ filetocheck = os.path.join(otfolder, filenametocheck)
+ # totalbytes2 = os.path.getsize(filetocheck)
+ # assert(totalbytes2==10262)
+ nlines2 = count_lines_in_file_bin(filetocheck)
+ assert(nlines2==61)
+
+ return
+
+def test_vtk_vti():
+ # test mf 2005 ibs2k
+ mpth = os.path.join('..', 'examples', 'data', 'mf2005_test')
+ namfile = 'ibs2k.nam'
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpth, verbose=False)
+ output_dir = os.path.join(cpth, m.name)
+ filenametocheck = 'DIS.vti'
+
+ # export and check
+ m.export(output_dir, fmt='vtk')
+ filetocheck = os.path.join(output_dir, filenametocheck)
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==6322)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==21)
+
+ # with point scalar
+ m.export(output_dir + '_points', fmt='vtk', point_scalars=True)
+ filetocheck = os.path.join(output_dir + '_points', filenametocheck)
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==16382)
+ nlines1 = count_lines_in_file(filetocheck)
+ assert(nlines1==38)
+
+ # with binary
+ m.export(output_dir + '_bin', fmt='vtk', binary=True)
+ filetocheck = os.path.join(output_dir + '_bin', filenametocheck)
+ # totalbytes2 = os.path.getsize(filetocheck)
+ # assert(totalbytes2==6537)
+ nlines2 = count_lines_in_file_bin(filetocheck)
+ assert(nlines2==18)
+
+ # force .vtr
+ filenametocheck = 'DIS.vtr'
+ m.export(output_dir, fmt='vtk', vtk_grid_type='RectilinearGrid')
+ filetocheck = os.path.join(output_dir, filenametocheck)
+ # totalbytes3 = os.path.getsize(filetocheck)
+ # assert(totalbytes3==7146)
+ nlines3 = count_lines_in_file(filetocheck)
+ assert(nlines3==56)
+
+ # force .vtu
+ filenametocheck = 'DIS.vtu'
+ m.export(output_dir, fmt='vtk', vtk_grid_type='UnstructuredGrid')
+ filetocheck = os.path.join(output_dir, filenametocheck)
+ # totalbytes4 = os.path.getsize(filetocheck)
+ # assert(totalbytes4==67065)
+ nlines4 = count_lines_in_file(filetocheck)
+ assert(nlines4==993)
return
+def test_vtk_vtr():
+ # test mf 2005 l1a2k
+ mpth = os.path.join('..', 'examples', 'data', 'mf2005_test')
+ namfile = 'l1a2k.nam'
+ m = flopy.modflow.Modflow.load(namfile, model_ws=mpth, verbose=False)
+ output_dir = os.path.join(cpth, m.name)
+ filenametocheck = 'EVT_01.vtr'
+
+ # export and check
+ m.export(output_dir, fmt='vtk')
+ filetocheck = os.path.join(output_dir, filenametocheck)
+ # totalbytes = os.path.getsize(filetocheck)
+ # assert(totalbytes==79953)
+ nlines = count_lines_in_file(filetocheck)
+ assert(nlines==87)
+
+ # with point scalar
+ m.export(output_dir + '_points', fmt='vtk', point_scalars=True)
+ filetocheck = os.path.join(output_dir + '_points', filenametocheck)
+ # totalbytes1 = os.path.getsize(filetocheck)
+ # assert(totalbytes1==182472)
+ nlines1 = count_lines_in_file(filetocheck)
+ assert(nlines1==121)
+
+ # with binary
+ m.export(output_dir + '_bin', fmt='vtk', binary=True)
+ filetocheck = os.path.join(output_dir + '_bin', filenametocheck)
+ # totalbytes2 = os.path.getsize(filetocheck)
+ # assert(totalbytes2==47778)
+ nlines2 = count_lines_in_file_bin(filetocheck)
+ assert(nlines2==28)
+
+ # force .vtu
+ filenametocheck = 'EVT_01.vtu'
+ m.export(output_dir, fmt='vtk', vtk_grid_type='UnstructuredGrid')
+ filetocheck = os.path.join(output_dir, filenametocheck)
+ # totalbytes3 = os.path.getsize(filetocheck)
+ # assert(totalbytes3==78762)
+ nlines3 = count_lines_in_file(filetocheck)
+ assert(nlines3==1105)
+
+ return
if __name__ == '__main__':
test_vtk_export_array2d()
test_vtk_export_array3d()
test_vtk_transient_array_2d()
test_vtk_export_packages()
- test_export_mf2005_vtk()
test_vtk_mf6()
test_vtk_binary_head_export()
test_vtk_cbc()
+ test_vtk_vti()
+ test_vtk_vtr()
diff --git a/flopy/discretization/grid.py b/flopy/discretization/grid.py
index dcab127bed..9853a95738 100644
--- a/flopy/discretization/grid.py
+++ b/flopy/discretization/grid.py
@@ -284,6 +284,12 @@ def extent(self):
raise NotImplementedError(
'must define extent in child class')
+ @property
+ def xyzextent(self):
+ return (np.min(self.xyzvertices[0]), np.max(self.xyzvertices[0]),
+ np.min(self.xyzvertices[1]), np.max(self.xyzvertices[1]),
+ np.min(self.xyzvertices[2]), np.max(self.xyzvertices[2]))
+
@property
def grid_lines(self):
raise NotImplementedError(
diff --git a/flopy/discretization/structuredgrid.py b/flopy/discretization/structuredgrid.py
index 23222da45d..f8a77b45e1 100644
--- a/flopy/discretization/structuredgrid.py
+++ b/flopy/discretization/structuredgrid.py
@@ -177,6 +177,23 @@ def xyedges(self):
else:
return self._cache_dict[cache_index].data_nocopy
+ @property
+ def zedges(self):
+ """
+ Return zedges for (column, row)==(0, 0).
+ """
+ cache_index = 'zedges'
+ if cache_index not in self._cache_dict or \
+ self._cache_dict[cache_index].out_of_date:
+ zedge = np.concatenate((np.array([self.top[0, 0]]),
+ self.botm[:, 0, 0]))
+ self._cache_dict[cache_index] = \
+ CachedData(zedge)
+ if self._copy_cache:
+ return self._cache_dict[cache_index].data
+ else:
+ return self._cache_dict[cache_index].data_nocopy
+
@property
def xyzcellcenters(self):
"""
@@ -421,6 +438,57 @@ def write_shapefile(self, filename='grid.shp', epsg=None, prj=None):
write_grid_shapefile(filename, self, array_dict={}, nan_val=-1.0e9,
epsg=epsg, prj=prj)
+ def is_regular(self):
+ """
+ Test whether the grid spacing is regular or not (including in the
+ vertical direction).
+ """
+ # Relative tolerance to use in test
+ rel_tol = 1.e-5
+
+ # Regularity test in x direction
+ rel_diff_x = (self.delr - self.delr[0]) / self.delr[0]
+ is_regular_x = np.count_nonzero(rel_diff_x > rel_tol) == 0
+
+ # Regularity test in y direction
+ rel_diff_y = (self.delc - self.delc[0]) / self.delc[0]
+ is_regular_y = np.count_nonzero(rel_diff_y > rel_tol) == 0
+
+ # Regularity test in z direction
+ thickness = (self.top[0, 0] - self.botm[0, 0, 0])
+ rel_diff_z1 = (self.top - self.botm[0, :, :] - thickness) / thickness
+ failed = np.abs(rel_diff_z1) > rel_tol
+ is_regular_z = np.count_nonzero(failed) == 0
+ for k in range(self.nlay - 1):
+ rel_diff_zk = (self.botm[k, :, :] - self.botm[k + 1, :, :] -
+ thickness) / thickness
+ failed = np.abs(rel_diff_zk) > rel_tol
+ is_regular_z = is_regular_z and np.count_nonzero(failed) == 0
+
+ return is_regular_x and is_regular_y and is_regular_z
+
+ def is_rectilinear(self):
+ """
+ Test whether the grid is rectilinear (it is always so in the x and
+ y directions, but not necessarily in the z direction).
+ """
+ # Relative tolerance to use in test
+ rel_tol = 1.e-5
+
+ # Rectilinearity test in z direction
+ thickness = (self.top[0, 0] - self.botm[0, 0, 0])
+ rel_diff_z1 = (self.top - self.botm[0, :, :] - thickness) / thickness
+ failed = np.abs(rel_diff_z1) > rel_tol
+ is_rectilinear_z = np.count_nonzero(failed) == 0
+ for k in range(self.nlay - 1):
+ thickness_k = (self.botm[k, 0, 0] - self.botm[k + 1, 0, 0])
+ rel_diff_zk = (self.botm[k, :, :] - self.botm[k + 1, :, :] -
+ thickness_k) / thickness_k
+ failed = np.abs(rel_diff_zk) > rel_tol
+ is_rectilinear_z = is_rectilinear_z and \
+ np.count_nonzero(failed) == 0
+
+ return is_rectilinear_z
if __name__ == "__main__":
import matplotlib.pyplot as plt
diff --git a/flopy/export/utils.py b/flopy/export/utils.py
index 4b4a9eba89..1e23712374 100644
--- a/flopy/export/utils.py
+++ b/flopy/export/utils.py
@@ -512,32 +512,17 @@ def model_export(f, ml, fmt=None, **kwargs):
or dictionary of ....
ml : flopy.modflow.mbase.ModelInterface object
flopy model object
- fmt: str
- output format flag. set to 'vtk' to export to vtk .vtu file
-
+ fmt : str
+ output format flag. 'vtk' will export to vtk
**kwargs : keyword arguments
- modelgrid: flopy.discretization.Grid
+ modelgrid: flopy.discretization.Grid
user supplied modelgrid object which will supercede the built
in modelgrid object
epsg : int
epsg projection code
prj : str
prj file name
-
- smooth: bool
- For vtk, if set to True will output smooth surface
-
- point_scalars: bool
- For vtk, if set to True will create point scalar values along
- with cell values.
-
- binary: bool
- For vtk, if set to Ture will output binary .vtu files. Default
- is False which exports standard text xml .vtu files.
-
- nanval: For vtk, no data value
-
-
+ if fmt is set to 'vtk', parameters of vtk.export_model
"""
assert isinstance(ml, ModelInterface)
@@ -567,13 +552,14 @@ def model_export(f, ml, fmt=None, **kwargs):
elif fmt == 'vtk':
# call vtk model export
+ nanval = kwargs.get('nanval', -1e20)
smooth = kwargs.get('smooth', False)
point_scalars = kwargs.get('point_scalars', False)
+ vtk_grid_type = kwargs.get('vtk_grid_type', 'auto')
binary = kwargs.get('binary', False)
- nanval = kwargs.get('nanval', -1e20)
- vtk.export_model(ml, f, package_names=package_names, smooth=smooth,
- point_scalars=point_scalars, binary=binary,
- nanval=nanval)
+ vtk.export_model(ml, f, package_names=package_names, nanval=nanval,
+ smooth=smooth, point_scalars=point_scalars,
+ vtk_grid_type=vtk_grid_type, binary=binary)
else:
raise NotImplementedError("unrecognized export argument:{0}".format(f))
@@ -591,8 +577,8 @@ def package_export(f, pak, fmt=None, **kwargs):
output file name (ends in .shp for shapefile or .nc for netcdf)
pak : flopy.pakbase.Package object
package to export
- fmt: str
- output format flag. set to 'vtk' to export to vtk .vtu file
+ fmt : str
+ output format flag. 'vtk' will export to vtk
** kwargs : keword arguments
modelgrid: flopy.discretization.Grid
user supplied modelgrid object which will supercede the built
@@ -601,19 +587,7 @@ def package_export(f, pak, fmt=None, **kwargs):
epsg projection code
prj : str
prj file name
-
- smooth: bool
- For vtk, if set to True will output smooth surface
-
- point_scalars: bool
- For vtk, if set to True will create point scalar values along
- with cell values.
-
- binary: bool
- For vtk, if set to Ture will output binary .vtu files. Default
- is False which exports standard text xml .vtu files.
-
- nanval: For vtk, no data value
+ if fmt is set to 'vtk', parameters of vtk.export_package
Returns
-------
@@ -656,14 +630,14 @@ def package_export(f, pak, fmt=None, **kwargs):
elif fmt == 'vtk':
# call vtk array export to folder
+ nanval = kwargs.get('nanval', -1e20)
smooth = kwargs.get('smooth', False)
point_scalars = kwargs.get('point_scalars', False)
+ vtk_grid_type = kwargs.get('vtk_grid_type', 'auto')
binary = kwargs.get('binary', False)
- nanval = kwargs.get('nanval', -1e20)
- vtk.export_package(pak.parent, pak.name, f, smooth=smooth,
- point_scalars=point_scalars, binary=binary,
- nanval=nanval)
-
+ vtk.export_package(pak.parent, pak.name, f, nanval=nanval,
+ smooth=smooth, point_scalars=point_scalars,
+ vtk_grid_type=vtk_grid_type, binary=binary)
else:
raise NotImplementedError("unrecognized export argument:{0}".format(f))
@@ -874,18 +848,14 @@ def transient2d_export(f, t2d, fmt=None, **kwargs):
f : str
filename or existing export instance type (NetCdf only for now)
u2d : Transient2d instance
- fmt: set to 'vtk' to export a .vtu file
+ fmt : str
+ output format flag. 'vtk' will export to vtk
**kwargs : keyword arguments
min_valid : minimum valid value
max_valid : maximum valid value
modelgrid : flopy.discretization.Grid
model grid instance which will supercede the flopy.model.modelgrid
- smooth: for vtk to output a smooth represenation of the model
- point_scalars: for vtk to output point value scalars as well as cell
- name: for vtk to set a specific name for array and output file
- binary: bool
- For vtk, if set to True will output binary .vtu files. Default
- is False which exports standard text xml .vtu files.
+ if fmt is set to 'vtk', parameters of vtk.export_transient
"""
@@ -986,13 +956,16 @@ def transient2d_export(f, t2d, fmt=None, **kwargs):
return f
elif fmt == 'vtk':
- smooth = kwargs.get('smooth', False)
- point_scalars = kwargs.get('point_scalars', False)
name = kwargs.get('name', t2d.name)
nanval = kwargs.get('nanval', -1e20)
- vtk.export_transient(t2d.model, t2d.array, f, name, smooth=smooth,
- point_scalars=point_scalars, array2d=True,
- nanval=nanval)
+ smooth = kwargs.get('smooth', False)
+ point_scalars = kwargs.get('point_scalars', False)
+ vtk_grid_type = kwargs.get('vtk_grid_type', 'auto')
+ binary = kwargs.get('binary', False)
+ vtk.export_transient(t2d.model, t2d.array, f, name, nanval=nanval,
+ smooth=smooth, point_scalars=point_scalars,
+ array2d=True, vtk_grid_type=vtk_grid_type,
+ binary=binary)
else:
raise NotImplementedError("unrecognized export argument:{0}".format(f))
@@ -1006,18 +979,14 @@ def array3d_export(f, u3d, fmt=None, **kwargs):
f : str
filename or existing export instance type (NetCdf only for now)
u2d : Util3d instance
- fmt: set to 'vtk' to export a .vtu file
+ fmt : str
+ output format flag. 'vtk' will export to vtk
**kwargs : keyword arguments
min_valid : minimum valid value
max_valid : maximum valid value
modelgrid : flopy.discretization.Grid
model grid instance which will supercede the flopy.model.modelgrid
- smooth: for vtk to output a smooth represenation of the model
- point_scalars: for vtk to output point value scalars as well as cell
- name: for vtk to set a specific name for array and output file
- binary: bool
- For vtk, if set to Ture will output binary .vtu files. Default
- is False which exports standard text xml .vtu files.
+ if fmt is set to 'vtk', parameters of vtk.export_array
"""
@@ -1137,17 +1106,18 @@ def array3d_export(f, u3d, fmt=None, **kwargs):
elif fmt == 'vtk':
# call vtk array export to folder
+ name = kwargs.get('name', u3d.name)
+ nanval = kwargs.get('nanval', -1e20)
smooth = kwargs.get('smooth', False)
point_scalars = kwargs.get('point_scalars', False)
- name = kwargs.get('name', u3d.name)
+ vtk_grid_type = kwargs.get('vtk_grid_type', 'auto')
binary = kwargs.get('binary', False)
- nanval = kwargs.get('nanval', -1e20)
if isinstance(name, list) or isinstance(name, tuple):
name = name[0]
- vtk.export_array(u3d.model, u3d.array, f, name, smooth=smooth,
- point_scalars=point_scalars, binary=binary,
- nanval=nanval)
+ vtk.export_array(u3d.model, u3d.array, f, name, nanval=nanval,
+ smooth=smooth, point_scalars=point_scalars,
+ vtk_grid_type=vtk_grid_type, binary=binary)
else:
raise NotImplementedError("unrecognized export argument:{0}".format(f))
@@ -1162,18 +1132,14 @@ def array2d_export(f, u2d, fmt=None, **kwargs):
f : str
filename or existing export instance type (NetCdf only for now)
u2d : Util2d instance
- fmt: set to 'vtk' to export a .vtu file
+ fmt : str
+ output format flag. 'vtk' will export to vtk
**kwargs : keyword arguments
min_valid : minimum valid value
max_valid : maximum valid value
modelgrid : flopy.discretization.Grid
model grid instance which will supercede the flopy.model.modelgrid
- smooth: for vtk to output a smooth represenation of the model
- point_scalars: for vtk to output point value scalars as well as cell
- name: for vtk to set a specific name for array and output file
- binary: bool
- For vtk, if set to Ture will output binary .vtu files. Default
- is False which exports standard text xml .vtu files.
+ if fmt is set to 'vtk', parameters of vtk.export_array
"""
assert isinstance(u2d, DataInterface), "util2d_helper only helps " \
@@ -1269,14 +1235,16 @@ def array2d_export(f, u2d, fmt=None, **kwargs):
elif fmt == 'vtk':
# call vtk array export to folder
+ name = kwargs.get('name', u2d.name)
+ nanval = kwargs.get('nanval', -1e20)
smooth = kwargs.get('smooth', False)
point_scalars = kwargs.get('point_scalars', False)
- name = kwargs.get('name', u2d.name)
+ vtk_grid_type = kwargs.get('vtk_grid_type', 'auto')
binary = kwargs.get('binary', False)
- nanval = kwargs.get('nanval', -1e20)
- vtk.export_array(u2d.model, u2d.array, f, name, smooth=smooth,
- point_scalars=point_scalars, array2d=True,
- binary=binary, nanval=nanval)
+ vtk.export_array(u2d.model, u2d.array, f, name, nanval=nanval,
+ smooth=smooth, point_scalars=point_scalars,
+ array2d=True, vtk_grid_type=vtk_grid_type,
+ binary=binary)
else:
raise NotImplementedError("unrecognized export argument:{0}".format(f))
diff --git a/flopy/export/vtk.py b/flopy/export/vtk.py
index dee14c1327..1fed49a8a7 100644
--- a/flopy/export/vtk.py
+++ b/flopy/export/vtk.py
@@ -11,7 +11,17 @@
# Module for exporting vtk from flopy
-# BINARY *********************************************
+np_to_vtk_type = {'int8': 'Int8',
+ 'uint8': 'UInt8',
+ 'int16': 'Int16',
+ 'uint16': 'UInt16',
+ 'int32': 'Int32',
+ 'uint32': 'UInt32',
+ 'int64': 'Int64',
+ 'uint64': 'UInt64',
+ 'float32': 'Float32',
+ 'float64': 'Float64'}
+
np_to_struct = {'int8': 'b',
'uint8': 'B',
'int16': 'h',
@@ -24,127 +34,293 @@
'float64': 'd'}
-class BinaryXml:
+class XmlWriterInterface:
"""
- Helps write binary vtk files
+ Helps writing vtk files.
Parameters
----------
file_path : str
output file path
-
"""
def __init__(self, file_path):
- self.stream = open(file_path, "wb")
+ # class attributes
self.open_tag = False
self.current = []
- self.stream.write(b'')
- if sys.byteorder == "little":
- self.byte_order = '<'
- else:
- self.byte_order = '>'
+ self.indent_level = 0
+ self.indent_char=' '
- def write_size(self, block_size):
- # size is a 64 bit unsigned integer
- byte_order = self.byte_order + 'Q'
- block_size = struct.pack(byte_order, block_size)
- self.stream.write(block_size)
+ # open file and initialize
+ self.f = self._open_file(file_path)
+ self.write_string('')
- def write_array(self, data):
- assert (data.flags['C_CONTIGUOUS'] or data.flags['F_CONTIGUOUS'])
+ # open VTKFile element
+ self.open_element('VTKFile').add_attributes(version='0.1')
- # ravel in fortran order
- dd = np.ravel(data, order='F')
-
- data_format = self.byte_order + str(data.size) + np_to_struct[
- data.dtype.name]
- binary_data = struct.pack(data_format, *dd)
- self.stream.write(binary_data)
-
- def write_coord_arrays(self, x, y, z):
- # check that arrays are the same shape and data type
- assert (x.size == y.size == z.size)
- assert (x.dtype.itemsize == y.dtype.itemsize == z.dtype.itemsize)
-
- # check if arrays are contiguous
- assert (x.flags['C_CONTIGUOUS'] or x.flags['F_CONTIGUOUS'])
- assert (y.flags['C_CONTIGUOUS'] or y.flags['F_CONTIGUOUS'])
- assert (z.flags['C_CONTIGUOUS'] or z.flags['F_CONTIGUOUS'])
-
- data_format = self.byte_order + str(1) + \
- np_to_struct[x.dtype.name]
-
- xrav = np.ravel(x, order='F')
- yrav = np.ravel(y, order='F')
- zrav = np.ravel(z, order='F')
+ def _open_file(self, file_path):
+ """
+ Open the file for writing.
- for idx in range(x.size):
- bx = struct.pack(data_format, xrav[idx])
- by = struct.pack(data_format, yrav[idx])
- bz = struct.pack(data_format, zrav[idx])
- self.stream.write(bx)
- self.stream.write(by)
- self.stream.write(bz)
+ Return
+ ------
+ File object.
+ """
+ raise NotImplementedError('must define _open_file in child class')
- def close(self):
- assert (not self.open_tag)
- self.stream.close()
+ def write_string(self, string):
+ """
+ Write a string into the file.
+ """
+ raise NotImplementedError('must define write_string in child class')
def open_element(self, tag):
if self.open_tag:
- self.stream.write(b">")
- tag_string = "\n<%s" % tag
- self.stream.write(str.encode(tag_string))
+ self.write_string(">")
+ indent = self.indent_level * self.indent_char
+ self.indent_level += 1
+ tag_string = "\n" + indent + "<%s" % tag
+ self.write_string(tag_string)
self.open_tag = True
self.current.append(tag)
return self
def close_element(self, tag=None):
+ self.indent_level -= 1
if tag:
assert (self.current.pop() == tag)
if self.open_tag:
- self.stream.write(b">")
+ self.write_string(">")
self.open_tag = False
- string = "\n%s>" % tag
- self.stream.write(str.encode(string))
+ indent = self.indent_level * self.indent_char
+ tag_string = "\n" + indent + "%s>" % tag
+ self.write_string(tag_string)
else:
- self.stream.write(b"/>")
+ self.write_string("/>")
self.open_tag = False
self.current.pop()
return self
- def add_text(self, text):
- if self.open_tag:
- self.stream.write(b">\n")
- self.open_tag = False
- self.stream.write(str.encode(text))
- return self
-
def add_attributes(self, **kwargs):
assert self.open_tag
for key in kwargs:
st = ' %s="%s"' % (key, kwargs[key])
- self.stream.write(str.encode(st))
+ self.write_string(st)
+ return self
+
+ def write_line(self, text):
+ if self.open_tag:
+ self.write_string('>')
+ self.open_tag = False
+ self.write_string('\n')
+ indent = self.indent_level * self.indent_char
+ self.write_string(indent)
+ self.write_string(text)
return self
-# END BINARY *********************************************
+ def write_array(self, array, actwcells=None, **kwargs):
+ """
+ Writes an array to the output vtk file.
+
+ Parameters
+ ----------
+ array : ndarray
+ the data array being output
+ actwcells : array
+ array of the active cells
+ kwargs : dictionary
+ Attributes to be added to the DataArray element
+ """
+ raise NotImplementedError('must define write_array in child class')
+
+ def final(self):
+ """
+ Finalize the file. Must be called.
+ """
+ self.close_element('VTKFile')
+ assert (not self.open_tag)
+ self.f.close()
-def start_tag(f, tag, indent_level, indent_char=' '):
- # starts xml tag
- s = indent_level * indent_char + tag
- indent_level += 1
- f.write(s + '\n')
- return indent_level
+class XmlWriterAscii(XmlWriterInterface):
+ """
+ Helps writing ascii vtk files.
+ Parameters
+ ----------
-def end_tag(f, tag, indent_level, indent_char=' '):
- # ends xml tag
- indent_level -= 1
- s = indent_level * indent_char + tag
- f.write(s + '\n')
- return indent_level
+ file_path : str
+ output file path
+ """
+ def __init__(self, file_path):
+ super(XmlWriterAscii, self).__init__(file_path)
+
+ def _open_file(self, file_path):
+ """
+ Open the file for writing.
+
+ Return
+ ------
+ File object.
+ """
+ return open(file_path, "w")
+
+ def write_string(self, string):
+ """
+ Write a string into the file.
+ """
+ self.f.write(string)
+
+ def write_array(self, array, actwcells=None, **kwargs):
+ """
+ Writes an array to the output vtk file.
+
+ Parameters
+ ----------
+ array : ndarray
+ the data array being output
+ actwcells : array
+ array of the active cells
+ kwargs : dictionary
+ Attributes to be added to the DataArray element
+ """
+ # open DataArray element with relevant attributes
+ self.open_element('DataArray')
+ vtk_type = np_to_vtk_type[array.dtype.name]
+ self.add_attributes(type=vtk_type)
+ self.add_attributes(**kwargs)
+ self.add_attributes(format='ascii')
+
+ # write the data
+ nlay = array.shape[0]
+ for lay in range(nlay):
+ if actwcells is not None:
+ idx = (actwcells[lay] != 0)
+ array_lay_flat = array[lay][idx].flatten()
+ else:
+ array_lay_flat = array[lay].flatten()
+ # replace NaN values by -1.e9 as there is a bug is Paraview when
+ # reading NaN in ASCII mode
+ # https://gitlab.kitware.com/paraview/paraview/issues/19042
+ # this may be removed in the future if they fix the bug
+ array_lay_flat[np.isnan(array_lay_flat)] = -1.e9
+ s = ' '.join(['{}'.format(val) for val in array_lay_flat])
+ self.write_line(s)
+
+ # close DataArray element
+ self.close_element('DataArray')
+ return
+
+
+class XmlWriterBinary(XmlWriterInterface):
+ """
+ Helps writing binary vtk files.
+
+ Parameters
+ ----------
+
+ file_path : str
+ output file path
+
+ """
+ def __init__(self, file_path):
+ super(XmlWriterBinary, self).__init__(file_path)
+
+ if sys.byteorder == "little":
+ self.byte_order = '<'
+ self.add_attributes(byte_order='LittleEndian')
+ else:
+ self.byte_order = '>'
+ self.add_attributes(byte_order='BigEndian')
+ self.add_attributes(header_type="UInt64")
+
+ # class attributes
+ self.offset = 0
+ self.byte_count_size = 8
+ self.processed_arrays = []
+
+ def _open_file(self, file_path):
+ """
+ Open the file for writing.
+
+ Return
+ ------
+ File object.
+ """
+ return open(file_path, "wb")
+
+ def write_string(self, string):
+ """
+ Write a string into the file.
+ """
+ self.f.write(str.encode(string))
+
+ def write_array(self, array, actwcells=None, **kwargs):
+ """
+ Writes an array to the output vtk file.
+
+ Parameters
+ ----------
+ array : ndarray
+ the data array being output
+ actwcells : array
+ array of the active cells
+ kwargs : dictionary
+ Attributes to be added to the DataArray element
+ """
+ # open DataArray element with relevant attributes
+ self.open_element('DataArray')
+ vtk_type = np_to_vtk_type[array.dtype.name]
+ self.add_attributes(type=vtk_type)
+ self.add_attributes(**kwargs)
+ self.add_attributes(format='appended', offset=self.offset)
+
+ # store array for later writing (appended data section)
+ if actwcells is not None:
+ array = array[actwcells != 0]
+ a = np.ascontiguousarray(array.ravel())
+ array_size = array.size * array[0].dtype.itemsize
+ self.processed_arrays.append([a, array_size])
+
+ # calculate the offset of the start of the next piece of data
+ # offset is calculated from beginning of data section
+ self.offset += array_size + self.byte_count_size
+
+ # close DataArray element
+ self.close_element('DataArray')
+ return
+
+ def _write_size(self, block_size):
+ # size is a 64 bit unsigned integer
+ byte_order = self.byte_order + 'Q'
+ block_size = struct.pack(byte_order, block_size)
+ self.f.write(block_size)
+
+ def _append_array_binary(self, data):
+ # see vtk documentation and more details here:
+ # https://vtk.org/Wiki/VTK_XML_Formats#Appended_Data_Section
+ assert (data.flags['C_CONTIGUOUS'] or data.flags['F_CONTIGUOUS'])
+ assert data.ndim==1
+ data_format = self.byte_order + str(data.size) + \
+ np_to_struct[data.dtype.name]
+ binary_data = struct.pack(data_format, *data)
+ self.f.write(binary_data)
+
+ def final(self):
+ """
+ Finalize the file. Must be called.
+ """
+ # build data section
+ self.open_element('AppendedData')
+ self.add_attributes(encoding='raw')
+ self.write_line('_')
+ for a, block_size in self.processed_arrays:
+ self._write_size(block_size)
+ self._append_array_binary(a)
+ self.close_element('AppendedData')
+
+ # call super final
+ super(XmlWriterBinary, self).final()
class _Array(object):
@@ -173,24 +349,34 @@ class Vtk(object):
model : MFModel
flopy model instance
verbose : bool
- if True, stdout is verbose
+ If True, stdout is verbose
nanval : float
no data value, default is -1e20
smooth : bool
- If True will create smooth output surface
+ if True, will create smooth layer elevations, default is False
point_scalars : bool
- if True will output point scalar values, this will set smooth to True.
+ if True, will also output array values at cell vertices, default is
+ False; note this automatically sets smooth to True
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (i.e., with cubic cells) will be saved as an
+ 'ImageData'.
+ * A rectilinear, non-regular grid will be saved as a
+ 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
+ binary : bool
+ if True the output file will be binary, default is False
Attributes
----------
arrays : dict
Stores data arrays added to VTK object
-
"""
-
def __init__(self, model, verbose=None, nanval=-1e+20, smooth=False,
- point_scalars=False):
+ point_scalars=False, vtk_grid_type='auto', binary=False):
if point_scalars:
smooth = True
@@ -202,7 +388,6 @@ def __init__(self, model, verbose=None, nanval=-1e+20, smooth=False,
# set up variables
self.model = model
self.modelgrid = model.modelgrid
- self.arrays = {}
self.nlay = self.modelgrid.nlay
if hasattr(self.model, 'dis') and hasattr(self.model.dis, 'laycbd'):
self.nlay = self.nlay + np.sum(self.model.dis.laycbd.array > 0)
@@ -246,12 +431,80 @@ def __init__(self, model, verbose=None, nanval=-1e+20, smooth=False,
self.verts, self.iverts, self.zverts = \
self.get_3d_vertex_connectivity()
+ self.vtk_grid_type, self.file_extension = \
+ self._vtk_grid_type(vtk_grid_type)
+
+ self.binary = binary
+
return
- def add_array(self, name, a, array2d=False):
+ def _vtk_grid_type(self, vtk_grid_type='auto'):
+ """
+ Determine the vtk grid type and corresponding file extension.
+ Parameters
+ ----------
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (in all three directions) will be saved as an
+ 'ImageData'.
+ * A rectilinear (in all three directions), non-regular grid
+ will be saved as a 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
+
+ Returns
+ ----------
+ (vtk_grid_type, file_extension) : tuple of two strings
"""
+ # if 'auto', determine the vtk grid type automatically
+ if vtk_grid_type == 'auto':
+ if self.modelgrid.grid_type == 'structured':
+ if self.modelgrid.is_regular():
+ vtk_grid_type = 'ImageData'
+ elif self.modelgrid.is_rectilinear():
+ vtk_grid_type = 'RectilinearGrid'
+ else:
+ vtk_grid_type = 'UnstructuredGrid'
+ else:
+ vtk_grid_type = 'UnstructuredGrid'
+ # otherwise, check the validity of the passed vtk_grid_type
+ else:
+ allowable_types = ['ImageData', 'RectilinearGrid',
+ 'UnstructuredGrid']
+ if not any(vtk_grid_type in s for s in allowable_types):
+ raise ValueError('"' + vtk_grid_type + '" is not a correct '\
+ 'vtk_grid_type.')
+ if (vtk_grid_type == 'ImageData' or \
+ vtk_grid_type == 'RectilinearGrid') and \
+ not self.modelgrid.grid_type == 'structured':
+ raise NotImplementedError('vtk_grid_type cannot be "' + \
+ vtk_grid_type + '" for a grid '\
+ 'that is not structured')
+ if vtk_grid_type == 'ImageData' and \
+ not self.modelgrid.is_regular():
+ raise ValueError('vtk_grid_type cannot be "ImageData" for a '\
+ 'non-regular grid spacing')
+ if vtk_grid_type == 'RectilinearGrid' and \
+ not self.modelgrid.is_rectilinear():
+ raise ValueError('vtk_grid_type cannot be "RectilinearGrid" '\
+ 'for a non-rectilinear grid spacing')
+
+ # determine the file extension
+ if vtk_grid_type == 'ImageData':
+ file_extension = '.vti'
+ elif vtk_grid_type == 'RectilinearGrid':
+ file_extension = '.vtr'
+ # else vtk_grid_type == 'UnstructuredGrid'
+ else:
+ file_extension = '.vtu'
+
+ # return vtk grid type and file extension
+ return (vtk_grid_type, file_extension)
+ def add_array(self, name, a, array2d=False):
+ """
Adds an array to the vtk object
Parameters
@@ -263,12 +516,7 @@ def add_array(self, name, a, array2d=False):
the array to be added to the vtk object
array2d : bool
True if the array is 2d
-
"""
-
- if name == 'ibound':
- return
-
# if array is 2d reformat to 3d array
if array2d:
assert a.shape == self.shape2d
@@ -277,392 +525,205 @@ def add_array(self, name, a, array2d=False):
a = array
try:
-
assert a.shape == self.shape
except AssertionError:
return
- a = np.where(a == self.nanval, np.nan, a)
- a = a.astype(float)
- # idxs = np.argwhere(a == self.nanval)
+ # assign nan where nanval or ibound==0
+ where_to_nan = np.logical_or(a==self.nanval, self.ibound==0)
+ a = np.where(where_to_nan, np.nan, a)
- # add array to self.arrays
+ # add a copy of the array to self.arrays
+ a = a.astype(float)
self.arrays[name] = a
return
def write(self, output_file, timeval=None):
"""
-
- writes the stored arrays to vtk file
+ Writes the stored arrays to vtk file in XML format.
Parameters
----------
output_file : str
- output file name to write the vtk data
-
+ output file name without extension (extension is determined
+ automatically)
timeval : scalar
model time value to be stored in the time section of the vtk
file, default is None
"""
-
- # make sure file ends with vtu
- assert output_file.lower().endswith(".vtu")
-
- # get the active data cells based on the data arrays and ibound
- actwcells3d = self._configure_data_arrays()
- actwcells = actwcells3d.ravel()
-
- # get the indexes of the active cells
- idxs = np.argwhere(actwcells != 0).ravel()
-
- # get the verts and iverts to be output
- verts = [self.verts[idx] for idx in idxs]
- iverts = self._build_iverts(verts)
-
- # get the total number of cells and vertices
- ncells = len(iverts)
- npoints = ncells * 8
-
+ # output file
+ output_file = output_file + self.file_extension
if self.verbose:
print('Writing vtk file: ' + output_file)
- print('Number of point is {}, Number of cells is {}\n'.format(
- npoints, ncells))
-
- # open output file for writing
- f = open(output_file, 'w')
- # write xml
- indent_level = 0
- s = ''
- f.write(s + '\n')
- indent_level = start_tag(f, '',
- indent_level)
+ # initialize xml file
+ if self.binary:
+ xml = XmlWriterBinary(output_file)
+ else:
+ xml = XmlWriterAscii(output_file)
+ xml.add_attributes(type=self.vtk_grid_type)
- indent_level = start_tag(f, '', indent_level)
+ # grid type
+ xml.open_element(self.vtk_grid_type)
# if time value write time section
if timeval:
-
- indent_level = start_tag(f, '', indent_level)
-
- s = ''
- indent_level = start_tag(f, s, indent_level)
-
- f.write(indent_level * ' ' + '{}\n'.format(timeval))
-
- indent_level = end_tag(f, '', indent_level)
-
- indent_level = end_tag(f, '', indent_level)
-
- # piece
- s = ''.format(npoints, ncells)
- indent_level = start_tag(f, s, indent_level)
-
- # points
- s = ''
- indent_level = start_tag(f, s, indent_level)
-
- s = ''
- indent_level = start_tag(f, s, indent_level)
- assert (isinstance(self.modelgrid, StructuredGrid))
- for cell in verts:
- for row in cell:
- s = indent_level * ' ' + '{} {} {} \n'.format(*row)
- f.write(s)
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- # cells
- s = ''
- indent_level = start_tag(f, s, indent_level)
-
- s = ''
- indent_level = start_tag(f, s, indent_level)
- for row in iverts:
- s = indent_level * ' ' + ' '.join([str(i) for i in row]) + '\n'
- f.write(s)
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- s = ''
- indent_level = start_tag(f, s, indent_level)
- icount = 0
- for row in iverts:
- icount += len(row)
- s = indent_level * ' ' + '{} \n'.format(icount)
- f.write(s)
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- s = ''
- indent_level = start_tag(f, s, indent_level)
- for row in iverts:
- s = indent_level * ' ' + '{} \n'.format(self.cell_type)
- f.write(s)
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- # add cell data
- s = ''
- indent_level = start_tag(f, s, indent_level)
-
- # write data arrays to file
- for arrayName, arrayValues in self.arrays.items():
- self.write_data_array(f, indent_level, arrayName,
- arrayValues, actwcells3d)
-
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- # write arrays as point data if point scalars is set to True
- if self.point_scalars:
- s = ''
- indent_level = start_tag(f, s, indent_level)
- for array_name, array_values in self.arrays.items():
- self.write_point_value(f, indent_level, array_values,
- array_name, actwcells3d)
-
- s = ''
- indent_level = end_tag(f, s, indent_level)
-
- else:
- pass
-
- # end piece
- indent_level = end_tag(f, '', indent_level)
-
- # end unstructured grid
- indent_level = end_tag(f, '', indent_level)
-
- # end xml
- indent_level = end_tag(f, '', indent_level)
-
- # end file
- f.close()
- self.arrays.clear()
- return
-
- def write_binary(self, output_file):
-
- """
-
- outputs binary .vtu file
-
- Parameters
- ----------
-
- output_file : str
- vtk output file
-
- """
-
- # make sure file ends with vtu
- assert output_file.lower().endswith(".vtu")
-
- if self.verbose:
- print('writing binary vtk file')
-
- xml = BinaryXml(output_file)
- offset = 0
- grid_type = 'UnstructuredGrid'
-
- # get the active data cells based on the data arrays and ibound
- actwcells3d = self._configure_data_arrays()
- actwcells = actwcells3d.ravel()
-
- # get the indexes of the active cells
- idxs = np.argwhere(actwcells != 0).ravel()
-
- # get the verts and iverts to be output
- verts = [self.verts[idx] for idx in idxs]
- iverts = self._build_iverts(verts)
-
- # check if there is data to be written out
- if len(verts) == 0:
- # if not cannot write binary .vtu file
- return
-
- # get the total number of cells and vertices
- ncells = len(iverts)
- npoints = ncells * 8
-
- if self.verbose:
- print('Writing vtk file: ' + output_file)
- print('Number of point is {}, Number of cells is {}\n'.format(
- npoints, ncells))
-
- # format verts and iverts
- verts = np.array(verts)
- verts.reshape(npoints, 3)
- iverts = np.ascontiguousarray(iverts, np.float64)
-
- # write xml file info
- xml.open_element("VTKFile"). \
- add_attributes(type=grid_type, version="1.0",
- byte_order=self._get_byte_order(),
- header_type="UInt64")
- # unstructured grid
- xml.open_element(grid_type)
-
- # piece
- xml.open_element('Piece')
- xml.add_attributes(NumberOfPoints=npoints, NumberOfCells=ncells)
-
- # points
- xml.open_element('Points')
-
- xml.open_element('DataArray')
- xml.add_attributes(Name='points', NumberOfComponents='3',
- type='Float64',
- format='appended', offset=offset)
-
- # calculate the offset of the start of the next piece of data
- # offset is calculated from beginning of data section
- points_size = verts.size * verts[0].dtype.itemsize
- offset += points_size + 8
-
- xml.close_element('DataArray')
-
- xml.close_element('Points')
-
- # cells
- xml.open_element('Cells')
-
- # connectivity
- xml.open_element('DataArray')
- xml.add_attributes(Name='connectivity', NumberOfComponents='1',
- type='Float64',
- format='appended', offset=offset)
- conn_size = iverts.size * iverts[0].dtype.itemsize
- offset += conn_size + 8
-
- xml.close_element('DataArray')
-
- xml.open_element('DataArray')
- xml.add_attributes(Name='offsets', NumberOfComponents='1',
- type='Float64',
- format='appended', offset=offset)
- offsets_size = iverts.shape[0] * iverts[0].dtype.itemsize
- offset += offsets_size + 8
-
- xml.close_element('DataArray')
-
- xml.open_element('DataArray')
- xml.add_attributes(Name='types', NumberOfComponents='1',
- type='Float64',
- format='appended', offset=offset)
- types_size = iverts.shape[0] * iverts[0].dtype.itemsize
- offset += types_size + 8
-
- xml.close_element('DataArray')
-
- xml.close_element('Cells')
-
+ xml.open_element('FieldData')
+ xml.write_array(np.array([timeval]), Name='TimeValue',
+ NumberOfTuples='1', RangeMin='{0}', RangeMax='{0}')
+ xml.close_element('FieldData')
+
+ if self.vtk_grid_type == 'UnstructuredGrid':
+ # get the active data cells based on the data arrays and ibound
+ actwcells3d = self._configure_data_arrays()
+
+ # get the verts and iverts to be output
+ verts, iverts, _ = \
+ self.get_3d_vertex_connectivity(actwcells=actwcells3d)
+
+ # check if there is data to be written out
+ if len(verts) == 0:
+ # if nothing, cannot write file
+ return
+
+ # get the total number of cells and vertices
+ ncells = len(iverts)
+ npoints = ncells * 8
+ if self.verbose:
+ print('Number of point is {}, Number of cells is {}\n'.format(
+ npoints, ncells))
+
+ # piece
+ xml.open_element('Piece')
+ xml.add_attributes(NumberOfPoints=npoints, NumberOfCells=ncells)
+
+ # points
+ xml.open_element('Points')
+ verts = np.array(list(verts.values()))
+ verts.reshape(npoints, 3)
+ xml.write_array(verts, Name='points', NumberOfComponents='3')
+ xml.close_element('Points')
+
+ # cells
+ xml.open_element('Cells')
+
+ # connectivity
+ iverts = np.array(list(iverts.values()))
+ xml.write_array(iverts, Name='connectivity',
+ NumberOfComponents='1')
+
+ # offsets
+ offsets = np.empty((iverts.shape[0]), np.int32)
+ icount = 0
+ for index, row in enumerate(iverts):
+ icount += len(row)
+ offsets[index] = icount
+ xml.write_array(offsets, Name='offsets', NumberOfComponents='1')
+
+ # types
+ types = np.full((iverts.shape[0]), self.cell_type, dtype=np.uint8)
+ xml.write_array(types, Name='types', NumberOfComponents='1')
+
+ # end cells
+ xml.close_element('Cells')
+
+ elif self.vtk_grid_type == 'ImageData':
+ # note: in vtk, "extent" actually means indices of grid lines
+ vtk_extent_str = '0' + ' ' + str(self.modelgrid.ncol) + ' ' + \
+ '0' + ' ' + str(self.modelgrid.nrow) + ' ' + \
+ '0' + ' ' + str(self.modelgrid.nlay)
+ xml.add_attributes(WholeExtent=vtk_extent_str)
+ grid_extent = self.modelgrid.xyzextent
+ vtk_origin_str = str(grid_extent[0]) + ' ' + \
+ str(grid_extent[2]) + ' ' + \
+ str(grid_extent[4])
+ xml.add_attributes(Origin=vtk_origin_str)
+ vtk_spacing_str = str(self.modelgrid.delr[0]) + ' ' + \
+ str(self.modelgrid.delc[0]) + ' ' + \
+ str(self.modelgrid.top[0, 0] -
+ self.modelgrid.botm[0, 0, 0])
+ xml.add_attributes(Spacing=vtk_spacing_str)
+
+ # piece
+ xml.open_element('Piece').add_attributes(Extent=vtk_extent_str)
+
+ elif self.vtk_grid_type == 'RectilinearGrid':
+ # note: in vtk, "extent" actually means indices of grid lines
+ vtk_extent_str = '0' + ' ' + str(self.modelgrid.ncol) + ' ' + \
+ '0' + ' ' + str(self.modelgrid.nrow) + ' ' + \
+ '0' + ' ' + str(self.modelgrid.nlay)
+ xml.add_attributes(WholeExtent=vtk_extent_str)
+
+ # piece
+ xml.open_element('Piece').add_attributes(Extent=vtk_extent_str)
+
+ # grid coordinates
+ xml.open_element('Coordinates')
+
+ # along x
+ xedges = self.modelgrid.xyedges[0]
+ xml.write_array(xedges, Name='coord_x', NumberOfComponents='1')
+
+ # along y
+ yedges = np.flip(self.modelgrid.xyedges[1])
+ xml.write_array(yedges, Name='coord_y', NumberOfComponents='1')
+
+ # along z
+ zedges = np.flip(self.modelgrid.zedges)
+ xml.write_array(zedges, Name='coord_z', NumberOfComponents='1')
+
+ # end coordinates
+ xml.close_element('Coordinates')
+
+ # cell data
xml.open_element('CellData')
- xml.add_attributes(Scalars='scalars')
- # format data arrays and store for later output
- processed_arrays = []
+ # loop through stored arrays
for name, a in self.arrays.items():
- a = a.ravel()[idxs]
- xml.open_element('DataArray')
- xml.add_attributes(Name=name, NumberOfComponents='1',
- type='Float64',
- format='appended', offset=offset)
- a = np.ascontiguousarray(a, np.float64)
- processed_arrays.append([a, a.size * a[0].dtype.itemsize])
- offset += processed_arrays[-1][-1] + 8
- xml.close_element('DataArray')
+ if self.vtk_grid_type == 'UnstructuredGrid':
+ xml.write_array(a, actwcells=actwcells3d, Name=name,
+ NumberOfComponents='1')
+ else:
+ # flip "a" so coordinates increase along with indices as in vtk
+ a = np.flip(a, axis=0)
+ a = np.flip(a, axis=1)
+ xml.write_array(a, Name=name, NumberOfComponents='1')
+ # end cell data
xml.close_element('CellData')
- # for data array point scalars
if self.point_scalars:
-
+ # point data (i.e., values at vertices)
xml.open_element('PointData')
- xml.add_attributes(Scalars='scalars')
- # get output point arrays
# loop through stored arrays
for name, a in self.arrays.items():
# get the array values onto vertices
- verts_info = self.get_3d_vertex_connectivity(
- actwcells=actwcells3d, zvalues=a)
- # get values
- point_values_dict = verts_info[2]
- a = np.array([point_values_dict[cellid] for cellid in
- sorted(point_values_dict.keys())]).ravel()
-
- xml.open_element('DataArray')
- xml.add_attributes(Name=name, NumberOfComponents='1',
- type='Float64',
- format='appended', offset=offset)
- a = np.ascontiguousarray(a, np.float64)
- processed_arrays.append([a, a.size * a[0].dtype.itemsize])
- offset += processed_arrays[-1][-1] + 8
-
- xml.close_element('DataArray')
+ if self.vtk_grid_type == 'UnstructuredGrid':
+ _, _, zverts = self.get_3d_vertex_connectivity(
+ actwcells=actwcells3d, zvalues=a)
+ a = np.array(list(zverts.values()))
+ else:
+ a = self.extendedDataArray(a)
+ # flip "a" so coordinates increase along with indices as in
+ # vtk
+ a = np.flip(a, axis=0)
+ a = np.flip(a, axis=1)
+ xml.write_array(a, Name=name, NumberOfComponents='1')
+
+ # end point data
xml.close_element('PointData')
# end piece
xml.close_element('Piece')
- # end unstructured grid
- xml.close_element('UnstructuredGrid')
+ # end vtk_grid_type
+ xml.close_element(self.vtk_grid_type)
+
+ # finalize and close xml file
+ xml.final()
- # build data section
- xml.open_element("AppendedData").add_attributes(
- encoding="raw").add_text("_")
-
- xml.write_size(points_size)
- # format verts for output
- verts_x = np.ascontiguousarray(np.ravel(verts[:, :, 0]),
- np.float64)
- verts_y = np.ascontiguousarray(np.ravel(verts[:, :, 1]),
- np.float64)
- verts_z = np.ascontiguousarray(np.ravel(verts[:, :, 2]),
- np.float64)
- # write coordinates
- xml.write_coord_arrays(verts_x, verts_y, verts_z)
-
- # write iverts
- xml.write_size(conn_size)
- rav_iverts = np.ascontiguousarray(np.ravel(iverts), np.float64)
- xml.write_array(rav_iverts)
-
- xml.write_size(offsets_size)
- data = np.empty((iverts.shape[0]), np.float64)
- icount = 0
- for index, row in enumerate(iverts):
- icount += len(row)
- data[index] = icount
- xml.write_array(data)
-
- # write cell types (11)
- xml.write_size(types_size)
- data = np.empty((iverts.shape[0]), np.float64)
- data.fill(self.cell_type)
- xml.write_array(data)
-
- # write out the array scalars and array point scalars
- for a, block_size in processed_arrays:
- xml.write_size(block_size)
- xml.write_array(a)
-
- # end xml
- xml.close_element("AppendedData")
- xml.close_element('VTKFile')
- xml.close()
# clear arrays
self.arrays.clear()
@@ -671,12 +732,12 @@ def _configure_data_arrays(self):
Compares arrays and active cells to find where active data
exists, and what cells to output.
"""
-
# get 1d shape
shape1d = self.shape[0] * self.shape[1] * self.shape[2]
# build index array
ot_idx_array = np.zeros(shape1d, dtype=np.int)
+
# loop through arrays
for name in self.arrays:
array = self.arrays[name]
@@ -693,15 +754,11 @@ def _configure_data_arrays(self):
# reset the shape of the active data array
ot_idx_array = ot_idx_array.reshape(self.shape)
- # where the ibound is 0 set the active array to 0
- ot_idx_array[self.ibound == 0] = 0
return ot_idx_array
def get_3d_vertex_connectivity(self, actwcells=None, zvalues=None):
-
"""
-
Builds x,y,z vertices
Parameters
@@ -720,7 +777,6 @@ def get_3d_vertex_connectivity(self, actwcells=None, zvalues=None):
dictionary of iverts
zvertsdict : dict
dictionary of zverts
-
"""
# set up active cells
if actwcells is None:
@@ -827,125 +883,12 @@ def extendedDataArray(self, dataArray):
index[1]])
neighList = np.array(neighList)
if neighList[neighList != self.nanval].shape[0] > 0:
- headMean = neighList[neighList != self.nanval].mean()
+ valMean = neighList[neighList != self.nanval].mean()
else:
- headMean = self.nanval
- matrix[lay, row, col] = headMean
+ valMean = self.nanval
+ matrix[lay, row, col] = valMean
return matrix
- @staticmethod
- def _get_byte_order():
- if sys.byteorder == "little":
- return "LittleEndian"
- else:
- return "BigEndian"
-
- @staticmethod
- def write_data_array(f, indent_level, arrayName, arrayValues,
- actWCells):
- """
-
- Writes the data array to the output vtk file
-
- Parameters
- ----------
- f : file object
- output vtk file
- indent_level : int
- current indent of the xml
- arrayName : str
- name of the output array
- arrayValues : array
- the data array being output
- actWCells : array
- array of the active cells
-
- """
-
- s = ''.format(
- arrayName)
- indent_level = start_tag(f, s, indent_level)
-
- # data
- nlay = arrayValues.shape[0]
-
- for lay in range(nlay):
- s = indent_level * ' '
- f.write(s)
- idx = (actWCells[lay] != 0)
- arrayValuesLay = arrayValues[lay][idx].flatten()
- for layValues in arrayValuesLay:
- s = ' {}'.format(layValues)
- f.write(s)
- f.write('\n')
-
- s = ''
- indent_level = end_tag(f, s, indent_level)
- return
-
- def write_point_value(self, f, indent_level, data_array, array_name,
- actwcells):
- """
- Writes the data array to the output vtk file as point scalars
- """
- # header tag
- s = ''.format(
- array_name)
- indent_level = start_tag(f, s, indent_level)
-
- # data
- verts_info = self.get_3d_vertex_connectivity(
- actwcells=actwcells, zvalues=data_array)
-
- zverts = verts_info[2]
-
- for cellid in sorted(zverts):
- for z in zverts[cellid]:
- s = indent_level * ' '
- f.write(s)
- s = ' {}'.format(z)
- f.write(s)
- f.write('\n')
-
- # ending tag
- s = ''
- indent_level = end_tag(f, s, indent_level)
- return
-
- @staticmethod
- def _build_iverts(verts):
- """
-
- Builds the iverts based on the vertices being output
-
- Parameters
- ----------
- verts : array
- vertices being output
-
- Returns
- -------
-
- iverts : array
- array of ivert values
-
- """
- ncells = len(verts)
- npoints = ncells * 8
- iverts = []
- ivert = []
- count = 1
- for i in range(npoints):
- ivert.append(i)
- if count == 8:
- iverts.append(ivert)
- ivert = []
- count = 0
- count += 1
- iverts = np.array(iverts)
-
- return iverts
-
def _get_names(in_list):
ot_list = []
@@ -958,10 +901,9 @@ def _get_names(in_list):
def export_cbc(model, cbcfile, otfolder, precision='single', nanval=-1e+20,
- kstpkper=None, text=None, smooth=False,
- point_scalars=False, binary=False):
+ kstpkper=None, text=None, smooth=False, point_scalars=False,
+ vtk_grid_type='auto', binary=False):
"""
-
Exports cell by cell file to vtk
Parameters
@@ -984,13 +926,21 @@ def export_cbc(model, cbcfile, otfolder, precision='single', nanval=-1e+20,
The text identifier for the record. Examples include
'RIVER LEAKAGE', 'STORAGE', 'FLOW RIGHT FACE', etc.
smooth : bool
- If true a smooth surface will be output, default is False
+ if True, will create smooth layer elevations, default is False
point_scalars : bool
- If True point scalar values will be written, default is False
+ if True, will also output array values at cell vertices, default is
+ False; note this automatically sets smooth to True
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (in all three directions) will be saved as an
+ 'ImageData'.
+ * A rectilinear (in all three directions), non-regular grid
+ will be saved as a 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
binary : bool
- if True the output .vtu file will be binary, default is
- False.
-
+ if True the output file will be binary, default is False
"""
mg = model.modelgrid
@@ -1054,7 +1004,8 @@ def export_cbc(model, cbcfile, otfolder, precision='single', nanval=-1e+20,
# get model name
model_name = model.name
- vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars)
+ vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars,
+ vtk_grid_type=vtk_grid_type, binary=binary)
# export data
addarray = False
@@ -1062,7 +1013,7 @@ def export_cbc(model, cbcfile, otfolder, precision='single', nanval=-1e+20,
for kper in kperlist:
for kstp in kstplist:
- ot_base = '{}_CBC_KPER{}_KSTP{}.vtu'.format(
+ ot_base = '{}_CBC_KPER{}_KSTP{}'.format(
model_name, kper + 1, kstp + 1)
otfile = os.path.join(otfolder, ot_base)
pvdfile.write("""
@@ -1120,10 +1068,9 @@ def export_cbc(model, cbcfile, otfolder, precision='single', nanval=-1e+20,
def export_heads(model, hdsfile, otfolder, nanval=-1e+20, kstpkper=None,
- smooth=False, point_scalars=False,
+ smooth=False, point_scalars=False, vtk_grid_type='auto',
binary=False):
"""
-
Exports binary head file to vtk
Parameters
@@ -1141,13 +1088,21 @@ def export_heads(model, hdsfile, otfolder, nanval=-1e+20, kstpkper=None,
A tuple containing the time step and stress period (kstp, kper).
The kstp and kper values are zero based.
smooth : bool
- If true a smooth surface will be output, default is False
+ if True, will create smooth layer elevations, default is False
point_scalars : bool
- If True point scalar values will be written, default is False
+ if True, will also output array values at cell vertices, default is
+ False; note this automatically sets smooth to True
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (in all three directions) will be saved as an
+ 'ImageData'.
+ * A rectilinear (in all three directions), non-regular grid
+ will be saved as a 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
binary : bool
- if True the output .vtu file will be binary, default is
- False.
-
+ if True the output file will be binary, default is False
"""
# setup output folder
@@ -1185,7 +1140,8 @@ def export_heads(model, hdsfile, otfolder, nanval=-1e+20, kstpkper=None,
kstplist = list(set([x[0] for x in hds.get_kstpkper() if x[0] > -1]))
# set upt the vtk
- vtk = Vtk(model, smooth=smooth, point_scalars=point_scalars, nanval=nanval)
+ vtk = Vtk(model, smooth=smooth, point_scalars=point_scalars, nanval=nanval,
+ vtk_grid_type=vtk_grid_type, binary=binary)
# output data
count = 0
@@ -1193,14 +1149,11 @@ def export_heads(model, hdsfile, otfolder, nanval=-1e+20, kstpkper=None,
for kstp in kstplist:
hdarr = hds.get_data((kstp, kper))
vtk.add_array('head', hdarr)
- ot_base = '{}_Heads_KPER{}_KSTP{}.vtu'.format(
+ ot_base = '{}_Heads_KPER{}_KSTP{}'.format(
model.name, kper + 1, kstp + 1)
otfile = os.path.join(otfolder, ot_base)
# vtk.write(otfile, timeval=totim_dict[(kstp, kper)])
- if binary:
- vtk.write_binary(otfile)
- else:
- vtk.write(otfile)
+ vtk.write(otfile)
pvdfile.write("""\n""".format(count, ot_base))
count += 1
@@ -1213,10 +1166,8 @@ def export_heads(model, hdsfile, otfolder, nanval=-1e+20, kstpkper=None,
def export_array(model, array, output_folder, name, nanval=-1e+20,
array2d=False, smooth=False, point_scalars=False,
- binary=False):
-
+ vtk_grid_type='auto', binary=False):
"""
-
Export array to vtk
Parameters
@@ -1235,34 +1186,39 @@ def export_array(model, array, output_folder, name, nanval=-1e+20,
array2d : bool
True if array is 2d, default is False
smooth : bool
- If true a smooth surface will be output, default is False
+ if True, will create smooth layer elevations, default is False
point_scalars : bool
- If True point scalar values will be written, default is False
+ if True, will also output array values at cell vertices, default is
+ False; note this automatically sets smooth to True
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (in all three directions) will be saved as an
+ 'ImageData'.
+ * A rectilinear (in all three directions), non-regular grid
+ will be saved as a 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
binary : bool
- if True the output .vtu file will be binary, default is
- False.
-
+ if True the output file will be binary, default is False
"""
if not os.path.exists(output_folder):
os.mkdir(output_folder)
- vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars)
+ vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars,
+ vtk_grid_type=vtk_grid_type, binary=binary)
vtk.add_array(name, array, array2d=array2d)
- otfile = os.path.join(output_folder, '{}.vtu'.format(name))
- if binary:
- vtk.write_binary(otfile)
- else:
- vtk.write(otfile)
+ otfile = os.path.join(output_folder, '{}'.format(name))
+ vtk.write(otfile)
return
def export_transient(model, array, output_folder, name, nanval=-1e+20,
array2d=False, smooth=False, point_scalars=False,
- binary=False):
+ vtk_grid_type='auto', binary=False):
"""
-
Export transient 2d array to vtk
Parameters
@@ -1281,13 +1237,21 @@ def export_transient(model, array, output_folder, name, nanval=-1e+20,
array2d : bool
True if array is 2d, default is False
smooth : bool
- If true a smooth surface will be output, default is False
+ if True, will create smooth layer elevations, default is False
point_scalars : bool
- If True point scalar values will be written, default is False
+ if True, will also output array values at cell vertices, default is
+ False; note this automatically sets smooth to True
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (in all three directions) will be saved as an
+ 'ImageData'.
+ * A rectilinear (in all three directions), non-regular grid
+ will be saved as a 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
binary : bool
- if True the output .vtu file will be binary, default is
- False.
-
+ if True the output file will be binary, default is False
"""
if not os.path.exists(output_folder):
@@ -1295,10 +1259,15 @@ def export_transient(model, array, output_folder, name, nanval=-1e+20,
to_tim = model.dis.get_totim()
- vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars)
+ vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars,
+ vtk_grid_type=vtk_grid_type, binary=binary)
- if array2d:
+ if name.endswith('_'):
+ separator = ''
+ else:
+ separator = '_'
+ if array2d:
for kper in range(array.shape[0]):
t2d_array_kper = array[kper]
@@ -1308,21 +1277,17 @@ def export_transient(model, array, output_folder, name, nanval=-1e+20,
vtk.add_array(name, t2d_array_input, array2d=True)
- ot_name = '{}_0{}'.format(name, kper + 1)
- ot_file = os.path.join(output_folder, '{}.vtu'.format(ot_name))
- vtk.write(ot_file, timeval=to_tim[kper])
+ otname = '{}'.format(name) + separator + '0{}'.format(kper + 1)
+ otfile = os.path.join(output_folder, '{}'.format(otname))
+ vtk.write(otfile, timeval=to_tim[kper])
else:
-
for kper in range(array.shape[0]):
vtk.add_array(name, array[kper])
- ot_name = '{}_0{}'.format(name, kper + 1)
- ot_file = os.path.join(output_folder, '{}.vtu'.format(ot_name))
- if binary:
- vtk.write_binary(ot_file)
- else:
- vtk.write(ot_file, timeval=to_tim[kper])
+ otname = '{}'.format(name) + separator + '0{}'.format(kper + 1)
+ otfile = os.path.join(output_folder, '{}'.format(otname))
+ vtk.write(otfile, timeval=to_tim[kper])
return
@@ -1340,10 +1305,9 @@ def trans_dict(in_dict, name, trans_array, array2d=False):
return in_dict
-def export_package(pak_model, pak_name, ot_folder, vtkobj=None,
+def export_package(pak_model, pak_name, otfolder, vtkobj=None,
nanval=-1e+20, smooth=False, point_scalars=False,
- binary=False):
-
+ vtk_grid_type='auto', binary=False):
"""
Exports package to vtk
@@ -1354,7 +1318,7 @@ def export_package(pak_model, pak_name, ot_folder, vtkobj=None,
the model of the package
pak_name : str
the name of the package
- ot_folder : str
+ otfolder : str
output folder to write the data
vtkobj : VTK instance
a vtk object (allows export_package to be called from
@@ -1362,12 +1326,21 @@ def export_package(pak_model, pak_name, ot_folder, vtkobj=None,
nanval : scalar
no data value, default value is -1e20
smooth : bool
- If true a smooth surface will be output, default is False
+ if True, will create smooth layer elevations, default is False
point_scalars : bool
- If True point scalar values will be written, default is False
+ if True, will also output array values at cell vertices, default is
+ False; note this automatically sets smooth to True
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (in all three directions) will be saved as an
+ 'ImageData'.
+ * A rectilinear (in all three directions), non-regular grid
+ will be saved as a 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
binary : bool
- if True the output .vtu file will be binary, default is
- False.
+ if True the output file will be binary, default is False
"""
@@ -1375,13 +1348,14 @@ def export_package(pak_model, pak_name, ot_folder, vtkobj=None,
if not vtkobj:
# if not build one
vtk = Vtk(pak_model, nanval=nanval, smooth=smooth,
- point_scalars=point_scalars)
+ point_scalars=point_scalars, vtk_grid_type=vtk_grid_type,
+ binary=binary)
else:
# otherwise use the vtk object that was supplied
vtk = vtkobj
- if not os.path.exists(ot_folder):
- os.mkdir(ot_folder)
+ if not os.path.exists(otfolder):
+ os.mkdir(otfolder)
# is there output data
has_output = False
@@ -1478,11 +1452,8 @@ def export_package(pak_model, pak_name, ot_folder, vtkobj=None,
# write out data
# write array data
if len(vtk.arrays) > 0:
- ot_file = os.path.join(ot_folder, '{}.vtu'.format(pak_name))
- if binary:
- vtk.write_binary(ot_file)
- else:
- vtk.write(ot_file)
+ otfile = os.path.join(otfolder, '{}'.format(pak_name))
+ vtk.write(otfile)
# write transient data
if vtk_trans_dict:
@@ -1497,7 +1468,7 @@ def export_package(pak_model, pak_name, ot_folder, vtkobj=None,
# else:
# time = None
# set up output file
- ot_file = os.path.join(ot_folder, '{} _0{}.vtu'.format(
+ otfile = os.path.join(otfolder, '{}_0{}'.format(
pak_name, kper + 1))
for name, array in sorted(array_dict.items()):
if array.array2d:
@@ -1506,17 +1477,19 @@ def export_package(pak_model, pak_name, ot_folder, vtkobj=None,
else:
a = array.array
vtk.add_array(name, a, array.array2d)
- # vtk.write(ot_file, timeval=time)
- if binary:
- vtk.write_binary(ot_file)
- else:
- vtk.write(ot_file)
+ # vtk.write(otfile, timeval=time)
+ vtk.write(otfile)
return
-def export_model(model, ot_folder, package_names=None, nanval=-1e+20,
- smooth=False, point_scalars=False, binary=False):
+def export_model(model, otfolder, package_names=None, nanval=-1e+20,
+ smooth=False, point_scalars=False, vtk_grid_type='auto',
+ binary=False):
"""
+ Exports model to vtk
+
+ Parameters
+ ----------
model : flopy model instance
flopy model
@@ -1529,15 +1502,24 @@ def export_model(model, ot_folder, package_names=None, nanval=-1e+20,
array2d : bool
True if array is 2d, default is False
smooth : bool
- If true a smooth surface will be output, default is False
+ if True, will create smooth layer elevations, default is False
point_scalars : bool
- If True point scalar values will be written, default is False
+ if True, will also output array values at cell vertices, default is
+ False; note this automatically sets smooth to True
+ vtk_grid_type : str
+ Specific vtk_grid_type or 'auto'. Possible specific values are
+ 'ImageData', 'RectilinearGrid', and 'UnstructuredGrid'.
+ If 'auto', the grid type is automatically determined. Namely:
+ * A regular grid (in all three directions) will be saved as an
+ 'ImageData'.
+ * A rectilinear (in all three directions), non-regular grid
+ will be saved as a 'RectilinearGrid'.
+ * Other grids will be saved as 'UnstructuredGrid'.
binary : bool
- if True the output .vtu file will be binary, default is
- False.
-
+ if True the output file will be binary, default is False
"""
- vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars)
+ vtk = Vtk(model, nanval=nanval, smooth=smooth, point_scalars=point_scalars,
+ vtk_grid_type=vtk_grid_type, binary=binary)
if package_names is not None:
if not isinstance(package_names, list):
@@ -1545,10 +1527,10 @@ def export_model(model, ot_folder, package_names=None, nanval=-1e+20,
else:
package_names = [pak.name[0] for pak in model.packagelist]
- if not os.path.exists(ot_folder):
- os.mkdir(ot_folder)
+ if not os.path.exists(otfolder):
+ os.mkdir(otfolder)
for pak_name in package_names:
- export_package(model, pak_name, ot_folder, vtkobj=vtk, nanval=nanval,
+ export_package(model, pak_name, otfolder, vtkobj=vtk, nanval=nanval,
smooth=smooth, point_scalars=point_scalars,
- binary=binary)
+ vtk_grid_type=vtk_grid_type, binary=binary)