Kratos CAD JSON (.cad.json)
The NURBS boundary representation that Kratos Multiphysics' isogeometric analysis (IGA) reads and writes: trimmed NURBS faces, the loops of trimming curves that bound them, edges with 3-D curves and the coupling topology between faces. Kratos's CadJsonInput (kratos/input_output/cad_json_input.h, behind the CadIoModeler) reads it, and CadJsonOutput writes it, in the schema of Teschemacher et al., Realization of CAD-integrated shell simulation based on isogeometric B-Rep analysis (AMSES 2018). Kratos's .mdpa decks hold no NURBS (their Begin Geometries blocks take only Lagrange geometry names), so this file is where a Kratos IGA model's geometry lives; see the MDPA sidecar.
| Format name | cad_json |
| Extensions | .cad.json (a bare .json is recognised by its content) |
| Read / Write | ✓ / ✓ |
| Extra dependencies | — |
import meshioplusplus as mp
mesh = mp.read("geometry.cad.json") # the faces sampled, the B-rep kept
brep = mesh.info["brep"] # faces, loops, edges, vertices
mp.write("copy.cad.json", mesh) # writes the B-rep back exactly
fine = mp.cad_json.read("geometry.cad.json", subdivisions=8)What is read
- Faces. Every
breps[].faces[]entry: itssurface(degrees,knot_vectors,control_pointsas[id, [x, y, z, w]]or[[x, y, z, w]],is_rational,is_trimmed), itsboundary_loops(loop_typeouterorinner, each a list oftrimming_curveswithtrim_index,curve_directionand a 2-Dparameter_curvewith itsactive_range), itsembedded_edges, andswapped_surface_normal. Knot vectors may be in the full form (n + p + 1knots) or Kratos's reduced one (n + p - 1, without the outer knots), told apart from the control-point count the way Kratos's ownNurbsSurfaceGeometrydoes (the reduced form first); they are held in the full form and written back in the form they came in. - Edges and vertices. Every
edges[]entry with its optional3d_curveand itstopology(the faces and trim indices it is, withrelative_direction), and everyvertices[]entry with its topology andlocal_coordinates. - Identity.
brep_idorbrep_nameon every entity (an id of -1 in meshio++ means the entity is named instead). - The rest. Members meshio++ does not model (Kratos's
tolerancesandversion_number, a face'sembedded_loopsandembedded_points, anything a newer schema adds) are kept per object as compact JSON text (extra) and written back in place, so nothing a file carries is dropped. - The import dialect. The
Surfaces/Linesfiles Kratos'sImportNurbsSbmModelerreads (shifted-boundary IGA:CPCoordinates,Weights,knotVector/knotVectors,pDegree,Layer) are read too: surfaces as untrimmed faces, lines as rational edge curves (as that modeler builds them). That modeler reads no surface weights, and its files often give them as zeros: weights all zero or all one make a polynomial surface. Such a file is written back in thebrepsschema.
Parsing is strict JSON plus comments (Kratos's Parameters accept them). A malformed file, text that is not UTF-8, a control net that does not match its knots, a decreasing knot vector, a degree outside 1–32, or a non-positive weight on a rational entity is a ReadError.
The mesh
The mesh is a sampling of the faces, so the usual operations, writers and viewers apply to it, while the exact geometry stays in the side channel.
- Faces. Every knot span of every face becomes one Lagrange quadrilateral of the face's higher degree:
quad,quad9, orVTK_LAGRANGE_QUADRILATERALfrom degree 3, its nodes the exact (rational) surface at the cell's lattice.subdivisionssplits each span further. The default (0, automatic) keeps one cell per span, the IGA analysis elements, except on a trimmed face, which is refined to about 16 cells per direction so that its trim shows. - Trimming. A trimmed face keeps the cells whose parametric centre lies inside its loops (even-odd over all of them, each trimming curve sampled at
trim_samplespoints per knot span;trim=Falsekeeps every span). The trimmed edge of the mesh is therefore staircase-accurate to a cell, while the trimming curves stay exact in the side channel: constrained triangulation of the trimmed parameter domain is a non-goal of the core. A cell the trim crosses hascad:trimmed= 1. - Edges. Every edge with a 3-D curve becomes Lagrange line cells (
line,line3,VTK_LAGRANGE_CURVE) over its knot spans within its active range;edges=Falseskips them. - Cell data.
cad:kind(0 a face cell, 1 an edge cell),cad:index(into the side channel's faces or edges),cad:id(that entity'sbrep_id),cad:span(the knot span per direction, counted over the spans of nonzero length) andcad:trimmed. - Points are shared within a face or an edge, not between them (adjacent faces of a Kratos model are coupled, not conforming).
The side channel
mesh.info["brep"] (C++ BrepInfo, brep.hpp) holds the patches (degrees, full knots, the control net u-fastest, weights), the brep groups, the faces with their loops and trims, the edges, the vertices and the file's own extra members; see the module docstring of meshioplusplus.cad_json._cad_json for the dict layout. mp.cad_json.sample(brep, ...) samples it again, as the reader does.
What is written
- With a side channel (a mesh read from CAD JSON, STEP or IGES, or the result of
fit_cad), the B-rep is written exactly, in the layout of Kratos's ownPrettyPrintJsonString. The keys Kratos reads are always written (is_rational,swapped_surface_normal,boundary_loops…), so a hand-written file gains its defaults on the first rewrite; a file meshio++ wrote reads back to the same side channel and rewrites to the same bytes. Kratos makes model-part nodes of surface and 3-D curve control points, which need ids: the writers warn when a net has none. - From a plain mesh, every
quadcell becomes an untrimmed bilinear face (degree 1, its corners the control points, ids the point ids + 1, so neighbouring faces share their nodes) and everylinecell an edge; other cells are dropped with a warning, and a mesh with neither is aWriteError.
Numbers are written as integers when they are integral (below 2⁵³), else as the shortest of %.15g, %.16g and %.17g that reads back exactly; both engines write the same bytes.
The MDPA sidecar
A Kratos IGA project keeps its geometry beside the deck: mp.mdpa.read("model.mdpa", cad_json=True) also loads it into mesh.info["brep"], from model.cad.json beside the deck or else from the geometry_file_name of the CadIoModeler in a ProjectParameters.json beside it (with .cad.json appended when the name lacks it, as Kratos appends it); cad_json="path" names it. mp.mdpa.write(..., cad_json=True) writes it back as <stem>.cad.json. C++: mdpa_cad_json_path, and the read_mdpa/write_mdpa overloads taking a BrepInfo (formats/mdpa.hpp). See MDPA.
Other surfaces
The C API's mio_read_with_info returns a "cad_json" handle whose mio_brep_info_* accessors read the side channel section by section, and mio_write_with_info writes it back (C API); Fortran (info%brep_*), Julia (brep_info), R (mio_brep_info) and WebAssembly (readMeshSelective(path, {info: true}).info, CadJsonInfo) mirror it. Both CLIs convert to and from it through the registry. STEP and IGES files read through the optional OpenCASCADE backend carry the same side channel, so meshio++ convert part.step part.cad.json turns a CAD model into Kratos IGA geometry.
Verification
The fixtures in tests/python/meshes/cad_json/ are generated by tools/gen_cad_json_fixtures.py from closed-form geometry (a plate with a circular hole, the Scordelis-Lo roof as an exact rational cylinder, a two-patch beam with a coupling edge, an import-dialect square), not copied from Kratos. tests/python/test_cad_json.py checks the two engines against each other (mesh, side channel and bytes), the exactness of the rational geometry (radii to 1e-14), the trimming and the error paths; when KratosMultiphysics and its IgaApplication are installed (pip install KratosMultiphysics KratosIgaApplication), it loads every file meshio++ writes through Kratos's own CadJsonInput and compares GlobalCoordinates with meshio++'s evaluation to 1e-12. The cases of the Kratos Examples iga/ folder were read and rewritten during development: each rewrite equals the original once the canonical defaults are filled in. tests/cpp/test_cad_json.cpp covers the native path. Notebook 35 renders the fixtures, the MDPA sidecar and, with OpenCASCADE, a fit_cad solid with a freeform face written as CAD JSON.