Skip to content

shore cc-par

Convert a SHORE .adjacency.json sidecar to an Xall cc.par chimera pre-processor input file.

bash
shore cc-par INPUT.adjacency.json OUTPUT.par --grd MESH.grd [OPTIONS]

Motivation

Xall is a Fortran CFD solver that consumes two files per simulation: a binary mesh (.grd) and an ASCII chimera descriptor (cc.par). The cc.par file lists every block's overset metadata (level, group, priority) and every face patch — boundary condition, IJK extents, and partner reference for inter-block connections.

SHORE produces the structured grid (packed into a binary .grd via shore grd) and a JSON adjacency sidecar that captures the multi-block connectivity. shore cc-par is the bridge: it translates the SHORE adjacency JSON into the Xall ASCII format, ready to feed into the Xall pre-processor.

File format reference

cc.par is plain ASCII, free-format, parsed by Fortran list-directed read(npar,*) calls. Order matters — the parser reads sections sequentially. Comments after ! are ignored by the reader but emitted by SHORE / overset-exploded for human readability.

The canonical readers / writers are:

  • Xnavis-projects/overset/src/readpar.f90 — Xall reader (the authoritative format definition).
  • Xnavis-projects/overset-exploded/src/lib/overset_exploded_cc_par_object.F90 — modular reader/writer used by overset-exploded for load-balancing.
  • Xnavis-projects/overset/src/calcorn.f90 lines 119–125, 392–411 — the orientation-digit decoder (tadia / nadia subroutines).
  • Xnavis-projects/overset/src/mod/modpar.f90 — BC code constants.

The file has 5 sections, in this order:

┌─ Header ──────────────────────┐  10 lines
│ '<grd-filename>'              │  line 1
│ '<output-basename>'           │  line 2
│ <save-ghost-cells>            │  line 3 (.true. / .false.)
│ <increase-overlap>            │  line 4 (.true. / .false.)
│ <extend-internal-wall>        │  line 5 (.true. / .false.)
│ <blank>                       │  line 6
│ <ngr> <fgr>                   │  line 7 (multigrid levels)
│ <blank>                       │  line 8
│ <boundary-layer-thickness>    │  line 9 (real)
│ <numerical-beach>             │  line 10 (real)
│ <blank>                       │  line 11
└───────────────────────────────┘
┌─ Blocks ──────────────────────┐
│ <N>                           │  number of blocks
│ <blank>                       │
│ <level> <group> <priority>  ! <comment>     ×N
│ <blank>                       │
└───────────────────────────────┘
┌─ Patches ─────────────────────┐
│ <M>                           │  number of patches
│ <blank>                       │
│ <block> <face> <BC> <family> <Imin> <Imax> <Jmin> <Jmax> <Kmin> <Kmax> ! <patch_index>     ×M
│ <blank>                       │
└───────────────────────────────┘
┌─ Edges ───────────────────────┐
│ <K>                           │  number of wall-edge entries (always 0 for SHORE)
│ <blank>                       │
│ ... (K lines if K > 0)        │
└───────────────────────────────┘
┌─ Boxes ───────────────────────┐
│ <B>                           │  number of hole-cutting boxes (always 0 for SHORE)
│ <blank>                       │
│ ... (B records of 1+8 lines)  │
└───────────────────────────────┘

Header fields

LineFieldTypeMeaning
1grd filenamequoted stringPath/name of the binary .grd mesh file Xall pairs with this cc.par.
2output basenamequoted stringBasename Xall uses for derived output files (e.g. cc.).
3save ghost cells.true. / .false.Write block files with ghost-cell frames.
4increase overlap.true. / .false.Enlarge inter-block overlap during chimera donor search.
5extend internal wall.true. / .false.Extend wall BC into chimera-boundary cells.
7ngr fgrtwo integersMultigrid: ngr = total levels, fgr = finest active level (typically 4 1).
9boundary layer thicknessrealEstimate of physical boundary-layer thickness; affects internal-wall and overlap heuristics. Negative disables.
10numerical beachrealWidth of numerical-beach damping zone. Negative disables.

Lines 6, 8, 11 are intentionally blank — parser advances past them with bare read(npar,*) calls.

Blocks section

N ! blocks number
                  ← blank line
<level> <group> <priority> ! <comment>     ← N lines, one per block
                  ← blank line
FieldMeaning
levelOverset priority among bodies. Higher level overrides lower when chimera holes overlap.
groupGroup index — used to bundle blocks belonging to the same body.
priorityWithin-group priority for donor search tie-breaking.
commentFree-form text. Conventionally the block name or a short label.

Block index is implicit: the first listed block is block 1, etc. This index is referenced by patches in the next section.

Patches section

The heart of the format. Every face of every block is one patch. A block with no split patches has exactly 6 lines (one per face); faces split into multiple sub-patches contribute more.

M ! patches number
                              ← blank line
<block> <face> <BC> <family> <Imin> <Imax> <Jmin> <Jmax> <Kmin> <Kmax> ! <patch_index>     ← M lines
                              ← blank line

10 numeric columns + 1 trailing comment:

ColFieldTypeMeaning
1blockint1-based index into the blocks section.
2faceint 1–6Which face: 1=Imin, 2=Imax, 3=Jmin, 4=Jmax, 5=Kmin, 6=Kmax.
3BCintBoundary-condition code (see below).
4familyintFor walls: family index for grouping (priority). For connections (BC ≥ 100): partner patch's 1-based patch_index. 0 when neither applies.
5–6Imin ImaxintPatch i-extent in cell counts (not nodes).
7–8Jmin JmaxintPatch j-extent in cells.
9–10Kmin KmaxintPatch k-extent in cells.
trailing! patch_indexint comment1-based patch index (must equal the line's position in the section; SHORE writes it for readability).

For a face perpendicular to axis A, the A-extents collapse (Amin == Amax = 0 for the lo face, n_A_cells for the hi face) and the other two axes span the full block face.

BC code constants

From Xnavis-projects/overset/src/mod/modpar.f90 and overset-exploded_block_object.F90:

CodeSymbolMeaning
0stdflagActive interior cell (not a BC).
1pareteAdiabatic viscous wall.
11inawalInactive wall, adiabatic.
12isowalIsothermal wall.
13isoinaInactive wall, isothermal.
-1BC_NATURAL_WALLNatural-BC viscous wall.
-2symmetrySymmetry plane.
-3inflowInflow.
-4inoutflowIn/outflow.
-5assigned inflowAssigned-inflow.
-6assigned pressureAssigned-pressure.
-7assigned normal velocity
-8assigned Riemann
-9extrapolatedExtrapolation (typical far-field).
-10moving wall
-11inactive wall
20offchiOffset for chimera face-center recipients. 21..26 = chimera face at I0/IN/J0/JN/K0/KN.
27innerxChimera interior point.
28innerwChimera internal wall.
29innerbNumerical-beach (spiaggia) cell.
40offgenOffset for chimera cell-center recipients. 41..46 = chimera face at I0/IN/J0/JN/K0/KN.
60offbiuOffset for one-to-one adjacency (recipient side). 61..66 = adjacent at I0/IN/J0/JN/K0/KN.
70estrapExtrapolation for moving bodies.
80xedgeEdge cell.
≥ 100connectionResolved one-to-one connection: orientation-coded, requires family > 0.

Codes ≥ 100 are not constants — they are computed from the orientation between two adjacent blocks (see next section). The parser distinguishes connections from BCs by BC > 99 AND family > 0 (readpar.f90:147). Patches with BC ≥ 100 must come in symmetric pairs: if patch p names q as its family, then patch q must name p as its family (readpar.f90:219-228); the symmetry check is fatal.

Edges section

0 ! edges number
                ← blank line

Wall-edge entries flag concave wall corners for boundary-layer treatment. SHORE produces no concave wall geometry, so this section is always 0 followed by a blank line.

Boxes section

N ! boxes number
                       ← blank line
        9       <ibl>  ! box k (type 9, hexahedron)
        v1.x  v1.y  v1.z
        v2.x  v2.y  v2.z
        ...
        v8.x  v8.y  v8.z
                       ← blank line

Boxes are hole-cutting volumes — closed regions that mark cells inside them as "internal wall". Conceptually each box contains a solid body and itself fits inside the body's near-mesh: the union of one body's boxes lies in the thin shell between the STL surface and the outer extent of the body's near-mesh, so that a background mesh's cells overlapping the body land inside at least one box and get hole-cut.

SHORE emits type 9 (hexahedron) only — eight vertex records per box, ordered by the canonical (i, j, k) bit layout described in shore.io.boxes (and reproduced in Marker boxes below). Other types (parallelepiped / cylinder shorthands the Xall reader supports) are passed through unchanged by the merger but never emitted by the writer.

<ibl> is the 1-based block index this box is associated with; the box inherits that block's level / group / priority for the chimera precedence rules in check_parete_interna (overset/src/scatole.f90). See the Marker boxes section below for the SHORE Python API and the --boxes CLI flag.

Adjacency map: how connections work

Every pair of conformal adjacent blocks contributes two patch lines — one on each side of the seam. Both reference each other via the family field, and both carry orientation codes that describe how their (i, j, k) index spaces map across the seam.

Worked example: same-axis seam

Two cubes A and B sharing a face: A's j_hi (face 4) is glued to B's j_lo (face 3). Both cubes are 8×8×8 cells, oriented the same way (no flip).

Patches:

1   4   135   2    0   8   8   8   0   8  ! 1     A.j_hi -> B.j_lo
2   3   145   1    0   8   0   0   0   8  ! 2     B.j_lo -> A.j_hi
  • 135 (A side): A's i → B's I-min increasing (along, l=1); A's j (perpendicular at Jmax) → B's J-min increasing inward (l=3); A's k → B's K-min increasing (l=5).
  • 145 (B side): B's i → A's I-min increasing (along, l=1); B's j (perpendicular at Jmin) → A's J-max decreasing inward (l=4); B's k → A's K-min increasing (l=5).
  • The two codes differ even though the seam is geometrically symmetric: each side reports its perpendicular partner from its own frame, and the partner is at Jmin on one side and Jmax on the other. Both codes describe the same seam — see the orientation digits table for the digit semantics.
  • family = 2 and family = 1 cross-reference the two patches.
  • A's j-extents are 8 8 (collapsed at j-max); B's j-extents are 0 0 (collapsed at j-min).

Worked example: cross-axis seam (cubed-sphere cap-equator)

Sub-block sub0 is one of the 4 equatorial blocks in the cubed-sphere topology; its north pole row connects to cap_north. Geometrically, sub0's j-axis is preserved into cap_north's j-axis, but sub0's i maps to cap_north's i (perpendicular axis swap from Imax→Imin):

1   2   135  25   8   8   0   8   0   4  ! 2     sub0.i_hi -> cap_north.i_lo
5   1   235   2   0   0   0   8   0   4  ! 25    cap_north.i_lo -> sub0.i_hi
  • 135 (sub side): sub's i → cap's I-min increasing (perpendicular, l=1); sub's j → cap's J-min increasing (preserved, l=3); sub's k → cap's K-min increasing (preserved, l=5).
  • 235 (cap side): cap's i → sub's I-max decreasing (perpendicular flipped, l=2); cap's j → sub's J-min increasing (preserved, l=3); cap's k → sub's K-min increasing (preserved, l=5).

The two BCs differ even though the geometric seam is the same — each side describes the mapping from its own axes to its partner's. The asymmetry comes from "Imax meets Imin": the perpendicular-axis digit on the sub side records "partner Imin going inward", while on the cap side it records "partner Imax going inward".

Orientation digits in detail

A connection BC code has three digits li lj lk:

BC = 100·li + 10·lj + lk

Each digit l ∈ {1..6} says how this side's axis maps onto a partner axis:

lPartner axis & startDirection
1I, starting at Iminincreasing inward
2I, starting at Imaxdecreasing inward (flipped)
3J, starting at Jminincreasing inward
4J, starting at Jmaxdecreasing inward (flipped)
5K, starting at Kminincreasing inward
6K, starting at Kmaxdecreasing inward (flipped)

Even-valued digits (2, 4, 6) flag a flipped axis correspondence; odd-valued digits (1, 3, 5) preserve direction. This is implemented in tadia / nadia subroutines (calcorn.f90:392-411):

fortran-free-form
! tadia: along-seam axis index
if      (l.eq.1) then; ia = nla(1) + n          ! Imin, increasing
else if (l.eq.2) then; ia = nla(2) + 1 - n      ! Imax, decreasing
else if (l.eq.3) then; ja = nla(3) + n          ! Jmin, increasing
else if (l.eq.4) then; ja = nla(4) + 1 - n      ! Jmax, decreasing
else if (l.eq.5) then; ka = nla(5) + n          ! Kmin, increasing
else if (l.eq.6) then; ka = nla(6) + 1 - n      ! Kmax, decreasing

For a same-axis seam with no flips, the side whose perpendicular face is at min (e.g. j_lo) emits 135 and the side at max (e.g. j_hi) emits 145. The codes are not symmetric: each side describes the mapping in its own frame, and the perpendicular digit reflects which boundary of the partner the seam lies on.

Decoding examples:

CodeliljlkMeaning
135135i→Imin↑, j→Jmin↑, k→Kmin↑ — no flips, perpendicular goes Imin
145145i→Imin↑, j→Jmax↓, k→Kmin↑ — perpendicular Jmax-flipped (mirror of 135)
235235i→Imax↓, j→Jmin↑, k→Kmin↑ — perpendicular Imax-flipped
415415i→Jmax↓, j→Imin↑, k→Kmin↑ — axis swap (i↔j) + flip on i
245245i→Imax↓, j→Jmax↓, k→Kmin↑ — both i and j flipped

Cell-count vs. node-count extents

Patch IJK extents are in cells, not nodes. A face perpendicular to i on a block of Ni × Nj × Nk nodes (so Ni-1 × Nj-1 × Nk-1 cells) has:

Imin = 0,  Imax = 0       (i_lo face)        Imin = Ni-1,  Imax = Ni-1   (i_hi face)
Jmin = 0,  Jmax = Nj-1                      ↳ same J extents
Kmin = 0,  Kmax = Nk-1                      ↳ same K extents

SHORE's adjacency JSON records node-shape (Ni, Nj, Nk); the writer subtracts 1 to produce the cell-count extents the reader expects.

SHORE → cc.par BC mapping

How shore cc-par translates each SHORE FaceBC enum value into the Xall BC code. See the BC code constants table above for the full Xall BC vocabulary.

SHORE FaceBCcc.par BC codefamily fieldNotes
WALL1 (parete, viscous wall)0Body wall.
FREE--free-bc (default 40), or per-block free_face_bc via --meta040 = chimera cell-center recipient (body-fitted / buffer meshes). For far-field background blocks, override with a natural BC: -3 inflow, -4 inoutflow, -9 extrapolation. Per-block overrides via --meta take precedence over --free-bc.
SHAREDorientation code (≥ 100)partner patch indexCode derived from the face's axis_map plus the partner face name — see orientation digits. For a same-axis seam with no flips the codes are 135 / 145 per side.
DIRICHLETorientation codepartner patch indexSame derivation as SHARED; cross-axis seams (e.g. cubed-sphere cap-equator) are produced naturally from the axis_map without per-topology lookup tables.
PERIODIC40 + UserWarning0cc.par has no first-class periodic BC; use Xall chimera boxes for periodic stitching.

Cubed-sphere cap-equator codes

For the cubed-sphere topology, each sub-block's polar face (sub_q.i_lo for south, sub_q.i_hi for north) connects to a lateral face of the matching cap block (cap_*.i_lo / i_hi / j_lo / j_hi), with a per-q axis remapping that mirrors the cap boundary overwrite in topology/sphere_cap.py. The eight orientation codes that fall out of the axis_map derivation are:

SubPoleCap faceSub-side codeCap-side code
sub0northcap_north.i_lo135235
sub1northcap_north.j_hi415325
sub2northcap_north.i_hi245245
sub3northcap_north.j_lo325425
sub0southcap_south.j_lo315315
sub1southcap_south.i_hi235135
sub2southcap_south.j_hi425415
sub3southcap_south.i_lo145145

These values are not hard-coded in the writer: they are computed from the axis_map field that CubedSphereTopology stamps onto each seam at build time, then serialised into the adjacency JSON. The table is shown here as a reference for cross-checking the writer's output, not as a writer input.

CLI options

FlagDefaultDescription
--grd TEXTrequiredName of the .grd mesh file Xall pairs with this cc.par (header line 1).
--output-basename TEXT"cc."Output basename Xall uses for derived files (header line 2).
--free-bc INT40BC code for FREE faces on every block that has no entry in --meta. Use -3/-4/-9 etc. for far-field background blocks.
--meta TEXTnullPer-block BlockMeta overrides. Accepts an inline JSON object or a path to a JSON file (inline JSON is tried first). Keys are block labels; values are objects with any subset of {level, group, priority, comment, free_face_bc}. Missing keys inherit their defaults. Any block absent from the map uses --free-bc for its FREE faces.
--mgl INT INT4 1Multigrid levels: total, finest active.
--boundary-layer-thickness FLOAT-0.1Header line 9.
--numerical-beach FLOAT-1.0Header line 10.

--meta format

--meta accepts either an inline JSON string or a path to a JSON file. Resolution order: the value is first parsed as JSON; if that fails it is treated as a file path (the file's content is then parsed as JSON). This means inline JSON is always unambiguous regardless of the working directory.

The JSON value must be an object mapping block labels to partial BlockMeta fields:

json
{
  "sub0":      { "level": 1, "group": 0, "priority": 1, "free_face_bc": 40 },
  "cap_north": { "level": 2, "free_face_bc": -9 }
}

Any field can be omitted; omitted fields fall back to their defaults (level=1, group=0, priority=1, free_face_bc=--free-bc). Blocks absent from the map entirely get all defaults plus free_face_bc from --free-bc.

Error cases:

  • Value is not valid JSON and is not a path to an existing file → exit 1.
  • Value is a valid file path but the file content is not valid JSON → exit 1.
  • Value parses as JSON but is not an object (e.g. a JSON array) → exit 1.

Examples

bash
# Body-fitted near-body mesh (FREE faces are chimera fringes)
shore cc-par sphere.adjacency.json sphere.cc.par --grd sphere.grd

# Far-field background mesh — all FREE faces are extrapolation
shore cc-par background.adjacency.json background.cc.par \
  --grd background.grd --free-bc -9

# Mixed near-body: caps get a different overset level and far-field BC
shore cc-par wall.adjacency.json wall.cc.par --grd wall.grd \
  --meta '{"cap_north": {"level": 2, "free_face_bc": -9},
           "cap_south": {"level": 2, "free_face_bc": -9}}'

# Same, loading the metadata from a JSON file
shore cc-par wall.adjacency.json wall.cc.par --grd wall.grd \
  --meta wall_meta.json

Python API

python
from shore.io.cc_par import BlockMeta, write_cc_par

write_cc_par(
    "wall.adjacency.json",     # path or parsed dict
    "wall.cc.par",
    grd_filename="wall.grd",
    output_basename="cc.",
    multigrid_levels=(4, 1),
    boundary_layer_thickness=-0.1,
    numerical_beach=-1.0,
    block_metadata={
        # Equatorial sub-blocks — chimera cell-centre handoff
        "sub0": BlockMeta(free_face_bc=40),
        "sub1": BlockMeta(free_face_bc=40),
        "sub2": BlockMeta(free_face_bc=40),
        "sub3": BlockMeta(free_face_bc=40),
        # Polar caps — different overset level, far-field BC
        "cap_north": BlockMeta(level=2, free_face_bc=-9),
        "cap_south": BlockMeta(level=2, free_face_bc=-9),
    },
)

The block_metadata dict is optional; any block not listed gets a default BlockMeta() (level=1, group=0, priority=1, free_face_bc=40). The --meta CLI flag exposes the same control without writing Python.

Multi-component runs

Independent Chimera components (e.g. a near-body wall + a far-field background) are produced as separate .grd + cc.par pairs and combined for a single Xall job by:

  • shore cc-par-merge — concatenate the cc.par files with the right block-index and patch-family shifts.
  • shore grd-merge — concatenate the binary .grd files in the same order.

The two commands must be invoked with the same input ordering; see each page for details.

Marker boxes

The boxes section of cc.par (cells flagged as internal-wall by the chimera hole-cutter) has its own page covering the data model, the --boxes flag, the shore boxes-from-stl generator, and the shore boxes-export ParaView visualiser:

Limitations

  • No edges section. Unsupported by SHORE-style adjacency.
  • One-way bridge. No cc.par reader is provided; the Xall Fortran tooling owns the canonical reader.
  • Topology-agnostic orientation. Cross-axis seams are no longer hard-coded per topology: every connection face in the adjacency JSON carries an axis_map that the writer uses to derive the orientation code. New topologies need only stamp valid axis_map values on their seams (see shore.mesh.face.AxisMap); no edits to this writer are required.

See also

Released under the MIT License.