Geometry / Read the grid

Different spacings, one coordinate map

Predict the coordinates before you run the code.

Download runnable lesson (.zip)

Includes the model, inputs, required headers and a short run guide.

A rectangular grid need not have cubic cells. With an origin \(o\) and spacing \(h\), the coordinate of index \((i,j,k)\) is

\[ \begin{gathered} x=o_x+i h_x, \\ y=o_y+j h_y, \\ z=o_z+k h_z. \end{gathered} \]

OpenPFC keeps size, origin and spacing explicit, so an initial condition can be written in physical coordinates even when the cells are anisotropic.

Let the domain do the conversion

const auto grid =
    pfc::domain::create(pfc::GridSize{{8, 4, 2}}, pfc::PhysicalOrigin{{-1, 2, 10}},
                        pfc::GridSpacing{{.25, .5, 3}});
std::cout << std::setprecision(17) << "i,j,k,x,y,z,ri,rj,rk\n";
for (const pfc::Int3 index : {pfc::Int3{0, 0, 0}, {3, 2, 1}, {7, 3, 1}}) {
  const auto point = pfc::domain::to_coords(grid, index);
  const auto recovered = pfc::domain::to_indices(grid, point);
  std::cout << index[0] << ',' << index[1] << ',' << index[2] << ',' << point[0]
            << ',' << point[1] << ',' << point[2] << ',' << recovered[0] << ','
            << recovered[1] << ',' << recovered[2] << '\n';
}

For index \((3,2,1)\), the example obtains \((-0.25,3,13)\). Mapping those coordinates back recovers the original index. The other probes exercise the first and last stored points. to_indices rounds each component to the nearest grid index; it is not a field interpolator.

Distinguish a coordinate map from a boundary rule

openpfc run model.cpp input.json --launcher=none

Edit the constants in model.cpp; the empty input is unused. The program prints a CSV table with both conversions. The regression checks all three physical coordinates and every recovered index against the affine formula.

Try a point halfway between two samples, then a point outside the box. The conversion does not clamp or wrap indices. Periodic wrapping belongs to the operation that needs it. Similarly, changing \(h_x\) must change an x derivative’s scale: a coordinate conversion alone does not implement that derivative. The heat comparison uses physical wave numbers for this reason.

This refactors the former strong-types domain demonstration into one coordinate experiment. The public domain header is the contract for rounding and endpoint conventions.

The complete C++ model and starting input are available with this lesson.