pytem1d - Python Interface to TEM1D
Python wrapper for the TEM1D Fortran code that computes 1D transient electromagnetic (TEM) forward responses and derivatives for layered earth models.
Features
- Dual API: Functional and class-based interfaces
- Complete TEM1D functionality: Step/impulse responses, IP effects, polygonal loops, waveform convolution
- Derivatives: Jacobian matrix calculation for inversion
- Visualization: Built-in plotting functions
- I/O utilities: Save/load results, export to various formats
- Type-safe: Data classes with validation
- Parallel processing: Multiprocessing support for millions of forward models (see
examples/parallel_utils.py)
Installation
From source
# Clone the repository
git clone https://github.com/tem1d/tem1d.git
cd tem1d/python
# Build the Fortran shared library
make
# Install the Python package (editable mode for development)
pip install -e .
# Or install with development dependencies
pip install -e ".[dev]"
Requirements
- Python >= 3.8
- NumPy >= 1.20
- Matplotlib >= 3.3
- gfortran (or compatible Fortran compiler)
- make
Quick Start
Functional API (Simple)
import numpy as np
import matplotlib.pyplot as plt
from pytem1d import run_tem1d
# Simple 2-layer model: 100 Ω·m over 10 Ω·m halfspace
result = run_tem1d(
resistivities=[100, 10],
depths=[0, 50], # Interface at 50m depth
tx_area=314.16 # Circular loop, radius ~10m
)
# Plot response
plt.loglog(result.times * 1e3, np.abs(result.responses))
plt.xlabel('Time (ms)')
plt.ylabel('|dB/dt| (V/A·m²)')
plt.grid(True, alpha=0.3)
plt.show()
Class-Based API (Advanced)
from pytem1d import TEM1DModel
# Create model instance
tem = TEM1DModel()
# Configure layered earth
tem.set_earth_model(
resistivities=[100, 10, 50], # 3 layers
depths=[0, 30, 100] # Interfaces at 30m and 100m
)
# Configure instrument
tem.set_instrument(
tx_area=314.16,
tx_rx_separation=0.0 # Central loop
)
# Enable derivative calculation
tem.enable_derivatives(True)
# Run forward modeling
result = tem.run()
# Access results
print(f"Number of time gates: {len(result.times)}")
print(f"Derivative shape: {result.derivatives.shape}")
With IP Effects
from pytem1d import run_tem1d
result = run_tem1d(
resistivities=[100, 10, 50],
depths=[0, 30, 100],
tx_area=314.16,
# Cole-Cole IP parameters
ip_params={
'chargeabilities': [0.1, 0.3, 0.05],
'time_constants': [0.01, 0.05, 0.001],
'powers': [0.5, 0.4, 0.6]
}
)
Polygonal Loop
import numpy as np
from pytem1d import run_tem1d
# Square loop 100m x 100m
vertices = np.array([
[-50, -50],
[50, -50],
[50, 50],
[-50, 50]
])
result = run_tem1d(
resistivities=[100, 10],
depths=[0, 50],
polygon_vertices=vertices,
rx_position=(0, 0) # Receiver at center
)
Visualization
from pytem1d import run_tem1d, plot_response, plot_derivatives
# Run with derivatives
result = run_tem1d(
resistivities=[100, 10, 50],
depths=[0, 30, 100],
calculate_derivatives=True
)
# Plot response
plot_response(result)
# Plot Jacobian (sensitivities)
plot_derivatives(result, param_labels=['σ₁', 'σ₂', 'σ₃', 'h₁', 'h₂'])
API Reference
Main Functions
run_tem1d()- Functional interface for forward modelingTEM1DModel- Class-based interface with state management
Data Classes
EarthModel- Layered earth parametersIPModel- Induced polarization (Cole-Cole)Instrument- TX/RX configurationPolygonLoop- Arbitrary loop geometryTEM1DResult- Computation results
Utilities
plot_response()- Plot TEM responseplot_derivatives()- Plot Jacobian matrixplot_comparison()- Compare multiple responsessave_result()- Save results to fileload_result()- Load results from file
Examples
See the examples/ directory for more usage examples:
basic_usage.py- Simple functional APIclass_api.py- Advanced class-based APIplotting_demo.py- Visualization examplesbatch_random_models.py- Batch processing 1000 random models (compares both APIs)numerical_derivatives.py- Workaround for computing derivatives using finite differencesparallel_utils.py⚡ NEW - Parallel execution utilities for large-scale processingbatch_random_models_parallel.py⚡ NEW - Parallel benchmarking (7,000+ models/s on 128-core system)
Building from Source
The Python package requires a compiled Fortran shared library:
cd python
make # Build shared library
make clean # Clean build artifacts
The Makefile automatically detects your platform and builds the appropriate shared library (.so on Linux, .dll on Windows, .dylib on macOS).
Testing
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/
# With coverage
pytest --cov=pytem1d tests/
Troubleshooting
Library not found
If you get "Cannot load libtem1d.so" errors:
- Ensure you ran
makein thepython/directory - Check that
python/src/pytem1d/lib/libtem1d.soexists - Try reinstalling:
pip install -e .
Fortran compiler issues
If make fails:
- Linux: Install gfortran:
sudo apt-get install gfortran - macOS: Install via Homebrew:
brew install gcc - Windows: Install MinGW-w64
Results don't match TEMTEST
Small numerical differences are expected due to floating-point precision. Differences > 1% may indicate an issue.
License
See LICENSE file in the root directory.
Citation
If you use this code in publications, please cite:
- See
TEM1D_UserManual_20251219.pdffor proper citation
Contributing
Contributions are welcome! Please see the main repository for guidelines.
Links
Known Issues
Derivative Calculation
The Python interface supports derivative (Jacobian) calculation via the calculate_derivatives=True parameter. However, in the current version of the TEM1D Fortran code, derivatives may return all zeros. This is not a Python wrapper issue - the same behavior occurs with the original TEMTEST program when IDERIV=1.
To verify if derivatives are supported in your version:
cd examples/
# Check if example2 (with derivatives) produces non-zero values
./run_example.sh example2_3layer_with_derivatives.txt
grep -v "0.0000E+00" output_example2_3layer_with_derivatives/FORWRITE | wc -l
If you need derivatives for inversion, you may need to:
- Check the TEM1D user manual for derivative support status
- Implement numerical derivatives using finite differences
- Contact the TEM1D developers for the derivative-enabled version
The Python interface is ready and will work correctly once the Fortran code produces non-zero derivatives.
Metadata
Release files for pytem1d 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pytem1d-0.1.2.tar.gz | 515.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pytem1d-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 992.4 kB
Release files / pytem1d-0.1.2.tar.gz
| Download URL | pytem1d-0.1.2.tar.gz |
|---|---|
| Size | 515.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ae458742df157610ee13956fbc324ca7a5ba170d2e62d6eaa040e6fedcbab90e
|
|
BLAKE2b-256 checksum How to use checksums |
ddb0f0bd3403484e01cfd67a33be72620aff0160c1ad47ff60972e1347521613
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|
Release files / pytem1d-0.1.2-py3-none-any.whl
| Download URL | pytem1d-0.1.2-py3-none-any.whl |
|---|---|
| Size | 476.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4fccfeed6aaa0c27d8b06af99136b9d872ed0d02e542d3c16ace1e9be38cb20c
|
|
BLAKE2b-256 checksum How to use checksums |
09c99a04997422499631021f7d8e33a269923fe018ec021d9a0e8adfdf336994
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|