From 748e56370a8827eee0e1d9aab39c7489068162fc Mon Sep 17 00:00:00 2001 From: rois1995 Date: Wed, 14 Oct 2026 07:47:07 +0200 Subject: [PATCH] Mesh with boundaries split in sections for the CGNS reader test A 3D channel of 96 cells (hexahedra and prisms) whose boundaries are split in sections by element type and by block, grouped by the ZoneBC, as meshers write them. gen_mesh.c writes it with the CGNS library. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01L7oxzVir4zENrpy3K3W6Fm --- cgns_reader/gen_mesh.c | 165 +++++++++++++++++++++++++ cgns_reader/mesh_channel_sections.cgns | Bin 0 -> 62611 bytes 2 files changed, 165 insertions(+) create mode 100644 cgns_reader/gen_mesh.c create mode 100644 cgns_reader/mesh_channel_sections.cgns diff --git a/cgns_reader/gen_mesh.c b/cgns_reader/gen_mesh.c new file mode 100644 index 00000000..3131bbe8 --- /dev/null +++ b/cgns_reader/gen_mesh.c @@ -0,0 +1,165 @@ +/* Writes mesh_channel_sections.cgns, the mesh of the test cgns_reader/channel_sections.cfg. + * Build with the CGNS library of SU2, e.g. from the build folder of SU2: + * mpicc gen_mesh.c -I/externals/cgns -Iexternals/cgns externals/cgns/libcgns.a externals/cgns/hdf5/libsu2hdf5.a -lz -lm -ldl + */ +/* Small 3D channel with hexahedra (x < 1) and prisms (x > 1), written as a mesher would: + * the boundaries are split in sections by element type or by block, and the ZoneBC groups them. + * inlet : no BC covers it -> marker named after the section ("inlet") + * upper_side : BC "upper", no family -> marker named after the BC ("upper") + * lower_1, lower_2 : BC "lower_wall", family "lower" -> one marker "lower" + * quad_back, tri_back : BC "back", family "back" -> one marker "back" + * quad_front,tri_front: BC "front", family "front" -> one marker "front" + * outlet : BC "outlet", family "outlet" -> marker "outlet" + */ +#include +#include +#include "cgnslib.h" + +#define NI 9 +#define NJ 5 +#define NK 3 +#define NH 4 /* hexahedra for i < NH, prisms after */ + +static cgsize_t n(int i, int j, int k) { return 1 + i + NI * (j + NJ * k); } + +#define CHK(x) if (x) { printf("%s\n", cg_get_error()); exit(1); } + +int fn, B, Z, S; +cgsize_t next = 1; +cgsize_t conn[4096]; + +static cgsize_t section(const char* name, CGNS_ENUMT(ElementType_t) type, int ne) { + cgsize_t first = next; + CHK(cg_section_write(fn, B, Z, name, type, first, first + ne - 1, 0, conn, &S)); + next += ne; + return first; +} + +static void bc(const char* name, const char* family, CGNS_ENUMT(BCType_t) type, cgsize_t first, cgsize_t last) { + int bc; + cgsize_t range[2] = {first, last}; + CHK(cg_boco_write(fn, B, Z, name, type, CGNS_ENUMV(PointRange), 2, range, &bc)); + CHK(cg_boco_gridlocation_write(fn, B, Z, bc, CGNS_ENUMV(FaceCenter))); + if (family) { + CHK(cg_goto(fn, B, "Zone_t", Z, "ZoneBC_t", 1, "BC_t", bc, "end")); + CHK(cg_famname_write(family)); + } +} + +int main(int argc, char** argv) { + const char* file = argc > 1 ? argv[1] : "mesh_channel_sections.cgns"; + double x[NI * NJ * NK], y[NI * NJ * NK], z[NI * NJ * NK]; + for (int k = 0; k < NK; k++) + for (int j = 0; j < NJ; j++) + for (int i = 0; i < NI; i++) { + x[n(i, j, k) - 1] = 0.25 * i; + y[n(i, j, k) - 1] = 0.25 * j; + z[n(i, j, k) - 1] = 0.125 * k; + } + + const int nHex = NH * (NJ - 1) * (NK - 1), nPrism = 2 * (NI - 1 - NH) * (NJ - 1) * (NK - 1); + cgsize_t size[3] = {NI * NJ * NK, nHex + nPrism, 0}; + int C; + + CHK(cg_open(file, CG_MODE_WRITE, &fn)); + CHK(cg_base_write(fn, "Base", 3, 3, &B)); + CHK(cg_zone_write(fn, B, "Channel", size, CGNS_ENUMV(Unstructured), &Z)); + CHK(cg_coord_write(fn, B, Z, CGNS_ENUMV(RealDouble), "CoordinateX", x, &C)); + CHK(cg_coord_write(fn, B, Z, CGNS_ENUMV(RealDouble), "CoordinateY", y, &C)); + CHK(cg_coord_write(fn, B, Z, CGNS_ENUMV(RealDouble), "CoordinateZ", z, &C)); + + const char* fams[] = {"lower", "back", "front", "outlet"}; + for (int f = 0; f < 4; f++) { + int F; + CHK(cg_family_write(fn, B, fams[f], &F)); + } + + int m; + + /*--- Volume sections. ---*/ + m = 0; + for (int k = 0; k < NK - 1; k++) + for (int j = 0; j < NJ - 1; j++) + for (int i = 0; i < NH; i++) { + cgsize_t h[8] = {n(i, j, k), n(i + 1, j, k), n(i + 1, j + 1, k), n(i, j + 1, k), + n(i, j, k + 1), n(i + 1, j, k + 1), n(i + 1, j + 1, k + 1), n(i, j + 1, k + 1)}; + for (int a = 0; a < 8; a++) conn[m++] = h[a]; + } + section("HexElements", CGNS_ENUMV(HEXA_8), nHex); + + m = 0; + for (int k = 0; k < NK - 1; k++) + for (int j = 0; j < NJ - 1; j++) + for (int i = NH; i < NI - 1; i++) { + cgsize_t p[12] = {n(i, j, k), n(i + 1, j, k), n(i + 1, j + 1, k), + n(i, j, k + 1), n(i + 1, j, k + 1), n(i + 1, j + 1, k + 1), + n(i, j, k), n(i + 1, j + 1, k), n(i, j + 1, k), + n(i, j, k + 1), n(i + 1, j + 1, k + 1), n(i, j + 1, k + 1)}; + for (int a = 0; a < 12; a++) conn[m++] = p[a]; + } + section("PrismElements", CGNS_ENUMV(PENTA_6), nPrism); + + /*--- Boundary sections, the ones of one BC are next to each other. ---*/ + cgsize_t first, mid; + + m = 0; + for (int k = 0; k < NK - 1; k++) + for (int j = 0; j < NJ - 1; j++) { + cgsize_t q[4] = {n(0, j, k), n(0, j, k + 1), n(0, j + 1, k + 1), n(0, j + 1, k)}; + for (int a = 0; a < 4; a++) conn[m++] = q[a]; + } + section("inlet", CGNS_ENUMV(QUAD_4), m / 4); + + m = 0; + for (int k = 0; k < NK - 1; k++) + for (int j = 0; j < NJ - 1; j++) { + cgsize_t q[4] = {n(NI - 1, j, k), n(NI - 1, j + 1, k), n(NI - 1, j + 1, k + 1), n(NI - 1, j, k + 1)}; + for (int a = 0; a < 4; a++) conn[m++] = q[a]; + } + first = section("outlet", CGNS_ENUMV(QUAD_4), m / 4); + bc("outlet", "outlet", CGNS_ENUMV(BCOutflow), first, next - 1); + + for (int part = 0; part < 2; part++) { + m = 0; + for (int k = 0; k < NK - 1; k++) + for (int i = part ? NH : 0; i < (part ? NI - 1 : NH); i++) { + cgsize_t q[4] = {n(i, 0, k), n(i + 1, 0, k), n(i + 1, 0, k + 1), n(i, 0, k + 1)}; + for (int a = 0; a < 4; a++) conn[m++] = q[a]; + } + mid = section(part ? "lower_2" : "lower_1", CGNS_ENUMV(QUAD_4), m / 4); + if (!part) first = mid; + } + bc("lower_wall", "lower", CGNS_ENUMV(BCWallInviscid), first, next - 1); + + m = 0; + for (int k = 0; k < NK - 1; k++) + for (int i = 0; i < NI - 1; i++) { + cgsize_t q[4] = {n(i, NJ - 1, k), n(i, NJ - 1, k + 1), n(i + 1, NJ - 1, k + 1), n(i + 1, NJ - 1, k)}; + for (int a = 0; a < 4; a++) conn[m++] = q[a]; + } + first = section("upper_side", CGNS_ENUMV(QUAD_4), m / 4); + bc("upper", NULL, CGNS_ENUMV(BCWallInviscid), first, next - 1); + + for (int side = 0; side < 2; side++) { + const int k = side ? NK - 1 : 0; + m = 0; + for (int j = 0; j < NJ - 1; j++) + for (int i = 0; i < NH; i++) { + cgsize_t q[4] = {n(i, j, k), n(i + 1, j, k), n(i + 1, j + 1, k), n(i, j + 1, k)}; + for (int a = 0; a < 4; a++) conn[m++] = q[a]; + } + first = section(side ? "quad_front" : "quad_back", CGNS_ENUMV(QUAD_4), m / 4); + m = 0; + for (int j = 0; j < NJ - 1; j++) + for (int i = NH; i < NI - 1; i++) { + cgsize_t t[6] = {n(i, j, k), n(i + 1, j, k), n(i + 1, j + 1, k), n(i, j, k), n(i + 1, j + 1, k), n(i, j + 1, k)}; + for (int a = 0; a < 6; a++) conn[m++] = t[a]; + } + section(side ? "tri_front" : "tri_back", CGNS_ENUMV(TRI_3), m / 3); + bc(side ? "front" : "back", side ? "front" : "back", CGNS_ENUMV(BCSymmetryPlane), first, next - 1); + } + + CHK(cg_close(fn)); + printf("Wrote %s: %d hexahedra, %d prisms, %ld elements.\n", file, nHex, nPrism, (long)(next - 1)); + return 0; +} diff --git a/cgns_reader/mesh_channel_sections.cgns b/cgns_reader/mesh_channel_sections.cgns new file mode 100644 index 0000000000000000000000000000000000000000..17a4745c0613461646388ee037c06aa1192269e3 GIT binary patch literal 62611 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