or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

discretization.mdexport.mdfile-io.mdindex.mdmodflow2005.mdmodflow6.mdparticle-tracking.mdplotting.mdtransport.mdutilities.md

particle-tracking.mddocs/

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.