The goal of this project is to provide tools to read, write, and visualize three-dimensional electric field data in the B3D format, in both Matlab and Python.
In the current version, a particular implementation of the latest version 4 is supported, Location and time data must be given as variable points. The data must have at least two float channels (ex and ey). Time offset is not supported. Optionally, the second meta string represents a length-two vector that describes the location points as a grid.
This repository has a Python class (B3D in b3d.py) and a MATLAB class (b3d in b3d.m) with the same fields and the same two jobs: read a B3D version 4 file into memory, and write the in-memory data back to a B3D file. The B3D files these classes handle hold a list of latitude/longitude points, a list of time points, and the x and y electric-field components (Ex, Ey) at every point and time. Both classes write the same layout. Only the grid-dimension text differs (Python writes [3, 2]; MATLAB writes the numbers separated by spaces), and each reader accepts the other's form, so files can be passed between MATLAB and Python. Each language has one example script that builds a small field, writes it, reads it back, doubles it and writes it again. Visualization, named in the goal above, is not implemented yet.
flowchart LR
A["Existing .b3d file<br/>(version 4)"] --> B["Reader<br/>B3D(fname) in Python<br/>b3d(fname) in MATLAB"]
N["Default object<br/>B3D() or b3d()<br/>2x2 grid, 3 time points"] --> C
B --> C["Object in memory<br/>comment, grid_dim, lat, lon,<br/>time, ex, ey"]
C --> D["Your code edits the fields<br/>(see example.py, example.m)"]
D --> E["Writer<br/>write_b3d_file(fname)<br/>checks array sizes"]
E --> F["New .b3d file<br/>(version 4, Ex and Ey only)"]
The readers keep only the first two float channels (Ex, Ey) and skip any extra float or byte channels. The writers always write exactly two float channels.
| Folder | What it contains | Main contributor (git history) | Start here |
|---|---|---|---|
| Root | Python and MATLAB B3D classes, and one example script for each language | abirchfield (code and README description), Adam Birchfield (README edits on GitHub) | example.py or example.m |
__pycache__/ |
One committed compiled file, b3d.cpython-310.pyc. Python writes its own compiled file when it imports b3d.py, so this one is not needed. |
abirchfield | Nothing to open |
Root files:
| File | What it does |
|---|---|
b3d.py |
B3D class. B3D() builds a default object (2x2 grid, 3 time points, zero field). B3D(fname) reads a file with load_b3d_file. write_b3d_file(fname) checks types and sizes, then writes the file. Needs NumPy. |
b3d.m |
b3d MATLAB class (classdef) with the same fields. b3d() builds a matching default object (2x2 grid, 3 time points, zero field, stored as doubles), b3d(fname) reads a file with read_b3d_file, and write_b3d_file(fname) checks sizes, then writes the file. |
example.py |
Builds a 3x2 grid (6 points) with 10 time points (0 to 900), writes example6by10.b3d, reads it back, doubles Ex and Ey, and writes example6by10_doubled.b3d. |
example.m |
The same steps in MATLAB, with the same output file names. |
Python (any platform; the commands below are for Windows):
- Install Python 3. The committed
.pycfile was built with Python 3.10. - Open a terminal in the repository folder.
python -m venv .venv.venv\Scripts\activatepip install -r requirements.txt(seerequirements.txt; NumPy is the only third-party package).
There are no hard-coded paths to edit. The example script writes its output files into the current folder.
MATLAB:
- Install MATLAB. No toolboxes are needed. The code uses double-quoted strings, so releases before R2017a cannot run it. The repository does not name a tested release.
- In MATLAB,
cdto the repository folder, or add it to the path from elsewhere withaddpath("<path to b3d_tools>").
Python, from the repository folder with the virtual environment active:
python example.py
It prints Done! and writes example6by10.b3d and example6by10_doubled.b3d in the current folder.
To use the class in your own script, put b3d.py next to the script (or add this folder to sys.path):
from b3d import B3D
b = B3D("input.b3d") # read
b.ex *= 2 # edit (the arrays stay float32)
b.write_b3d_file("output.b3d") # writeMATLAB, from the repository folder in the Command Window:
exampleor from a terminal in the repository folder (MATLAB R2019a or later):
matlab -batch "example"
The MATLAB example writes the same two file names as the Python example, so running one overwrites the other's output. To use the class in your own code:
b = b3d("input.b3d");
b.ex = 2*b.ex;
b.write_b3d_file("output.b3d");- Input files: B3D version 4 (file code 34280) with location format 1 (a list of points), a time step of 0 (a list of time points), and at least two float channels. The first two float channels are read as Ex and Ey; extra float and byte channels are skipped. The first metastring becomes
comment, and the second, if present, becomesgrid_dim. A wrong file code, other versions, other location formats, fixed time steps, or fewer than two float channels raise an error. - Output files: B3D version 4 with two metastrings (
commentandgrid_dim), two float channels (Ex, Ey), no byte channels, location format 1 with the third location value set to 0, time offset 0, and time step 0.time_0andtime_unitsare written as stored in the object. The Python reader keeps a file's time offset intime_offset, but the writer always writes 0. - Python field types checked by
write_b3d_file:latandlonfloat64 of length n;timeuint32 of length nt;exandeyfloat32 of shape (nt, n). Any other type or shape raises an exception. - MATLAB field shapes and types:
latandlonn-by-1 column vectors (row vectors make the writer fail);timea vector of length nt;exandeynt-by-n. The reader returns doubles. The writer stores the field as float32 andtimeas uint32.commentmust be a string in double quotes: the writer joins it to the other header text with+, so a character vector in single quotes is added as numbers and the write fails or writes a broken header. - Python reads a file with exactly two float channels and no byte channels in one step. Files with extra channels are read with a Python loop over every point, which is slower on large files.
- The format itself is described in the PDF linked above.
- Both
write_b3d_filemethods open the output file before checking the data. If a check fails, the file is left empty, and an existing file with that name is lost. In MATLAB the file also stays open; runfclose('all')before retrying. The MATLABread_b3d_filealso leaves the file open when it rejects a file. - In MATLAB,
grid_dimkeeps the default[2 2]when a file has no second metastring, and it is not checked against the number of points. The Python reader sets it to[n, 1]in both cases. - Two error messages are wrong:
b3d.msays "Only version 2 of B3D format is supported" for any version other than 4, and the longitude type check inb3d.pysays "Latitude must by np array of doubles".
- Upstream: https://github.com/abirchfield/b3d_tools. This clone's
originis https://github.com/OverbyeResearchGroup/b3d_tools and itsupstreamis the abirchfield repository. At the last fetch, bothorigin/mainandupstream/mainpointed to commitac66a1a(2023-02-20). - Copies of
b3d.pyin other group repositories are listed below. They are plain file copies, so changes here do not reach them.
| Repository | Copy | Compared with b3d.py here |
|---|---|---|
| GMD-Extended-Team | B3D Import/b3d.py |
Same code (line endings ignored) |
| GMD-Extended-Team | b3d.py |
One small change in write_b3d_file (the output name is held in a separate variable); same behavior |
| GIC-inclusive-state-estimator | DC GIC State Estimator/Optimization/b3d.py |
Same code (line endings ignored) |
| GIC-Voltage-Stability | Melvin Code/htcm2026-03-18 1/htcm/src/htcm/b3d.py |
Modified: adds debug logging and a bounds check when reading files with extra channels |
| Web-Scraping-Project | Efield_auto/b3d.py |
Modified: adds an n_station array that is written as the third location value |
From the git history:
- Adam Birchfield: 4 commits (the initial commit and README edits, all made on GitHub, 2022-04-15 and 2023-02-20)
- abirchfield: 2 commits (all the code and the README description: the initial MATLAB and Python tools on 2022-04-15, and support for files with extra channels on 2023-02-20)
- Jonathan M. Snodgrass: documentation commits only, from 2026-09-28 (the README sections below the marker and
requirements.txt); no code changes
b3d.py names Adam Birchfield as its author; the Adam Birchfield and abirchfield entries are both his.
- First commit: 2022-04-15. Last code commit: 2023-02-20. Later commits (from 2026-09-28) add only documentation: the README sections below the marker and
requirements.txt. - The classes were written on 2022-04-15. The only later code change (2023-02-20) let both readers accept files with extra float or byte channels. The example scripts have not changed since 2022-04-15.
- The repository is one small library with no legacy parts. Visualization, mentioned in the goal and marked "(later)" in the
b3d.pyheader, is not implemented.