0
# Data Export Capabilities
1
2
This module provides comprehensive export functionality for model grids, arrays, and results to various formats including NetCDF, VTK, shapefiles, and other GIS-compatible formats. These tools enable interoperability with other modeling software, GIS systems, and visualization platforms.
3
4
## NetCDF Export
5
6
### NetCdf
7
8
Primary class for exporting MODFLOW models and results to NetCDF format.
9
10
```python { .api }
11
class NetCdf:
12
"""NetCDF export functionality for MODFLOW models"""
13
def __init__(
14
self,
15
output_filename: str,
16
model: object,
17
array_dict: dict = None,
18
meshtype: str = None,
19
**kwargs
20
): ...
21
22
def write(self) -> None:
23
"""Write model and data to NetCDF file"""
24
...
25
26
def add_model(self, model: object) -> None:
27
"""Add model to NetCDF file"""
28
...
29
30
def add_package(
31
self,
32
package: object,
33
text: str = None,
34
**kwargs
35
) -> None:
36
"""Add package data to NetCDF file"""
37
...
38
39
def add_transient_array(
40
self,
41
array: np.ndarray,
42
name: str,
43
units: str = None,
44
**kwargs
45
) -> None:
46
"""Add time-varying array data"""
47
...
48
49
def add_array(
50
self,
51
array: np.ndarray,
52
name: str,
53
units: str = None,
54
**kwargs
55
) -> None:
56
"""Add array data to NetCDF file"""
57
...
58
59
def add_grid(
60
self,
61
grid: object,
62
**kwargs
63
) -> None:
64
"""Add grid information to NetCDF file"""
65
...
66
67
def add_coordinate_system(
68
self,
69
epsg: int = None,
70
proj4_str: str = None,
71
**kwargs
72
) -> None:
73
"""Add coordinate reference system"""
74
...
75
76
@property
77
def nc(self) -> object:
78
"""NetCDF4 Dataset object"""
79
...
80
81
@property
82
def logger(self) -> object:
83
"""Export logger"""
84
...
85
```
86
87
### Logger
88
89
Logging functionality for export operations.
90
91
```python { .api }
92
class Logger:
93
"""Logging for export operations"""
94
def __init__(
95
self,
96
level: str = 'INFO',
97
filename: str = None,
98
**kwargs
99
): ...
100
101
def info(self, message: str) -> None:
102
"""Log info message"""
103
...
104
105
def warning(self, message: str) -> None:
106
"""Log warning message"""
107
...
108
109
def error(self, message: str) -> None:
110
"""Log error message"""
111
...
112
113
def debug(self, message: str) -> None:
114
"""Log debug message"""
115
...
116
```
117
118
## VTK Export
119
120
### Vtk
121
122
VTK format export for 3D visualization and analysis.
123
124
```python { .api }
125
class Vtk:
126
"""VTK format export for MODFLOW models"""
127
def __init__(
128
self,
129
model: object = None,
130
modelgrid: object = None,
131
vertical_exageration: float = 1.0,
132
binary: bool = True,
133
smooth: bool = False,
134
point_scalars: bool = False,
135
fmt: str = None,
136
**kwargs
137
): ...
138
139
def add_model(self, model: object) -> None:
140
"""Add model to VTK export"""
141
...
142
143
def add_array(
144
self,
145
array: np.ndarray,
146
name: str,
147
**kwargs
148
) -> None:
149
"""Add array data for export"""
150
...
151
152
def add_transient_array(
153
self,
154
d: dict,
155
name: str,
156
**kwargs
157
) -> None:
158
"""Add time-varying array data"""
159
...
160
161
def add_vector(
162
self,
163
vectors: tuple[np.ndarray, np.ndarray, np.ndarray],
164
name: str,
165
**kwargs
166
) -> None:
167
"""Add vector field data"""
168
...
169
170
def add_pathline_points(
171
self,
172
pathlines: list,
173
**kwargs
174
) -> None:
175
"""Add MODPATH pathline data"""
176
...
177
178
def add_endpoint_points(
179
self,
180
endpoints: np.ndarray,
181
**kwargs
182
) -> None:
183
"""Add MODPATH endpoint data"""
184
...
185
186
def write(
187
self,
188
filename: str,
189
**kwargs
190
) -> None:
191
"""Write VTK file"""
192
...
193
194
@property
195
def arrays(self) -> dict:
196
"""Dictionary of arrays for export"""
197
...
198
```
199
200
### Pvd
201
202
ParaView data file management for time series VTK files.
203
204
```python { .api }
205
class Pvd:
206
"""ParaView data file management"""
207
def __init__(
208
self,
209
filename: str,
210
**kwargs
211
): ...
212
213
def add_dataset(
214
self,
215
filename: str,
216
timestep: float,
217
**kwargs
218
) -> None:
219
"""Add VTK dataset to time series"""
220
...
221
222
def write(self) -> None:
223
"""Write PVD file"""
224
...
225
```
226
227
## Shapefile Export
228
229
### Shapefile Utilities
230
231
Functions for exporting model data to ESRI shapefile format.
232
233
```python { .api }
234
def write_grid_shapefile(
235
filename: str,
236
mg: object,
237
array_dict: dict = None,
238
**kwargs
239
) -> None:
240
"""Export model grid to shapefile"""
241
...
242
243
def write_shapefile(
244
filename: str,
245
geoms: list,
246
attribute_dict: dict = None,
247
**kwargs
248
) -> None:
249
"""Write geometries and attributes to shapefile"""
250
...
251
252
def model_attributes_to_shapefile(
253
filename: str,
254
ml: object,
255
package_names: list = None,
256
array_dict: dict = None,
257
**kwargs
258
) -> None:
259
"""Export model attributes to shapefile"""
260
...
261
262
def package_export_shapefile(
263
pak: object,
264
filename: str,
265
**kwargs
266
) -> None:
267
"""Export package data to shapefile"""
268
...
269
270
def boundary_condition_export(
271
filename: str,
272
pak: object,
273
kper: int = 0,
274
**kwargs
275
) -> None:
276
"""Export boundary condition data to shapefile"""
277
...
278
```
279
280
## Metadata Standards
281
282
### acdd
283
284
Attribute Convention for Data Discovery (ACDD) metadata standards.
285
286
```python { .api }
287
class acdd:
288
"""ACDD metadata standards for export files"""
289
290
@staticmethod
291
def get_standard_attributes() -> dict:
292
"""Get standard ACDD attributes"""
293
...
294
295
@staticmethod
296
def create_attributes(
297
title: str,
298
summary: str,
299
institution: str = None,
300
source: str = None,
301
**kwargs
302
) -> dict:
303
"""Create ACDD-compliant attribute dictionary"""
304
...
305
306
@staticmethod
307
def add_global_attributes(
308
nc_file: object,
309
attributes: dict,
310
**kwargs
311
) -> None:
312
"""Add global attributes to NetCDF file"""
313
...
314
```
315
316
## High-Level Export Functions
317
318
```python { .api }
319
def model_export(
320
filename: str,
321
model: object,
322
fmt: str = 'netcdf',
323
**kwargs
324
) -> None:
325
"""Export complete model to specified format"""
326
...
327
328
def package_export(
329
filename: str,
330
package: object,
331
fmt: str = 'netcdf',
332
**kwargs
333
) -> None:
334
"""Export individual package to specified format"""
335
...
336
337
def array2d_export(
338
filename: str,
339
array: np.ndarray,
340
modelgrid: object,
341
**kwargs
342
) -> None:
343
"""Export 2D array with grid information"""
344
...
345
346
def array3d_export(
347
filename: str,
348
array: np.ndarray,
349
modelgrid: object,
350
**kwargs
351
) -> None:
352
"""Export 3D array with grid information"""
353
...
354
355
def export_array(
356
filename: str,
357
array: np.ndarray,
358
fmt: str = 'netcdf',
359
**kwargs
360
) -> None:
361
"""Generic array export function"""
362
...
363
364
def export_contours(
365
filename: str,
366
array: np.ndarray,
367
levels: list = None,
368
modelgrid: object = None,
369
**kwargs
370
) -> None:
371
"""Export contour data to shapefile"""
372
...
373
```
374
375
## Usage Examples
376
377
### Basic NetCDF Export
378
379
```python
380
import flopy
381
import flopy.export as fpe
382
import numpy as np
383
384
# Load or create MODFLOW model
385
mf = flopy.modflow.Modflow.load('model.nam')
386
387
# Basic NetCDF export
388
nc_file = fpe.NetCdf('model_export.nc', mf)
389
390
# Add model grid and packages
391
nc_file.add_model(mf)
392
393
# Add arrays from packages
394
if hasattr(mf, 'lpf'):
395
nc_file.add_array(mf.lpf.hk.array, 'hydraulic_conductivity', units='m/day')
396
nc_file.add_array(mf.lpf.sy.array, 'specific_yield', units='dimensionless')
397
398
if hasattr(mf, 'dis'):
399
nc_file.add_array(mf.dis.top.array, 'top_elevation', units='m')
400
nc_file.add_array(mf.dis.botm.array, 'bottom_elevation', units='m')
401
402
# Add coordinate system information
403
nc_file.add_coordinate_system(epsg=32633) # UTM Zone 33N
404
405
# Write the NetCDF file
406
nc_file.write()
407
408
print("NetCDF export completed: model_export.nc")
409
```
410
411
### Advanced NetCDF Export with Results
412
413
```python
414
import flopy
415
import flopy.export as fpe
416
import flopy.utils as fpu
417
import numpy as np
418
419
# Load model and results
420
mf = flopy.modflow.Modflow.load('model.nam')
421
422
# Read head and budget files
423
hds = fpu.HeadFile('model.hds')
424
cbb = fpu.CellBudgetFile('model.cbb')
425
426
# Create NetCDF export with metadata
427
nc_file = fpe.NetCdf(
428
'complete_model_export.nc',
429
mf,
430
array_dict=None,
431
meshtype='structured'
432
)
433
434
# Add ACDD metadata
435
metadata = fpe.acdd.create_attributes(
436
title='Regional Groundwater Flow Model',
437
summary='Three-dimensional groundwater flow model for water resource assessment',
438
institution='University Research Center',
439
source='MODFLOW-2005',
440
creator_name='Jane Doe',
441
creator_email='jane.doe@university.edu',
442
project='Regional Water Study',
443
geospatial_bounds='POLYGON((...))'
444
)
445
446
fpe.acdd.add_global_attributes(nc_file.nc, metadata)
447
448
# Add model structure
449
nc_file.add_model(mf)
450
451
# Add static arrays
452
array_dict = {
453
'hydraulic_conductivity': (mf.lpf.hk.array, 'm/day'),
454
'specific_yield': (mf.lpf.sy.array, 'dimensionless'),
455
'specific_storage': (mf.lpf.ss.array, '1/m'),
456
'top_elevation': (mf.dis.top.array, 'm'),
457
'bottom_elevation': (mf.dis.botm.array, 'm'),
458
'porosity': (np.ones(mf.dis.botm.array.shape) * 0.25, 'dimensionless')
459
}
460
461
for name, (array, units) in array_dict.items():
462
nc_file.add_array(array, name, units=units)
463
464
# Add transient results
465
# Heads for all time steps
466
head_dict = {}
467
times = hds.get_times()
468
kstpkper_list = hds.get_kstpkper()
469
470
for i, (time, kstpkper) in enumerate(zip(times, kstpkper_list)):
471
head = hds.get_data(kstpkper=kstpkper)
472
head_dict[time] = head
473
474
nc_file.add_transient_array(head_dict, 'head', units='m')
475
476
# Add budget components
477
budget_components = ['STORAGE', 'CONSTANT HEAD', 'WELLS', 'RECHARGE']
478
for comp in budget_components:
479
try:
480
budget_dict = {}
481
for i, (time, kstpkper) in enumerate(zip(times, kstpkper_list)):
482
budget_data = cbb.get_data(text=comp, kstpkper=kstpkper)
483
if budget_data is not None:
484
budget_dict[time] = budget_data[0]
485
486
if budget_dict:
487
nc_file.add_transient_array(
488
budget_dict,
489
f'budget_{comp.lower().replace(" ", "_")}',
490
units='m3/day'
491
)
492
except:
493
print(f"Could not export {comp} budget data")
494
495
# Add coordinate system and finish
496
nc_file.add_coordinate_system(epsg=4326) # WGS84
497
nc_file.write()
498
499
print("Complete NetCDF export finished")
500
501
# Close files
502
hds.close()
503
cbb.close()
504
```
505
506
### VTK Export for 3D Visualization
507
508
```python
509
import flopy
510
import flopy.export as fpe
511
import flopy.utils as fpu
512
import numpy as np
513
514
# Load model
515
mf = flopy.modflow.Modflow.load('model.nam')
516
517
# Create VTK export object
518
vtk_file = fpe.Vtk(
519
model=mf,
520
vertical_exageration=10.0, # Exaggerate vertical for better visualization
521
binary=True, # Binary format for smaller files
522
smooth=True # Smooth surfaces
523
)
524
525
# Add model structure
526
vtk_file.add_model(mf)
527
528
# Add hydraulic conductivity
529
if hasattr(mf, 'lpf'):
530
vtk_file.add_array(mf.lpf.hk.array, 'K_horizontal')
531
vtk_file.add_array(mf.lpf.vka.array, 'K_vertical')
532
533
# Add head results
534
try:
535
hds = fpu.HeadFile('model.hds')
536
537
# Add steady-state heads
538
head_ss = hds.get_data(kstpkper=(0, 0))
539
vtk_file.add_array(head_ss, 'head_steady_state')
540
541
# Add transient heads (multiple time steps)
542
head_transient = {}
543
times = hds.get_times()
544
kstpkper_list = hds.get_kstpkper()
545
546
for time, kstpkper in zip(times, kstpkper_list):
547
head = hds.get_data(kstpkper=kstpkper)
548
head_transient[time] = head
549
550
vtk_file.add_transient_array(head_transient, 'head_transient')
551
552
hds.close()
553
554
except FileNotFoundError:
555
print("Head file not found")
556
557
# Add velocity vectors
558
try:
559
cbb = fpu.CellBudgetFile('model.cbb')
560
561
# Get face flows
562
frf = cbb.get_data(text='FLOW RIGHT FACE')[0]
563
fff = cbb.get_data(text='FLOW FRONT FACE')[0]
564
flf = cbb.get_data(text='FLOW LOWER FACE')[0]
565
566
# Convert to cell-centered velocities (simplified)
567
# Proper conversion would account for cell dimensions and porosity
568
qx = np.zeros_like(frf)
569
qy = np.zeros_like(fff)
570
qz = np.zeros_like(flf)
571
572
# Simple averaging (not rigorous)
573
qx[:, :, :-1] = frf[:, :, :-1]
574
qy[:, :-1, :] = fff[:, :-1, :]
575
qz[:-1, :, :] = flf[:-1, :, :]
576
577
vtk_file.add_vector((qx, qy, qz), 'velocity_vectors')
578
579
cbb.close()
580
581
except FileNotFoundError:
582
print("Budget file not found")
583
584
# Add MODPATH results if available
585
try:
586
# Pathlines
587
pth_file = fpu.PathlineFile('model.mppth')
588
pathlines = pth_file.get_alldata()
589
vtk_file.add_pathline_points(pathlines[:100]) # First 100 pathlines
590
591
# Endpoints
592
ep_file = fpu.EndpointFile('model.mpend')
593
endpoints = ep_file.get_alldata()
594
vtk_file.add_endpoint_points(endpoints)
595
596
except FileNotFoundError:
597
print("MODPATH files not found")
598
599
# Write VTK file
600
vtk_file.write('model_3d.vtu')
601
602
print("VTK export completed: model_3d.vtu")
603
604
# For time series, create PVD file
605
pvd_file = fpe.Pvd('model_timeseries.pvd')
606
607
for i, time in enumerate(times[:10]): # First 10 time steps
608
# Create individual VTK files for each time step
609
vtk_time = fpe.Vtk(model=mf)
610
vtk_time.add_model(mf)
611
612
# Add head for this time step
613
head = hds.get_data(idx=i)
614
vtk_time.add_array(head, f'head_t{i}')
615
616
filename = f'model_t{i:03d}.vtu'
617
vtk_time.write(filename)
618
619
# Add to PVD file
620
pvd_file.add_dataset(filename, time)
621
622
# Write PVD file
623
pvd_file.write()
624
625
print("Time series VTK export completed")
626
```
627
628
### Shapefile Export for GIS Integration
629
630
```python
631
import flopy
632
import flopy.export as fpe
633
import flopy.utils as fpu
634
import numpy as np
635
636
# Load model
637
mf = flopy.modflow.Modflow.load('model.nam')
638
639
# Export model grid to shapefile
640
grid_dict = {
641
'layer': np.repeat(range(mf.dis.nlay), mf.dis.nrow * mf.dis.ncol),
642
'row': np.tile(np.repeat(range(mf.dis.nrow), mf.dis.ncol), mf.dis.nlay),
643
'column': np.tile(range(mf.dis.ncol), mf.dis.nlay * mf.dis.nrow)
644
}
645
646
# Add hydraulic properties
647
if hasattr(mf, 'lpf'):
648
grid_dict['k_horizontal'] = mf.lpf.hk.array.ravel()
649
grid_dict['k_vertical'] = mf.lpf.vka.array.ravel()
650
grid_dict['specific_yield'] = mf.lpf.sy.array.ravel()
651
652
# Add elevations
653
grid_dict['top_elev'] = np.repeat(mf.dis.top.array.ravel(), mf.dis.nlay)
654
botm_3d = np.broadcast_to(mf.dis.botm.array, (mf.dis.nlay, mf.dis.nrow, mf.dis.ncol))
655
grid_dict['bot_elev'] = botm_3d.ravel()
656
657
# Export grid with attributes
658
fpe.write_grid_shapefile('model_grid.shp', mf.modelgrid, array_dict=grid_dict)
659
660
print("Grid shapefile exported: model_grid.shp")
661
662
# Export head results
663
try:
664
hds = fpu.HeadFile('model.hds')
665
666
# Final heads
667
head_final = hds.get_data(kstpkper=(-1, -1))
668
669
head_dict = {
670
'head_final': head_final.ravel(),
671
'layer': grid_dict['layer'],
672
'row': grid_dict['row'],
673
'column': grid_dict['column']
674
}
675
676
fpe.write_grid_shapefile('model_heads.shp', mf.modelgrid, array_dict=head_dict)
677
678
hds.close()
679
680
except FileNotFoundError:
681
print("Head file not found")
682
683
# Export boundary conditions
684
bc_packages = ['WEL', 'RIV', 'GHB', 'DRN', 'CHD']
685
686
for bc_name in bc_packages:
687
try:
688
package = mf.get_package(bc_name)
689
if package is not None:
690
fpe.package_export_shapefile(package, f'{bc_name.lower()}_bc.shp')
691
print(f"Exported {bc_name} package to shapefile")
692
except:
693
print(f"Could not export {bc_name} package")
694
695
# Export well data with detailed attributes
696
if hasattr(mf, 'wel'):
697
wel_package = mf.wel
698
699
# Get well data for stress period 0
700
wel_data = wel_package.stress_period_data[0]
701
702
# Create well points with attributes
703
well_geoms = []
704
well_attrs = {
705
'well_id': [],
706
'layer': [],
707
'row': [],
708
'column': [],
709
'pump_rate': [],
710
'x_coord': [],
711
'y_coord': []
712
}
713
714
for i, well in enumerate(wel_data):
715
lay, row, col, rate = well[0], well[1], well[2], well[3]
716
717
# Get coordinates from model grid
718
x, y = mf.modelgrid.get_coords(row, col)
719
720
# Create point geometry (simplified - would use shapely in practice)
721
well_geoms.append((x, y))
722
723
well_attrs['well_id'].append(f'WELL_{i+1:03d}')
724
well_attrs['layer'].append(lay + 1) # 1-based indexing
725
well_attrs['row'].append(row + 1)
726
well_attrs['column'].append(col + 1)
727
well_attrs['pump_rate'].append(rate)
728
well_attrs['x_coord'].append(x)
729
well_attrs['y_coord'].append(y)
730
731
# Export wells (would need actual shapefile writing function)
732
# fpe.write_shapefile('wells.shp', well_geoms, well_attrs)
733
734
print(f"Found {len(wel_data)} wells for export")
735
736
# Export contours
737
try:
738
hds = fpu.HeadFile('model.hds')
739
head = hds.get_data(kstpkper=(0, 0))
740
741
# Define contour levels
742
levels = np.linspace(head.min(), head.max(), 20)
743
744
fpe.export_contours(
745
'head_contours.shp',
746
head[0, :, :], # Top layer only
747
levels=levels,
748
modelgrid=mf.modelgrid
749
)
750
751
print("Head contours exported")
752
753
hds.close()
754
755
except FileNotFoundError:
756
print("Head file not found for contour export")
757
```
758
759
### Multi-Format Export Workflow
760
761
```python
762
import flopy
763
import flopy.export as fpe
764
import flopy.utils as fpu
765
import os
766
767
def export_model_complete(model_name: str, export_formats: list = None):
768
"""Complete model export to multiple formats"""
769
770
if export_formats is None:
771
export_formats = ['netcdf', 'vtk', 'shapefile']
772
773
# Load model
774
mf = flopy.modflow.Modflow.load(f'{model_name}.nam')
775
776
# Create export directory
777
export_dir = f'{model_name}_export'
778
os.makedirs(export_dir, exist_ok=True)
779
780
print(f"Exporting model {model_name} to formats: {export_formats}")
781
782
# NetCDF export
783
if 'netcdf' in export_formats:
784
print("Exporting to NetCDF...")
785
786
nc_file = fpe.NetCdf(
787
os.path.join(export_dir, f'{model_name}.nc'),
788
mf
789
)
790
791
# Add comprehensive metadata
792
metadata = {
793
'title': f'MODFLOW Model: {model_name}',
794
'summary': 'Groundwater flow model with complete package and result data',
795
'source': 'MODFLOW-2005',
796
'Conventions': 'CF-1.6, ACDD-1.3',
797
'date_created': '2024-01-01',
798
'geospatial_bounds_crs': 'EPSG:4326'
799
}
800
801
fpe.acdd.add_global_attributes(nc_file.nc, metadata)
802
803
nc_file.add_model(mf)
804
805
# Add results if available
806
try:
807
hds = fpu.HeadFile(f'{model_name}.hds')
808
head_dict = {}
809
for i, time in enumerate(hds.get_times()):
810
head = hds.get_data(idx=i)
811
head_dict[time] = head
812
nc_file.add_transient_array(head_dict, 'head', units='m')
813
hds.close()
814
except:
815
pass
816
817
nc_file.write()
818
print(f" NetCDF export complete: {model_name}.nc")
819
820
# VTK export
821
if 'vtk' in export_formats:
822
print("Exporting to VTK...")
823
824
vtk_file = fpe.Vtk(model=mf, binary=True)
825
vtk_file.add_model(mf)
826
827
# Add results
828
try:
829
hds = fpu.HeadFile(f'{model_name}.hds')
830
head = hds.get_data(kstpkper=(0, 0))
831
vtk_file.add_array(head, 'head')
832
hds.close()
833
except:
834
pass
835
836
vtk_output = os.path.join(export_dir, f'{model_name}.vtu')
837
vtk_file.write(vtk_output)
838
print(f" VTK export complete: {model_name}.vtu")
839
840
# Shapefile export
841
if 'shapefile' in export_formats:
842
print("Exporting to Shapefiles...")
843
844
# Grid with attributes
845
grid_dict = {
846
'layer': np.repeat(range(mf.dis.nlay), mf.dis.nrow * mf.dis.ncol),
847
'k_horiz': mf.lpf.hk.array.ravel() if hasattr(mf, 'lpf') else None,
848
'top_elev': np.repeat(mf.dis.top.array.ravel(), mf.dis.nlay)
849
}
850
851
# Filter out None values
852
grid_dict = {k: v for k, v in grid_dict.items() if v is not None}
853
854
grid_output = os.path.join(export_dir, f'{model_name}_grid.shp')
855
fpe.write_grid_shapefile(grid_output, mf.modelgrid, array_dict=grid_dict)
856
857
# Boundary conditions
858
bc_packages = ['WEL', 'RIV', 'GHB', 'DRN']
859
for bc_name in bc_packages:
860
try:
861
package = mf.get_package(bc_name)
862
if package is not None:
863
bc_output = os.path.join(export_dir, f'{model_name}_{bc_name.lower()}.shp')
864
fpe.package_export_shapefile(package, bc_output)
865
except:
866
continue
867
868
print(f" Shapefile export complete in directory: {export_dir}")
869
870
print(f"Model export completed. Files saved in: {export_dir}")
871
872
# Example usage
873
export_model_complete('regional_model', ['netcdf', 'vtk', 'shapefile'])
874
```
875
876
### Custom Export Functions
877
878
```python
879
import flopy
880
import flopy.export as fpe
881
import numpy as np
882
import json
883
884
def export_model_summary_json(model: object, filename: str):
885
"""Export model summary information to JSON"""
886
887
summary = {
888
'model_info': {
889
'name': model.name,
890
'version': model.version,
891
'workspace': model.model_ws,
892
'executable': model.exe_name
893
},
894
'discretization': {
895
'nlay': model.dis.nlay,
896
'nrow': model.dis.nrow,
897
'ncol': model.dis.ncol,
898
'nper': model.dis.nper,
899
'total_cells': model.dis.nlay * model.dis.nrow * model.dis.ncol
900
},
901
'packages': [pak.name[0] for pak in model.packagelist],
902
'grid_info': {
903
'delr_min': float(np.min(model.dis.delr.array)),
904
'delr_max': float(np.max(model.dis.delr.array)),
905
'delc_min': float(np.min(model.dis.delc.array)),
906
'delc_max': float(np.max(model.dis.delc.array)),
907
'extent': model.modelgrid.extent
908
}
909
}
910
911
# Add package-specific information
912
if hasattr(model, 'lpf'):
913
summary['hydraulic_properties'] = {
914
'k_horizontal_range': [float(np.min(model.lpf.hk.array)),
915
float(np.max(model.lpf.hk.array))],
916
'porosity_range': [float(np.min(model.lpf.sy.array)),
917
float(np.max(model.lpf.sy.array))]
918
}
919
920
if hasattr(model, 'wel'):
921
wel_data = model.wel.stress_period_data[0]
922
summary['wells'] = {
923
'count': len(wel_data),
924
'total_pumping': float(np.sum([w[3] for w in wel_data if w[3] < 0])),
925
'total_injection': float(np.sum([w[3] for w in wel_data if w[3] > 0]))
926
}
927
928
# Write JSON file
929
with open(filename, 'w') as f:
930
json.dump(summary, f, indent=2)
931
932
print(f"Model summary exported to: {filename}")
933
934
def export_budget_csv(cbb_file: str, output_file: str):
935
"""Export budget components to CSV format"""
936
937
import pandas as pd
938
939
cbb = fpu.CellBudgetFile(cbb_file)
940
941
# Get all available records
942
records = cbb.list_unique_records()
943
times = cbb.get_times()
944
945
# Create DataFrame
946
budget_data = []
947
948
for time in times:
949
for record in records:
950
try:
951
data = cbb.get_data(text=record, totim=time)
952
if data is not None:
953
total_flow = np.sum(data[0])
954
budget_data.append({
955
'time': time,
956
'component': record,
957
'total_flow': total_flow
958
})
959
except:
960
continue
961
962
df = pd.DataFrame(budget_data)
963
df.to_csv(output_file, index=False)
964
965
cbb.close()
966
print(f"Budget data exported to: {output_file}")
967
968
# Example usage
969
mf = flopy.modflow.Modflow.load('model.nam')
970
export_model_summary_json(mf, 'model_summary.json')
971
export_budget_csv('model.cbb', 'budget_summary.csv')
972
```
973
974
## Common Types
975
976
```python { .api }
977
# Export format types
978
ExportFormat = Literal['netcdf', 'vtk', 'shapefile', 'csv', 'json']
979
FileFormat = Literal['binary', 'ascii']
980
CompressionLevel = int # 0-9 for compression
981
982
# Data types for export
983
ArrayData = np.ndarray
984
TransientData = dict[float, np.ndarray] # Time -> Array
985
VectorData = tuple[np.ndarray, np.ndarray, np.ndarray] # (vx, vy, vz)
986
987
# Geometry types
988
GeometryType = Literal['Point', 'LineString', 'Polygon']
989
ShapefileGeometry = list[tuple[float, ...]]
990
AttributeDict = dict[str, list]
991
992
# Metadata types
993
MetadataDict = dict[str, Union[str, int, float]]
994
ACDDAttributes = dict[str, str]
995
CoordinateSystem = Union[int, str] # EPSG code or proj4 string
996
997
# File and path types
998
FilePath = Union[str, os.PathLike]
999
OutputDirectory = str
1000
FileExtension = str
1001
1002
# VTK specific types
1003
VTKDataType = Literal['SCALARS', 'VECTORS', 'TENSORS']
1004
VTKFormat = Literal['ascii', 'binary']
1005
TimeStepData = dict[float, str] # Time -> filename mapping
1006
1007
# NetCDF specific types
1008
NCVariable = str
1009
NCDimension = str
1010
NCAttributes = dict[str, Union[str, int, float, list]]
1011
1012
# Shapefile specific types
1013
FieldType = Literal['C', 'N', 'F', 'L', 'D'] # Character, Numeric, Float, Logical, Date
1014
FieldDefinition = tuple[str, str, int, int] # (name, type, width, precision)
1015
```
1016
1017
This comprehensive documentation covers the complete data export API for FloPy including NetCDF, VTK, and shapefile export capabilities. The examples demonstrate basic to advanced export scenarios including complete model export workflows, multi-format exports, and custom export functions for various use cases.