Here's how you name the layers and how that naming breaks down to pieces of
information that inform FloodAdapt. The pipeline reads the layer name and
(where present) the geometry's Z coordinates, then writes a ready-to-ingest
GeoJSON. Per-feature attribute entry via Rhino's SetUserText is
still supported as an override but is no longer required.
01Layer Names
The pattern is:
<canonical_type>[_<value><unit>][_<value><unit>]…
The canonical type tells the pipeline what kind of intervention this is.
Each trailing _<value><unit> token sets one parameter on every feature on
that layer. Tokens stack and are order-independent; a plain canonical name (no suffix)
uses the layer's defaults.
Canonical types
| Layer name | Becomes | Geometry | What it represents |
|---|---|---|---|
levee | levee measure | LineString | Earthen embankment / generic wall |
seawall | levee measure (seawall variant) | LineString | Shoreline barrier |
gate | gate measure | LineString | Deployable barrier / floodgate |
platform | levee measure (platform variant) | Polygon | Flat elevated pad — single crest height |
mesh_surface | many platform measures | 3D Mesh / Brep / Surface | Elevated form with grading — auto-contoured into iso-band platforms |
pump | pump measure | 2-vertex LineString | Active stormwater pump (line direction = source → sink) |
culvert | culvert measure | 2-vertex LineString | Passive drainage culvert (inlet → outlet) |
retention | retention basin | Polygon | Detention / retention basin |
green_infra | green infrastructure | Polygon | Distributed green infra coverage area |
buildings | custom building exposure | Polygon / Brep / Mesh | Proposed or hypothetical building footprint |
Suffix units
Append _<value><unit> to encode a parameter. The unit determines the
attribute and which conversion (if any) is applied. Units that aren't valid for the
canonical type are rejected with a warning and the layer still resolves without
that attribute.
| Suffix | Sets | Conversion | Valid on |
|---|---|---|---|
m | crest_elevation_m | × 1 | levee, seawall, gate, platform |
cms | capacity_cms | × 1 | pump, culvert |
m3s | capacity_cms (alias) | × 1 | pump, culvert |
m3 | capacity_m3 | × 1 | retention |
mmhr | infiltration_rate_mm_hr | × 1 | retention |
pct | retention_pct | ÷ 100 | green_infra |
Examples
| Layer name | Resolves to |
|---|---|
seawall_5.33m |
seawall measure with crest_elevation_m = 5.33 |
platform_4.064m |
platform with crest_elevation_m = 4.064 |
pump_20cms or pump_20m3s |
pump with capacity_cms = 20 |
retention_10000m3 |
retention basin with capacity_m3 = 10000 |
retention_10000m3_5mmhr |
retention basin with capacity_m3 = 10000, infiltration_rate_mm_hr = 5 |
green_infra_30pct |
green infrastructure with retention_pct = 0.30 |
Multiple input layers can resolve to the same canonical type with different parameter
values. pump_5cms and pump_20cms both write into one
<stem>_pump.geojson with mixed-capacity features; the pipeline reads
capacity per-feature.
Variants _v<N> and options _opt<X>
Two tag suffixes let you author multiple design alternatives in one Rhino file. They serve different purposes and follow different rules — pick the right one.
| Suffix | Meaning | Typical use | Co-linking |
|---|---|---|---|
_v1, _v2, … |
Design variant — paired across multiple measure types that move together. | Seawall + pump pairs: seawall_v1 goes with pump_20cms_v1;
seawall_v2 goes with pump_5cms_v2. |
Coupled. The scenario builder snaps all variant-bearing measures to the same v# at once. Mixed pairs (e.g. seawall v1 + pump v2) are not run. |
_optA, _optB, … |
Independent option — exclusive alternatives for a single measure type that are not tied to any other measure. | Platform proposals: platform_optA, platform_optB, platform_optC — three distinct platform designs to evaluate side-by-side. |
Decoupled. Selecting platform option A does not change which seawall or pump is active. Currently only used on the platform layer. |
Each variant + option combination writes to its own geojson:
platform_optA_4.064m → <stem>_platform_optA.geojson.
The properties dict on every feature carries variant and/or
option fields so downstream code can filter.
Tags are order-independent and stack with parameter tokens.
platform_optA_4.064m, platform_4.064m_optA, and
platform_optA (with crest set via UserText) all resolve correctly.
02Auto-Derive From Geometry Z
Drawing geometry at non-zero Z lets the pipeline read elevation directly. Z values are converted from the source CRS units to metres automatically — Rhino models in EPSG:2263 (US survey feet) get a 0.3048 multiplier; EPSG:32618 (metres) doesn't. The factor is logged on every ingest.
Barriers and platforms
For LineStrings on levee / seawall / gate
layers and Polygons on the platform layer:
| Z values | What happens |
|---|---|
| All vertices at z=0 (the default Rhino plane) | No Z signal — falls through to layer-name suffix or layer default. |
| All vertices at uniform Z (range ≤ 0.05 m) | Mean Z becomes crest_elevation_m. |
| Z varies (range > 0.05 m) | Refused — feature is skipped with a warning. Either flatten,
move to mesh_surface, or set crest_elevation_m via UserText. |
Buildings
For 3D Brep / Mesh / Extrusion footprints on the buildings layer:
ground_elev_m= min Z across all verticesheight_m= (max − min) Z, only if the range exceeds 0.5 m (so flat 2D footprints aren't false-tagged with a height)
2D building footprints (closed polylines drawn flat) keep working — the pipeline samples ground elevation from the DEM and uses the layer-default height.
mesh_surface (the special case)
For elevated forms with grading — a rail station with sloping ramps, a podium that
steps down between streets, a complex landform — author the design as a single 3D
mesh on a layer named mesh_surface. The pipeline rasterizes the mesh
to a height field, slices it into elevation bands at --contour-interval
(default 0.5 m), and emits one platform polygon per band. Each polygon is tagged
with the band's mid-elevation as crest_elevation_m.
Per-mesh UserText keys contour_interval_m and raster_res_m
override the CLI defaults for that mesh.
Iso-band features carry raise_only=true automatically. If part of the
massing dips below existing grade — a ramp that overshoots, a modeling artifact —
those cells leave the SFINCS DEM at its existing terrain value rather than digging
a trench. You'll see an raise_only platforms: N cells left at existing grade
line in the SFINCS run log when this happens.
03Geometry per Layer
| Layer | What to draw |
|---|---|
| levee, seawall, gate | Open polyline — do not close. Snap endpoints precisely to avoid gaps. |
| platform, retention, green_infra | Closed polyline or closed curve. |
| mesh_surface | 3D Mesh / Brep / Surface — the design's elevation IS the source of truth. |
| pump, culvert | 2-vertex polyline. First vertex = source / inlet; second vertex = sink / outlet. Direction encodes flow. |
| buildings | Closed polyline, Extrusion, Brep, or Mesh. 3D solids let the pipeline read ground + height from Z. |
04Coordinate System
Declare the CRS at ingest time. Common options:
| CRS | EPSG | Units |
|---|---|---|
| NY State Plane Long Island | 2263 | US survey feet (auto-converted) |
| NY State Plane LI (NAD83 2011) | 6539 | US survey feet (auto-converted) |
| UTM Zone 18N | 32618 | metres |
python scripts/ingest_cad.py my_design.3dm --source-crs EPSG:2263
The pipeline auto-detects whether the CRS is foot-based or metre-based and applies the conversion to Z values. But if your Rhino model is drawn in metres and you declare a foot-based CRS (or vice versa), Z will be off by 3.28×. Verify the per-ingest log line:
source CRS 'EPSG:2263' uses 'us survey foot' → z×0.3048
05Precedence
When multiple sources supply the same attribute, the higher source wins:
| # | Source | Granularity | Use when… |
|---|---|---|---|
| 1 | Layer-map default | All features on layer | Lowest fallback. Implicit; nothing to author. |
| 2 | Layer-name suffix | All features on layer | One value applies to every feature on the layer (e.g. all pumps on this layer have capacity 20 m³/s). |
| 3 | Geometry Z | Per-feature | You drew the design at the right elevation — no extra typing needed. |
| 4 | Per-object UserText | Per-feature | Highest. Explicit override for one feature. |
06UserText (Override Path)
For per-feature exceptions — one pump that's bigger than the rest, one barrier
with a custom name — use Rhino's SetUserText command. UserText overrides
everything from the layer name and from geometry Z.
SetUserText crest_elevation_m 5.33 SetUserText capacity_cms 12.5 SetUserText measure_name "East Harlem Seawall — Section A" // On a mesh_surface mesh, override the contour interval / resolution SetUserText contour_interval_m 0.25 SetUserText raster_res_m 0.5
07Pitfalls
| Mistake | What goes wrong | Fix |
|---|---|---|
| Closed polyline for a barrier | Read as a Polygon — barrier becomes a filled area, not a line | Open the curve (delete the closing segment) |
| Pump line drawn river → inland | Pump pumps water into the protected area instead of draining it | Reverse the line direction (first vertex = source, second = sink) |
| Barrier polyline with varying Z (snapped to terrain) | Feature refused with a warning — no output | Flatten the polyline, use mesh_surface, or set crest_elevation_m via UserText |
pump_20m3 (volume unit on a flow-rate-rated pump) |
Token rejected with a warning; capacity falls back to default 5 m³/s | Use pump_20cms or pump_20m3s |
| Stacked contour-platforms for a graded surface | Tedious, error-prone, out of sync with the 3D source | Author one 3D mesh on the mesh_surface layer; the pipeline contours it |
| 3D massing that dips below existing grade | Nothing — those bands are silently masked at burn time (no excavation) | No fix needed. The pipeline tags mesh_surface bands with raise_only=true so they only ever raise the DEM. Check the run log for raise_only platforms: N cells left at existing grade. |
| Rhino model in metres but ingested with a foot-based CRS | Z values 3.28× too low (or the inverse) | Match model units to the CRS. Verify the ingest log: z×0.3048 vs z×1.0000 |
| Stray geometry on an unrecognized layer | Skipped with a warning — no output for those features | Move to a canonical layer or delete |
Run python scripts/ingest_cad.py your_file.3dm --source-crs EPSG:2263 --dry-run
to see exactly what the ingest will produce — every layer, every feature, every parsed
suffix, every Z signal — without writing any files.