0
# MODPATH Particle Tracking
1
2
This module provides comprehensive support for MODPATH 6 and 7 models for particle tracking analysis with flexible particle placement, endpoint analysis, and pathline tracking. MODPATH is used to simulate the movement of particles through groundwater flow fields computed by MODFLOW, enabling analysis of flow paths, travel times, and capture zones.
3
4
## Model Classes
5
6
### Modpath7
7
8
MODPATH version 7 model for advanced particle tracking capabilities.
9
10
```python { .api }
11
class Modpath7:
12
"""MODPATH 7 particle tracking model"""
13
def __init__(
14
self,
15
modelname: str = 'modpathtest',
16
flowmodel: object = None,
17
exe_name: str = 'mp7',
18
modflowmodel: object = None,
19
dis_file: str = None,
20
dis_unit: int = 87,
21
head_file: str = None,
22
budget_file: str = None,
23
model_ws: str = '.',
24
external_path: str = None,
25
verbose: bool = False,
26
load: bool = True,
27
listunit: int = 7,
28
**kwargs
29
): ...
30
31
def write_input(self) -> None:
32
"""Write MODPATH 7 input files"""
33
...
34
35
def run_model(
36
self,
37
silent: bool = False,
38
pause: bool = False,
39
report: bool = False,
40
normal_msg: str = 'normal termination'
41
) -> tuple[bool, list[str]]:
42
"""Run MODPATH 7 model and return success status and output"""
43
...
44
45
@classmethod
46
def create_mp7(
47
cls,
48
modelname: str,
49
trackdir: str = 'forward',
50
flowmodel: object = None,
51
exe_name: str = 'mp7',
52
model_ws: str = '.',
53
rowcelldivisions: int = 1,
54
columncelldivisions: int = 1,
55
layercelldivisions: int = 1,
56
**kwargs
57
) -> 'Modpath7':
58
"""Create basic MODPATH 7 model"""
59
...
60
61
def add_package(self, p: object) -> None:
62
"""Add package to model"""
63
...
64
65
def remove_package(self, pname: str) -> None:
66
"""Remove package from model"""
67
...
68
69
def get_package(self, name: str) -> object:
70
"""Get package by name"""
71
...
72
73
@property
74
def modelgrid(self) -> object:
75
"""Model grid object"""
76
...
77
```
78
79
### Modpath6
80
81
MODPATH version 6 model for legacy compatibility.
82
83
```python { .api }
84
class Modpath6:
85
"""MODPATH 6 particle tracking model"""
86
def __init__(
87
self,
88
modelname: str = 'modpathtest',
89
exe_name: str = 'mp6',
90
modflowmodel: object = None,
91
dis_file: str = None,
92
head_file: str = None,
93
budget_file: str = None,
94
model_ws: str = '.',
95
external_path: str = None,
96
verbose: bool = False,
97
load: bool = True,
98
**kwargs
99
): ...
100
101
def write_input(self) -> None:
102
"""Write MODPATH 6 input files"""
103
...
104
105
def run_model(
106
self,
107
silent: bool = False,
108
pause: bool = False,
109
report: bool = False
110
) -> tuple[bool, list[str]]:
111
"""Run MODPATH 6 model"""
112
...
113
```
114
115
## Package Classes
116
117
### Modpath7Bas
118
119
Basic package for MODPATH 7 that defines fundamental simulation parameters.
120
121
```python { .api }
122
class Modpath7Bas:
123
"""MODPATH 7 basic package"""
124
def __init__(
125
self,
126
model: Modpath7,
127
hnoflo: float = 1e30,
128
hdry: float = -1e30,
129
def_face_ct: int = 6,
130
bud_loc: int = 0,
131
bud_label: str = None,
132
def_iface: ArrayData = None,
133
laytyp: ArrayData = None,
134
ibound: ArrayData = None,
135
porosity: ArrayData = 0.1,
136
retfac: ArrayData = 1.0,
137
izone: ArrayData = 1,
138
extension: str = 'mpbas',
139
**kwargs
140
): ...
141
```
142
143
**Parameters:**
144
- `hnoflo` (float): Head value for inactive cells
145
- `hdry` (float): Head value for dry cells
146
- `porosity` (ArrayData): Effective porosity for calculating velocities
147
- `retfac` (ArrayData): Retardation factor
148
- `izone` (ArrayData): Zone array for grouping cells
149
150
### Modpath7Sim
151
152
Simulation package that defines particle tracking simulation parameters.
153
154
```python { .api }
155
class Modpath7Sim:
156
"""MODPATH 7 simulation package"""
157
def __init__(
158
self,
159
model: Modpath7,
160
simulationtype: str = 'combined',
161
trackingdirection: str = 'forward',
162
weaksinkoption: str = 'pass_through',
163
weaksourceoption: str = 'pass_through',
164
budgetoutputoption: str = 'no',
165
traceparticledata: list = None,
166
budgetcellnumbers: list = None,
167
referencetime: float = 0.0,
168
stoptimeoption: str = 'extend',
169
stoptime: float = None,
170
timepointdata: list = None,
171
zonedataoption: str = 'no',
172
zones: list = None,
173
retardationfactoroption: str = 'no',
174
retardation: list = None,
175
particlegroups: list = None,
176
extension: str = 'mpsim',
177
**kwargs
178
): ...
179
```
180
181
**Parameters:**
182
- `simulationtype` (str): Type of simulation
183
- 'endpoint': Track to endpoints only
184
- 'pathline': Track full pathlines
185
- 'timeseries': Track through time points
186
- 'combined': Both endpoints and pathlines
187
- `trackingdirection` (str): 'forward' or 'backward'
188
- `weaksinkoption` (str): How to handle weak sinks
189
- `weaksourceoption` (str): How to handle weak sources
190
- `referencetime` (float): Reference time for simulation
191
- `stoptime` (float): Maximum tracking time
192
193
### Modpath6Bas
194
195
Basic package for MODPATH 6.
196
197
```python { .api }
198
class Modpath6Bas:
199
"""MODPATH 6 basic package"""
200
def __init__(
201
self,
202
model: Modpath6,
203
hnoflo: float = 1e30,
204
hdry: float = -1e30,
205
def_face_ct: int = 6,
206
bud_loc: int = 0,
207
bud_label: str = None,
208
def_iface: ArrayData = None,
209
laytyp: ArrayData = None,
210
ibound: ArrayData = None,
211
porosity: ArrayData = 0.1,
212
extension: str = 'mpbas',
213
**kwargs
214
): ...
215
```
216
217
### Modpath6Sim
218
219
Simulation package for MODPATH 6.
220
221
```python { .api }
222
class Modpath6Sim:
223
"""MODPATH 6 simulation package"""
224
def __init__(
225
self,
226
model: Modpath6,
227
option_flags: list = None,
228
ref_time: float = 0.0,
229
ref_time_per_stp: list = None,
230
stop_time: float = None,
231
group_name: list = None,
232
group_placement: list = None,
233
release_times: list = None,
234
group_region: list = None,
235
mask_nlay: list = None,
236
mask_layer: list = None,
237
mask_1lay: list = None,
238
face_ct: list = None,
239
ifaces: list = None,
240
part_ct: list = None,
241
time_ct: list = None,
242
release_time_incr: list = None,
243
time_pts: list = None,
244
particle_cell_cnt: list = None,
245
cell_bd_ct: list = None,
246
bud_grp: list = None,
247
trace_id: list = None,
248
stop_zone: list = None,
249
zone: list = None,
250
retard_fac: list = None,
251
retard_fcCB: list = None,
252
sf_water_cont: list = None,
253
extension: str = 'mpsim',
254
**kwargs
255
): ...
256
```
257
258
## Particle Data Classes
259
260
### ParticleData
261
262
Base class for defining particle starting locations.
263
264
```python { .api }
265
class ParticleData:
266
"""Base particle data class"""
267
def __init__(
268
self,
269
partlocs: ArrayData,
270
structured: bool = True,
271
particleids: ArrayData = None,
272
**kwargs
273
): ...
274
275
@property
276
def particlecount(self) -> int:
277
"""Number of particles"""
278
...
279
280
def to_coords(self, grid: object) -> list[tuple[float, float, float]]:
281
"""Convert particle locations to coordinates"""
282
...
283
284
def write(self, f: object) -> None:
285
"""Write particle data to file"""
286
...
287
```
288
289
### LRCParticleData
290
291
Particle data using layer-row-column coordinates for structured grids.
292
293
```python { .api }
294
class LRCParticleData(ParticleData):
295
"""Layer-row-column particle data for structured grids"""
296
def __init__(
297
self,
298
subdivisiondata: list = None,
299
lrcregions: list = None,
300
**kwargs
301
): ...
302
303
@classmethod
304
def create_subdivisiondata(
305
cls,
306
grid: object,
307
subdivisions: tuple[int, int, int] = (1, 1, 1),
308
localx: ArrayData = 0.5,
309
localy: ArrayData = 0.5,
310
localz: ArrayData = 0.5
311
) -> list:
312
"""Create subdivision data for uniform particle placement"""
313
...
314
315
@classmethod
316
def create_lrcregions(
317
cls,
318
lrcregions: list[tuple[int, int, int, int, int, int]]
319
) -> list:
320
"""Create LRC regions for particle placement"""
321
...
322
```
323
324
**Parameters:**
325
- `subdivisiondata` (list): Cell subdivision specifications
326
- `lrcregions` (list): Layer-row-column regions for particle placement
327
- Format: [(lay1, row1, col1, lay2, row2, col2), ...]
328
329
### NodeParticleData
330
331
Particle data using node numbers for unstructured grids.
332
333
```python { .api }
334
class NodeParticleData(ParticleData):
335
"""Node-based particle data for unstructured grids"""
336
def __init__(
337
self,
338
subdivisiondata: list = None,
339
nodes: ArrayData = None,
340
**kwargs
341
): ...
342
```
343
344
### CellDataType
345
346
Template for cell-based particle starting locations.
347
348
```python { .api }
349
class CellDataType:
350
"""Cell-based particle starting locations"""
351
def __init__(
352
self,
353
drape: int = 0,
354
columncelldivisions: int = 1,
355
rowcelldivisions: int = 1,
356
layercelldivisions: int = 1,
357
**kwargs
358
): ...
359
```
360
361
### FaceDataType
362
363
Template for face-based particle starting locations.
364
365
```python { .api }
366
class FaceDataType:
367
"""Face-based particle starting locations"""
368
def __init__(
369
self,
370
drape: int = 0,
371
verticaldivisions: int = 1,
372
horizontaldivisions: int = 1,
373
**kwargs
374
): ...
375
```
376
377
## Particle Group Classes
378
379
### ParticleGroup
380
381
Container for groups of particles with common properties.
382
383
```python { .api }
384
class ParticleGroup:
385
"""Particle group container"""
386
def __init__(
387
self,
388
particlegroupname: str,
389
particledata: ParticleData,
390
filename: str = None,
391
releasedata: object = None,
392
**kwargs
393
): ...
394
395
@property
396
def particlecount(self) -> int:
397
"""Total number of particles in group"""
398
...
399
400
def set_releaseoption(
401
self,
402
option: str = 'specified',
403
releasedata: list = None
404
) -> None:
405
"""Set particle release timing"""
406
...
407
408
def write(self, f: object) -> None:
409
"""Write particle group to file"""
410
...
411
```
412
413
**Parameters:**
414
- `particlegroupname` (str): Name for particle group
415
- `particledata` (ParticleData): Particle location data
416
- `releasedata` (object): Release timing information
417
418
### ParticleGroupLRCTemplate
419
420
Template for LRC-based particle groups.
421
422
```python { .api }
423
class ParticleGroupLRCTemplate:
424
"""LRC-based particle group template"""
425
def __init__(
426
self,
427
particlegroupname: str,
428
particledata: LRCParticleData,
429
filename: str = None,
430
**kwargs
431
): ...
432
```
433
434
### ParticleGroupNodeTemplate
435
436
Template for node-based particle groups.
437
438
```python { .api }
439
class ParticleGroupNodeTemplate:
440
"""Node-based particle group template"""
441
def __init__(
442
self,
443
particlegroupname: str,
444
particledata: NodeParticleData,
445
filename: str = None,
446
**kwargs
447
): ...
448
```
449
450
## Usage Examples
451
452
### Basic Forward Particle Tracking
453
454
```python
455
import flopy
456
import numpy as np
457
458
# Create or load MODFLOW model first
459
mf = flopy.modflow.Modflow(modelname='flow_model')
460
# ... MODFLOW setup and execution ...
461
462
# Create MODPATH 7 model
463
mp = flopy.modpath.Modpath7(
464
modelname='basic_tracking',
465
flowmodel=mf, # Link to MODFLOW model
466
exe_name='mp7',
467
model_ws='.'
468
)
469
470
# Basic package - define porosity and zones
471
bas = flopy.modpath.Modpath7Bas(
472
mp,
473
porosity=0.25, # Effective porosity
474
retfac=1.0, # No retardation
475
izone=1 # Single zone
476
)
477
478
# Create particle starting locations
479
# Place particles at well locations for capture zone analysis
480
nlay, nrow, ncol = mf.dis.nlay, mf.dis.nrow, mf.dis.ncol
481
482
# Define particle locations around pumping wells
483
particledata = []
484
well_locations = [(0, 25, 25), (1, 40, 60)] # Layer, row, col
485
486
for lay, row, col in well_locations:
487
# Create 3x3x1 grid of particles around each well
488
for dr in [-1, 0, 1]:
489
for dc in [-1, 0, 1]:
490
r = max(0, min(nrow-1, row + dr))
491
c = max(0, min(ncol-1, col + dc))
492
particledata.append([lay, r, c, 0.5, 0.5, 0.5])
493
494
# Create particle data object
495
pdata = flopy.modpath.LRCParticleData(
496
subdivisiondata=particledata
497
)
498
499
# Create particle group
500
pg = flopy.modpath.ParticleGroup(
501
particlegroupname='wells',
502
particledata=pdata,
503
filename='wells.sloc'
504
)
505
506
# Simulation package for forward tracking
507
sim = flopy.modpath.Modpath7Sim(
508
mp,
509
simulationtype='combined', # Both pathlines and endpoints
510
trackingdirection='forward',
511
weaksinkoption='pass_through',
512
weaksourceoption='pass_through',
513
referencetime=0.0,
514
stoptimeoption='extend',
515
particlegroups=[pg]
516
)
517
518
# Write and run MODPATH
519
mp.write_input()
520
success, buff = mp.run_model()
521
522
# Results will be in endpoint and pathline files
523
```
524
525
### Backward Particle Tracking from Discharge Points
526
527
```python
528
import flopy
529
import numpy as np
530
531
# MODFLOW model (abbreviated)
532
mf = flopy.modflow.Modflow(modelname='source_tracking')
533
# ... model setup ...
534
535
# MODPATH 7 for backward tracking
536
mp = flopy.modpath.Modpath7(
537
modelname='backward_track',
538
flowmodel=mf
539
)
540
541
# Basic package
542
bas = flopy.modpath.Modpath7Bas(
543
mp,
544
porosity=0.30,
545
retfac=1.0
546
)
547
548
# Backward tracking from stream discharge points
549
# Place particles at all stream cells
550
stream_cells = []
551
# Assume stream along row 30
552
for col in range(20, 80): # Stream extent
553
stream_cells.append([0, 30, col, 0.5, 0.5, 0.9]) # Near top of cell
554
555
pdata = flopy.modpath.LRCParticleData(
556
subdivisiondata=stream_cells
557
)
558
559
pg = flopy.modpath.ParticleGroup(
560
particlegroupname='stream_discharge',
561
particledata=pdata
562
)
563
564
# Backward simulation with time limit
565
sim = flopy.modpath.Modpath7Sim(
566
mp,
567
simulationtype='pathline',
568
trackingdirection='backward',
569
referencetime=0.0,
570
stoptimeoption='specified',
571
stoptime=3650.0, # 10 years maximum travel time
572
particlegroups=[pg]
573
)
574
575
mp.write_input()
576
success, buff = mp.run_model()
577
```
578
579
### Advanced Particle Tracking with Multiple Release Times
580
581
```python
582
import flopy
583
import numpy as np
584
585
# Complex particle tracking scenario
586
mf = flopy.modflow.Modflow(modelname='complex_tracking')
587
# ... transient MODFLOW model setup ...
588
589
mp = flopy.modpath.Modpath7(
590
modelname='complex_mp',
591
flowmodel=mf
592
)
593
594
# Enhanced basic package with multiple zones
595
# Different porosity and retardation by layer
596
porosity_3d = np.ones((nlay, nrow, ncol)) * 0.25
597
porosity_3d[0, :, :] = 0.35 # Higher porosity in top layer
598
porosity_3d[2, :, :] = 0.15 # Lower porosity in bottom layer
599
600
retardation_3d = np.ones((nlay, nrow, ncol))
601
retardation_3d[1, :, :] = 2.0 # Retardation in middle layer
602
603
# Zone array for different geological units
604
zones = np.ones((nlay, nrow, ncol), dtype=int)
605
zones[0, :, :] = 1 # Alluvium
606
zones[1, :, :] = 2 # Clay layer
607
zones[2, :, :] = 3 # Bedrock
608
609
bas = flopy.modpath.Modpath7Bas(
610
mp,
611
porosity=porosity_3d,
612
retfac=retardation_3d,
613
izone=zones
614
)
615
616
# Multiple particle groups with different release strategies
617
618
# Group 1: Continuous release at contamination source
619
source_particles = []
620
source_row, source_col = 15, 40
621
# Dense particle grid at source
622
for i in range(5):
623
for j in range(5):
624
localx = 0.1 + i * 0.2
625
localy = 0.1 + j * 0.2
626
source_particles.append([0, source_row, source_col, localx, localy, 0.5])
627
628
pdata1 = flopy.modpath.LRCParticleData(subdivisiondata=source_particles)
629
pg1 = flopy.modpath.ParticleGroup(
630
particlegroupname='continuous_source',
631
particledata=pdata1
632
)
633
634
# Group 2: Periodic releases at injection wells
635
injection_particles = []
636
injection_locations = [(0, 20, 25), (0, 30, 45), (1, 25, 35)]
637
for lay, row, col in injection_locations:
638
# Single particle per injection point
639
injection_particles.append([lay, row, col, 0.5, 0.5, 0.5])
640
641
pdata2 = flopy.modpath.LRCParticleData(subdivisiondata=injection_particles)
642
pg2 = flopy.modpath.ParticleGroup(
643
particlegroupname='periodic_injection',
644
particledata=pdata2
645
)
646
647
# Group 3: Area source with uniform distribution
648
area_particles = []
649
# Distributed source over agricultural area
650
for row in range(10, 20):
651
for col in range(50, 70):
652
if (row - 10) % 2 == 0 and (col - 50) % 3 == 0: # Sparse distribution
653
area_particles.append([0, row, col, 0.5, 0.5, 0.8])
654
655
pdata3 = flopy.modpath.LRCParticleData(subdivisiondata=area_particles)
656
pg3 = flopy.modpath.ParticleGroup(
657
particlegroupname='area_source',
658
particledata=pdata3
659
)
660
661
# Complex simulation with time points and budget output
662
time_points = [30.0, 90.0, 365.0, 1825.0, 3650.0] # Monthly to 10 years
663
664
sim = flopy.modpath.Modpath7Sim(
665
mp,
666
simulationtype='combined',
667
trackingdirection='forward',
668
weaksinkoption='stop', # Stop at weak sinks
669
weaksourceoption='pass_through',
670
budgetoutputoption='summary',
671
referencetime=0.0,
672
stoptimeoption='specified',
673
stoptime=7300.0, # 20 years maximum
674
timepointdata=time_points,
675
zonedataoption='on',
676
zones=[1, 2, 3], # Track zone transitions
677
particlegroups=[pg1, pg2, pg3]
678
)
679
680
mp.write_input()
681
success, buff = mp.run_model()
682
683
# Post-process results
684
try:
685
# Read pathline data
686
pthobj = flopy.utils.PathlineFile(mp.model_ws + '/complex_mp.mppth')
687
pathlines = pthobj.get_alldata()
688
689
# Read endpoint data
690
epobj = flopy.utils.EndpointFile(mp.model_ws + '/complex_mp.mpend')
691
endpoints = epobj.get_alldata()
692
693
print(f"Number of pathlines: {len(pathlines)}")
694
print(f"Number of endpoints: {len(endpoints)}")
695
696
except:
697
print("Could not read MODPATH output files")
698
```
699
700
### Structured Grid Subdivision for Dense Particle Placement
701
702
```python
703
import flopy
704
import numpy as np
705
706
# High-resolution particle tracking in specific zones
707
mf = flopy.modflow.Modflow(modelname='detailed_tracking')
708
# ... MODFLOW setup ...
709
710
mp = flopy.modpath.Modpath7(
711
modelname='detailed_mp',
712
flowmodel=mf
713
)
714
715
bas = flopy.modpath.Modpath7Bas(mp, porosity=0.25)
716
717
# Create detailed subdivision data for high-density particle placement
718
# Method 1: Uniform subdivision across selected cells
719
nlay, nrow, ncol = mf.dis.nlay, mf.dis.nrow, mf.dis.ncol
720
721
# Define region of interest (contamination plume area)
722
roi_layers = [0, 1] # Top two layers
723
roi_rows = range(20, 40) # Central portion
724
roi_cols = range(30, 70) # Extended width
725
726
subdivisiondata = []
727
for lay in roi_layers:
728
for row in roi_rows:
729
for col in roi_cols:
730
# 4x4x2 subdivision in each cell (32 particles per cell)
731
for k_div in range(2):
732
for i_div in range(4):
733
for j_div in range(4):
734
localx = (j_div + 0.5) / 4.0
735
localy = (i_div + 0.5) / 4.0
736
localz = (k_div + 0.5) / 2.0
737
subdivisiondata.append([lay, row, col, localx, localy, localz])
738
739
# Method 2: Using built-in subdivision functionality
740
subdivision_specs = []
741
for lay in roi_layers:
742
for row in roi_rows:
743
for col in roi_cols:
744
# Each cell subdivided into 3x3x2 = 18 particles
745
subdivision_specs.append([lay, row, col, 3, 3, 2])
746
747
# Create particle data with manual subdivision
748
pdata_manual = flopy.modpath.LRCParticleData(
749
subdivisiondata=subdivisiondata
750
)
751
752
# Create using built-in subdivision
753
grid = mf.modelgrid
754
pdata_auto = flopy.modpath.LRCParticleData.create_subdivisiondata(
755
grid=grid,
756
subdivisions=(2, 3, 3), # z, y, x subdivisions
757
localx=np.array([0.25, 0.75]), # Two columns
758
localy=np.array([0.2, 0.5, 0.8]), # Three rows
759
localz=np.array([0.25, 0.75]) # Two layers
760
)
761
762
# Create particle groups
763
pg_manual = flopy.modpath.ParticleGroup(
764
particlegroupname='detailed_manual',
765
particledata=pdata_manual
766
)
767
768
# Simulation for detailed analysis
769
sim = flopy.modpath.Modpath7Sim(
770
mp,
771
simulationtype='pathline',
772
trackingdirection='forward',
773
referencetime=0.0,
774
stoptimeoption='specified',
775
stoptime=1825.0, # 5 years
776
particlegroups=[pg_manual]
777
)
778
779
mp.write_input()
780
success, buff = mp.run_model()
781
782
print(f"Total particles tracked: {pdata_manual.particlecount}")
783
```
784
785
### Unstructured Grid Particle Tracking
786
787
```python
788
import flopy
789
import numpy as np
790
791
# MODFLOW-USG or MODFLOW 6 unstructured model
792
# Example assumes MODFLOW 6 with DISV
793
sim = flopy.mf6.MFSimulation(sim_name='unstructured_sim')
794
# ... simulation setup ...
795
796
gwf = flopy.mf6.ModflowGwf(sim, modelname='gwf_unstructured')
797
# ... unstructured grid model setup with DISV ...
798
799
# MODPATH 7 for unstructured grid
800
mp = flopy.modpath.Modpath7(
801
modelname='unstructured_mp',
802
flowmodel=gwf
803
)
804
805
# Basic package for unstructured grid
806
ncpl = gwf.disv.ncpl.array # Cells per layer
807
nlay = gwf.disv.nlay.array
808
porosity = np.ones(ncpl * nlay) * 0.25
809
810
bas = flopy.modpath.Modpath7Bas(
811
mp,
812
porosity=porosity
813
)
814
815
# Node-based particle data for unstructured grid
816
# Select nodes around specific features
817
source_nodes = []
818
target_nodes = []
819
820
# Assume contamination source at specific nodes
821
contamination_nodes = [150, 151, 152, 180, 181, 182] # Node numbers
822
for node in contamination_nodes:
823
# Multiple particles per node with different local positions
824
for i in range(9): # 3x3 pattern
825
localx = 0.2 + (i % 3) * 0.3
826
localy = 0.2 + (i // 3) * 0.3
827
localz = 0.5
828
source_nodes.append([node, localx, localy, localz])
829
830
# Discharge area nodes for backward tracking
831
discharge_nodes = [800, 801, 802, 820, 821, 822]
832
for node in discharge_nodes:
833
target_nodes.append([node, 0.5, 0.5, 0.9]) # Near cell top
834
835
# Create node particle data
836
pdata_source = flopy.modpath.NodeParticleData(
837
subdivisiondata=source_nodes
838
)
839
840
pdata_target = flopy.modpath.NodeParticleData(
841
subdivisiondata=target_nodes
842
)
843
844
# Create particle groups
845
pg_forward = flopy.modpath.ParticleGroup(
846
particlegroupname='source_forward',
847
particledata=pdata_source
848
)
849
850
pg_backward = flopy.modpath.ParticleGroup(
851
particlegroupname='target_backward',
852
particledata=pdata_target
853
)
854
855
# Simulation with both forward and backward tracking
856
sim_mp = flopy.modpath.Modpath7Sim(
857
mp,
858
simulationtype='combined',
859
trackingdirection='forward', # Will be overridden per group
860
particlegroups=[pg_forward, pg_backward]
861
)
862
863
mp.write_input()
864
success, buff = mp.run_model()
865
```
866
867
## Common Types
868
869
```python { .api }
870
# Particle tracking types
871
TrackingDirection = Literal['forward', 'backward']
872
SimulationType = Literal['endpoint', 'pathline', 'timeseries', 'combined']
873
SinkSourceOption = Literal['pass_through', 'stop']
874
StopTimeOption = Literal['extend', 'specified']
875
876
# Particle location data
877
ParticleLocation = list[Union[int, float]] # [lay/node, row, col, localx, localy, localz]
878
SubdivisionData = list[ParticleLocation]
879
RegionData = list[tuple[int, int, int, int, int, int]] # (lay1, row1, col1, lay2, row2, col2)
880
881
# Grid and array types
882
ArrayData = Union[float, list[float], np.ndarray]
883
GridType = Literal['structured', 'unstructured', 'vertex']
884
NodeNumbers = list[int]
885
886
# Time and release data
887
TimeData = list[float]
888
ReleaseOption = Literal['specified', 'periodic', 'continuous']
889
ReleaseData = Union[float, list[float]]
890
891
# Output options
892
BudgetOutput = Literal['no', 'summary', 'record_summary']
893
ZoneOption = Literal['no', 'on']
894
RetardationOption = Literal['no', 'on']
895
896
# File types
897
ParticleFile = str
898
PathlineFile = str
899
EndpointFile = str
900
TimeseriesFile = str
901
```
902
903
This comprehensive documentation covers the complete MODPATH particle tracking API including both versions 6 and 7, all particle data types, and usage patterns. The examples demonstrate basic to advanced particle tracking scenarios including forward/backward tracking, multiple release strategies, and both structured and unstructured grid applications.