Skip to content

Repository files navigation

medium-painter

tests python license

Draw a 2D parameter field by hand.

English · 简体中文

Example: a composite plate with two layers, a circular insert, a void and a coating, showing thermal conductivity

pip install git+https://github.com/zzzzswh/medium-painter
mepa ui

That is the whole install. The editor is plain HTML/CSS/JS packed in the wheel: no Node, no build step, no network access at runtime, so it works on an offline server over an SSH tunnel.

Why

I do geophysics research and constantly need subsurface velocity models. There are plenty of polished, AI-generated models around now, but a model I draw myself still says exactly what I mean, so I wrote this tool to help me make 2D velocity models.

Then it occurred to me that other fields have the same need: heat conduction, electromagnetics, fluids, all start with a drawn medium. So, with some help from AI, I tidied it into a web tool that is not tied to any discipline and runs on a server. What the fields are called and what they mean is up to you.

It is 2D only for now. 3D may come later. If you have ideas or suggestions, please let me know. Thanks!

How to use it

What a model is

A model = a grid + some curves + some seed points + some fields.

  • Curves divide the plane into regions. Segments, polylines, splines, polygons, rectangles, circles, ellipses, parabolas, hyperbolas and freehand strokes, all defined by draggable control points.
  • Seed points give an enclosed area its values. Double-click an area and type a value for each field. Move a curve and the fill follows, because the fill remembers a physical coordinate, not a region number.
  • Fields are the arrays you export. Add one with the + above the canvas, name it, give it a unit and a background value. Any number of fields share the same geometry.

The project file holds the curves and the rules, never a raster, so it is a few kilobytes whatever the grid. Changing nx and nz moves nothing: the same file exports at 601 × 301 for a quick test and 12001 × 6001 for the real run. It goes in git, it diffs, it can be attached to a paper.

Drawing

Pick a tool and click on the canvas. Multi-point curves (polyline, spline, polygon) keep taking points; Enter finishes, Esc abandons. Points snap to crossings, control points, other curves and the model edge, so what should seal does seal; hold Ctrl to turn snapping off for a moment.

Drawing a polyline and a spline

Values

Double-click an enclosed area and fill in a value for each field in the inspector on the right. Double-click means nothing else on the canvas.

Double-click an area, type a value

A region's value can be given four ways: constant, one number; interpolate, linear between the region's own top and bottom, following the boundary as it changes; expression, a formula in x, z and the other fields' names; inherit, the field's own derivation rule.

Areas without a seed point are outlined in amber rather than silently filled with the background.

Levels

Every shape has a level. A closed shape on a higher level erases whatever lower levels drew inside it; shapes on the same level leave each other alone.

A circle drawn across two interfaces, then lifted to level 1

Put interfaces on level 0 and an inclusion on level 1, and the interfaces stop at its edge, leaving the inclusion one region. Otherwise curves running across the model would slice it into pieces. + level on the right creates a level; new shapes land on the top one, and existing shapes can be dragged to another level in the layer list.

Splitting at crossings

Select some curves (Shift to add more) and press s: every place they cross becomes a cut. Delete the pieces you do not want.

Two crossing segments split into four pieces

A piece shares the original control points over a narrower parameter range, so a cut parabola is still exactly that parabola, not a polyline.

Fields

The Field panel on the left manages the field being shown: name, unit, background value, colormap and range. A field can also have a derivation rule, such as rho * cp, and be computed from the others; a value set on a region overrides the rule. Expressions are parsed against a whitelist, never evaled, so files are safe to pass around.

Export

Export in the top bar writes the current field at full grid size as raw float32, either as a download or straight to a path on the server. mepa render on the command line exports every field at once and can write .npy.

Arrays are always (nz, nx). Whether the bytes in a raw file run down a column or across a row is set by fast_axis, and the layout actually written is printed on export, because that is the number-one way a model ends up transposed in someone else's code.

From a script

Everything the editor does is a library call:

import mepa

m = mepa.Model.load("examples/composite_plate.mepa.json")
m.grid.nx, m.grid.nz = 4001, 2001         # same geometry, ten times the sampling
fields = mepa.render(m)                   # {"k": (nz, nx) array, "rho_cp": ...}
mepa.write_binary("k.bin", fields["k"], fast_axis="z")
mepa info    examples/composite_plate.mepa.json
mepa check   examples/composite_plate.mepa.json   # seed collisions, unassigned areas, bad expressions
mepa render  examples/composite_plate.mepa.json --field k -o k.bin

On a server

The backend is stateless; the browser holds the whole project and sends it with every request (it is a few kilobytes).

mepa ui --host 127.0.0.1 --port 8000 --no-browser     # on the server
ssh -L 8000:localhost:8000 user@cluster               # on your laptop

This is a single-user tool with no authentication, and Export can write to any path. Keep it on 127.0.0.1 and tunnel in; do not bind it to an interface other people can reach.

On the side: a seismic shot

The core does not know what a field means; anything that does lives in mepa.contrib and is only reachable from the command line. There is one such extra today: with deepwave installed, mepa shot runs one acoustic shot through the field you name as the velocity, which is a quick way to see whether a model is what you meant.

pip install 'medium-painter[deepwave] @ git+https://github.com/zzzzswh/medium-painter'
mepa shot examples/salt_dome.mepa.json --vp vp --freq 10 --png shot.png

Documentation

Editor reference Every tool, panel and shortcut
File format What a .mepa.json contains
mepa-1.1.schema.json The same rules, for machines and editors
Design notes Why it works this way, and what was rejected (中文)
examples/ A heat-conduction plate and a seismic section

Development

git clone https://github.com/zzzzswh/medium-painter
cd medium-painter
pip install -e ".[dev]"
mepa ui
pytest

Citing

If a model made with this ends up in a paper, CITATION.cff has the details, and GitHub's "Cite this repository" button will format it for you.

MIT licensed.

About

Hand-draw 2D property fields in the browser and export them as arrays at any grid resolution. Seismic velocity, thermal conductivity, density, anything you name.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages