From 0b3afbd5b91c38f0c30b8f245e8d4ace0b4cda7d Mon Sep 17 00:00:00 2001 From: Jim Schaff Date: Mon, 24 Aug 2026 00:42:35 -0400 Subject: [PATCH 1/2] test(geometry): add real corpus models as Geometry_IT fixtures Generated on the golden base branch, against the pre-change implementation (f35beaddcd), per the workflow this suite documents. Cherry-picked onto master separately so the goldens provably predate the code they check. Six stored models from the VCML test corpus, spanning 0.47-3.96 MP, 2D and 3D, cubic through to a 2151x504 slab. They earn their place by being irregular in ways the synthetic fixtures are not -- thin features, awkward aspect ratios, and disconnected regions sharing a pixel value. corpus_95707047_208x153x83 alone yields SIX regions from TWO pixel classes, five separate cytosol bodies, which nothing in the synthetic set produces. They deliberately REBUILD surfaces rather than pinning what the document already carries. A stored model has a , XmlReader applies it, and precomputeAll therefore skips updateAll() on parse -- so the geometry arrives with regions restored from the file rather than computed. Pinning those would test the XML reader instead of surface generation, which is the opposite of the point. fromCorpus() calls updateAll() to force a fresh RegionImage and SurfaceCollection. Kept in their own group and class so the fast lane stays fast. Worth being straight about the naming though: at 2.87 s for all six they are not actually slow, and could sit in Fast if running on every push is preferred over running only in the regression lane. The separation is mainly headroom -- they depend on corpus resources and the obvious way to extend them is to add more models. Also splits golden regeneration so iterating on the synthetic fixtures does not silently leave the corpus goldens stale or spend minutes rebuilding them: GeometrySurfaceGolden.main with no argument does both, with 'fast' does only the synthetic set. The comparison logic is now shared rather than duplicated between the two test classes, including the everyFixtureHasAGolden guard -- a @TestFactory whose resources went missing would otherwise just produce fewer tests and stay green. Pre-merge verification: GeometrySurfaceRegressionTest 7/7 (0.42 s), GeometrySurfaceCorpusRegressionTest 7/7 (2.87 s). Refs #2021, #2025, #2028 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018kr8SbzXtwW3gMVUgMfDDt --- .../GeometrySurfaceCorpusRegressionTest.java | 40 +++++++++ .../vcell/geometry/GeometrySurfaceGolden.java | 82 +++++++++++++++++-- .../GeometrySurfaceRegressionTest.java | 34 +++++--- .../vcell/geometry/surface-golden/README.md | 27 ++++++ .../corpus_12522025_2151x504_2d.txt | 32 ++++++++ .../corpus_201022999_211x201x11.txt | 28 +++++++ .../corpus_209284198_600x300x22.txt | 34 ++++++++ .../corpus_26454463_564x160x31.txt | 28 +++++++ .../corpus_65311813_256x256x34.txt | 34 ++++++++ .../corpus_95707047_208x153x83.txt | 44 ++++++++++ 10 files changed, 365 insertions(+), 18 deletions(-) create mode 100644 vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceCorpusRegressionTest.java create mode 100644 vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_12522025_2151x504_2d.txt create mode 100644 vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_201022999_211x201x11.txt create mode 100644 vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_209284198_600x300x22.txt create mode 100644 vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_26454463_564x160x31.txt create mode 100644 vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_65311813_256x256x34.txt create mode 100644 vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_95707047_208x153x83.txt diff --git a/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceCorpusRegressionTest.java b/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceCorpusRegressionTest.java new file mode 100644 index 0000000000..1829a61716 --- /dev/null +++ b/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceCorpusRegressionTest.java @@ -0,0 +1,40 @@ +package cbit.vcell.geometry; + +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; + +import java.util.List; + +/** + * The same golden comparison as {@link GeometrySurfaceRegressionTest}, over REAL stored models from + * the VCML test corpus rather than synthetic shapes. + * + * Separate class and separate group because these parse multi-megabyte documents and rebuild + * regions and surfaces over 0.5-4 MP images. They belong in {@code Geometry_IT}, which + * regression.yml runs, rather than in the fast lane on every push. + * + * They earn their place by being irregular in ways synthetic fixtures are not. The synthetic set is + * spheres, shells and stripes; a real segmentation has thin features, awkward aspect ratios and + * disconnected regions sharing a pixel value. {@code corpus_95707047_208x153x83} alone yields SIX + * regions from TWO pixel classes -- five separate cytosol bodies -- which no synthetic fixture here + * produces. + * + * Note these deliberately REBUILD surfaces rather than reading the stored {@code + * }; see {@code GeometrySurfaceGolden.fromCorpus}. Pinning the stored values + * would test the XML reader instead of surface generation. + */ +@Tag("Geometry_IT") +public class GeometrySurfaceCorpusRegressionTest { + + @TestFactory + public List corpusSurfaceDescriptionsMatchTheDeployedImplementation() { + return GeometrySurfaceRegressionTest.testsFor(GeometrySurfaceGolden.corpusFixtures()); + } + + @Test + public void everyCorpusFixtureHasAGolden() { + GeometrySurfaceRegressionTest.assertEveryFixtureHasAGolden(GeometrySurfaceGolden.corpusFixtures()); + } +} diff --git a/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceGolden.java b/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceGolden.java index ef692204d1..f4c9b443d7 100644 --- a/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceGolden.java +++ b/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceGolden.java @@ -11,7 +11,12 @@ import cbit.vcell.geometry.surface.SurfaceCollection; import cbit.vcell.geometry.surface.SurfaceGeometricRegion; import cbit.vcell.geometry.surface.VolumeGeometricRegion; +import cbit.vcell.biomodel.BioModel; +import cbit.vcell.mapping.SimulationContext; import cbit.vcell.parser.Expression; +import cbit.vcell.xml.XMLSource; +import cbit.vcell.xml.XmlHelper; +import org.vcell.sbml.VcmlTestSuiteFiles; import org.vcell.util.Extent; import org.vcell.util.ISize; import org.vcell.util.Origin; @@ -79,6 +84,54 @@ public static Map fixtures() { return map; } + /** + * Real stored models from the VCML test corpus, kept separate from {@link #fixtures()} because + * they are far slower: each parses a multi-megabyte document and then builds regions and + * surfaces over a 0.5-4 MP image. They run in the {@code Geometry_IT} regression group, not in + * {@code Fast}. + * + * They are worth the time because synthetic fixtures are made of spheres, shells and stripes. + * Real segmentations are irregular, have thin features and awkward aspect ratios, and are the + * shapes that actually broke things. The selection spans 0.47-3.96 MP, 2D and 3D, cubic through + * to a 2151x504 slab. + */ + public static Map corpusFixtures() { + Map map = new LinkedHashMap<>(); + map.put("corpus_209284198_600x300x22", () -> fromCorpus("biomodel_209284198.vcml")); + map.put("corpus_26454463_564x160x31", () -> fromCorpus("biomodel_26454463.vcml")); + map.put("corpus_95707047_208x153x83", () -> fromCorpus("biomodel_95707047.vcml")); + map.put("corpus_65311813_256x256x34", () -> fromCorpus("biomodel_65311813.vcml")); + map.put("corpus_12522025_2151x504_2d", () -> fromCorpus("biomodel_12522025_spatial.vcml")); + map.put("corpus_201022999_211x201x11", () -> fromCorpus("biomodel_201022999.vcml")); + return map; + } + + /** + * The first spatial image geometry in a stored BioModel, with its surfaces REBUILT. + * + * Rebuilding matters. A stored document carries a {@code }, and XmlReader + * applies it, so {@code precomputeAll} skips {@code updateAll()} on parse and the geometry + * arrives with regions restored from the file rather than computed. Pinning that would test the + * XML reader, not surface generation. Calling {@code updateAll()} here forces a fresh + * RegionImage and SurfaceCollection, which is the thing under test. + */ + private static Geometry fromCorpus(String vcmlFile) throws Exception { + String vcml; + try (java.io.InputStream in = VcmlTestSuiteFiles.getVcmlTestCase(vcmlFile)) { + vcml = new String(in.readAllBytes(), StandardCharsets.UTF_8); + } + BioModel bioModel = XmlHelper.XMLToBioModel(new XMLSource(vcml)); + for (SimulationContext simContext : bioModel.getSimulationContexts()) { + Geometry geometry = simContext.getGeometry(); + if (geometry != null && geometry.getDimension() > 0 + && geometry.getGeometrySpec().getImage() != null) { + geometry.getGeometrySurfaceDescription().updateAll(); + return geometry; + } + } + throw new IllegalStateException("no spatial image geometry in " + vcmlFile); + } + public interface GeometryFactory { Geometry create() throws Exception; } @@ -454,17 +507,36 @@ public static Path goldenPath(String fixture) { return goldenDir().resolve(fixture + ".txt"); } - /** Writes every fixture's description to the golden directory. */ - public static void writeGoldens() throws Exception { + /** + * Writes every fixture's description to the golden directory. + * + * @param includeCorpus also regenerate the slow corpus goldens. Off by default when a single + * argument "fast" is given, so a quick iteration on the synthetic fixtures + * does not silently leave the corpus goldens stale or spend minutes + * rebuilding them. + */ + public static void writeGoldens(boolean includeCorpus) throws Exception { Files.createDirectories(goldenDir()); - for (Map.Entry e : fixtures().entrySet()) { + writeSet(fixtures(), "fast"); + if (includeCorpus) { + writeSet(corpusFixtures(), "corpus"); + } else { + System.out.println("skipped corpus fixtures (pass 'all' to regenerate them)"); + } + } + + private static void writeSet(Map set, String label) throws Exception { + for (Map.Entry e : set.entrySet()) { + long t0 = System.currentTimeMillis(); String text = describe(e.getValue().create()); Files.writeString(goldenPath(e.getKey()), text, StandardCharsets.UTF_8); - System.out.printf("wrote %-38s %d bytes%n", e.getKey(), text.length()); + System.out.printf("wrote [%s] %-34s %5d bytes %6d ms%n", + label, e.getKey(), text.length(), System.currentTimeMillis() - t0); } } public static void main(String[] args) throws Exception { - writeGoldens(); + boolean includeCorpus = args.length == 0 || !"fast".equalsIgnoreCase(args[0]); + writeGoldens(includeCorpus); } } diff --git a/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceRegressionTest.java b/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceRegressionTest.java index 1c6fc21c03..bf42164381 100644 --- a/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceRegressionTest.java +++ b/vcell-core/src/test/java/cbit/vcell/geometry/GeometrySurfaceRegressionTest.java @@ -37,13 +37,17 @@ @Tag("Fast") public class GeometrySurfaceRegressionTest { - private static final String RESOURCE_DIR = "/cbit/vcell/geometry/surface-golden/"; + static final String RESOURCE_DIR = "/cbit/vcell/geometry/surface-golden/"; @TestFactory public List surfaceDescriptionsMatchTheDeployedImplementation() { + return testsFor(GeometrySurfaceGolden.fixtures()); + } + + /** Shared with {@link GeometrySurfaceCorpusRegressionTest}; the comparison is identical. */ + static List testsFor(Map fixtures) { List tests = new ArrayList<>(); - for (Map.Entry entry - : GeometrySurfaceGolden.fixtures().entrySet()) { + for (Map.Entry entry : fixtures.entrySet()) { String fixture = entry.getKey(); tests.add(DynamicTest.dynamicTest(fixture, () -> { String expected = readGolden(fixture); @@ -54,24 +58,28 @@ public List surfaceDescriptionsMatchTheDeployedImplementation() { return tests; } - /** - * Guards the guard. If a fixture is added without a golden, or a golden goes missing, the - * factory above would simply produce fewer tests and the suite would still be green. - */ - @Test - public void everyFixtureHasAGolden() { + static void assertEveryFixtureHasAGolden(Map fixtures) { List missing = new ArrayList<>(); - for (String fixture : GeometrySurfaceGolden.fixtures().keySet()) { + for (String fixture : fixtures.keySet()) { if (GeometrySurfaceRegressionTest.class.getResourceAsStream(RESOURCE_DIR + fixture + ".txt") == null) { missing.add(fixture); } } assertTrue(missing.isEmpty(), "fixtures with no committed golden (run GeometrySurfaceGolden.main): " + missing); - assertFalse(GeometrySurfaceGolden.fixtures().isEmpty(), "there must be fixtures to compare"); + assertFalse(fixtures.isEmpty(), "there must be fixtures to compare"); + } + + /** + * Guards the guard. If a fixture is added without a golden, or a golden goes missing, the + * factory above would simply produce fewer tests and the suite would still be green. + */ + @Test + public void everyFixtureHasAGolden() { + assertEveryFixtureHasAGolden(GeometrySurfaceGolden.fixtures()); } - private static String readGolden(String fixture) throws Exception { + static String readGolden(String fixture) throws Exception { try (InputStream in = GeometrySurfaceRegressionTest.class .getResourceAsStream(RESOURCE_DIR + fixture + ".txt")) { assertNotNull(in, "no golden for fixture '" + fixture + "'"); @@ -83,7 +91,7 @@ private static String readGolden(String fixture) throws Exception { * A readable report. assertEquals on two multi-line blocks prints both in full and leaves the * reader to find the difference; surface descriptions are long enough that this matters. */ - private static String describeDifference(String fixture, String expected, String actual) { + static String describeDifference(String fixture, String expected, String actual) { String[] want = expected.split("\n", -1); String[] got = actual.split("\n", -1); StringBuilder sb = new StringBuilder(); diff --git a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/README.md b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/README.md index d690d8c291..a95528740d 100644 --- a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/README.md +++ b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/README.md @@ -8,6 +8,27 @@ They exist because VCell's regression suites are math-generation centric and mos Nothing else pins `RegionImage` or `SurfaceCollection`, so a change to region finding, surface tessellation, Taubin smoothing or membrane adjacency could alter every spatial model silently. +## Two sets + +| prefix | fixtures | group | runtime | +|---|---|---|---| +| `image*` / `analytic*` | synthetic shapes — spheres, shells, stripes, an analytic subvolume | `Fast` | 0.42 s | +| `corpus_*` | real stored models from the VCML test corpus, 0.47–3.96 MP | `Geometry_IT` | 2.87 s | + +The corpus set earns its place by being irregular in ways synthetic shapes are not: thin features, +awkward aspect ratios, and disconnected regions sharing a pixel value. +`corpus_95707047_208x153x83` yields **six regions from two pixel classes** — five separate cytosol +bodies — which nothing in the synthetic set produces. + +They deliberately **rebuild** surfaces rather than reading the stored `` out of +the document. XmlReader applies that element on parse, so `precomputeAll` skips `updateAll()` and +the geometry arrives with regions restored from the file; pinning those would test the XML reader +rather than surface generation. + +At 2.87 s the corpus set is not actually slow, and could live in `Fast` if you would rather it ran +on every push instead of only in the regression lane. It is separate mainly for headroom — it +depends on the corpus resources, and the natural way to extend it is to add more models. + ## Where these came from, and why it matters **Generated on `f35beaddcd`** — master as it stood before the #2026 / #2027 memory work. They record @@ -61,8 +82,14 @@ An intentional improvement will fail these tests — that is correct, not a nuis deliberately: ```bash +# both sets mvn -q -pl vcell-core exec:java -Dexec.classpathScope=test \ -Dexec.mainClass=cbit.vcell.geometry.GeometrySurfaceGolden + +# synthetic only, when iterating (leaves corpus goldens untouched) +mvn -q -pl vcell-core exec:java -Dexec.classpathScope=test \ + -Dexec.mainClass=cbit.vcell.geometry.GeometrySurfaceGolden -Dexec.args=fast + git diff -- vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden ``` diff --git a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_12522025_2151x504_2d.txt b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_12522025_2151x504_2d.txt new file mode 100644 index 0000000000..139aadff78 --- /dev/null +++ b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_12522025_2151x504_2d.txt @@ -0,0 +1,32 @@ +geometry purk-neck3 dimension=2 +extent 27.921000000 6.542000000 1.000000000 +origin 0.000000000 0.000000000 0.000000000 +image 2151x504x1 pixelClasses=2 pixelsSHA=a8d98c9564617179cf5ee751 +subVolumes 2 + subVolume cytosol(handle=1) + subVolume extracellular(handle=0) +sampleSize 208x48x1 +cutoffFrequency 0.300000000 +regionImage regions=3 dims=208x48x1 +regionImage.pixelPartition sumOfRegions=9984 totalPixels=9984 complete=true + region index=0 pixelValue=0 numPixels=1969 + region index=1 pixelValue=1 numPixels=5968 + region index=2 pixelValue=0 numPixels=2047 +regionImage.encodedRegionIndexSHA d406b42537b7931045e2d2c7 +surfaceCollection surfaces=2 nodes=4166 + nodeBounds x=[0.000000000,27.921000000] y=[0.078249924,6.325590769] z=[0.000000000,1.000000000] + nodeCoordsSHA b3737fb395aae69f47bc3e90 + surface[0] interiorRegion=0 exteriorRegion=1 polygons=1036 area=102.049107892 + surface[1] interiorRegion=1 exteriorRegion=2 polygons=1045 area=101.359268590 + polygonNodeIndicesSHA a537270eb94537957e13088d + polygonVolumeNeighborsSHA 3cc17d70634baa3d999b2750 + totalArea 203.408376482 + membraneEdgeNeighbors total=8324 SHA=5d322119221f508ab3c78b2f +geometricRegions 5 + surface membrane_cytosol1_extracellular2 size=101.359268590 adjacent=[cytosol1, extracellular2] + surface membrane_extracellular0_cytosol1 size=102.049107892 adjacent=[cytosol1, extracellular0] + volume cytosol1 size=111.681379805 adjacent=[membrane_cytosol1_extracellular2, membrane_extracellular0_cytosol1] + volume extracellular0 size=34.723831546 adjacent=[membrane_extracellular0_cytosol1] + volume extracellular2 size=36.253970649 adjacent=[membrane_cytosol1_extracellular2] +surfaceClasses 1 + cytosol_extracellular_membrane adjacent=[cytosol, extracellular] diff --git a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_201022999_211x201x11.txt b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_201022999_211x201x11.txt new file mode 100644 index 0000000000..177c058ce7 --- /dev/null +++ b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_201022999_211x201x11.txt @@ -0,0 +1,28 @@ +geometry geom_20190115_151208 dimension=3 +extent 0.220000000 0.210000000 0.220000000 +origin 0.000000000 0.000000000 0.000000000 +image 211x201x11 pixelClasses=2 pixelsSHA=be54e3ae7a595731d630f355 +subVolumes 2 + subVolume MIM(handle=0) + subVolume Matrix(handle=1) +sampleSize 211x201x11 +cutoffFrequency 0.300000000 +regionImage regions=2 dims=211x201x11 +regionImage.pixelPartition sumOfRegions=466521 totalPixels=466521 complete=true + region index=0 pixelValue=0 numPixels=258473 + region index=1 pixelValue=1 numPixels=208048 +regionImage.encodedRegionIndexSHA 9e39b8622c6c82f5fed7aa6c +surfaceCollection surfaces=1 nodes=160488 + nodeBounds x=[0.018825469,0.199874502] y=[0.019426030,0.190573970] z=[0.011000000,0.209000000] + nodeCoordsSHA 25292c76b6267950cb3bc87a + surface[0] interiorRegion=0 exteriorRegion=1 polygons=160486 area=0.371065484 + polygonNodeIndicesSHA 224d75136e1ca6645e26af80 + polygonVolumeNeighborsSHA 147adf43e95c953596223842 + totalArea 0.371065484 + membraneEdgeNeighbors total=641944 SHA=49b8a287979823cb4889cb01 +geometricRegions 3 + surface membrane_MIM0_Matrix1 size=0.371065484 adjacent=[MIM0, Matrix1] + volume MIM0 size=0.005129238 adjacent=[membrane_MIM0_Matrix1] + volume Matrix1 size=0.005034762 adjacent=[membrane_MIM0_Matrix1] +surfaceClasses 1 + MIM_Matrix_membrane adjacent=[MIM, Matrix] diff --git a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_209284198_600x300x22.txt b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_209284198_600x300x22.txt new file mode 100644 index 0000000000..2b5f0c093f --- /dev/null +++ b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_209284198_600x300x22.txt @@ -0,0 +1,34 @@ +geometry AliciaSpacial dimension=3 +extent 30.000000000 15.000000000 11.000000000 +origin 0.000000000 0.000000000 0.000000000 +image 600x300x22 pixelClasses=3 pixelsSHA=dc7477deaa8eb18fc9810237 +subVolumes 3 + subVolume region0(handle=2) + subVolume region1(handle=0) + subVolume region2(handle=1) +sampleSize 89x44x32 +cutoffFrequency 0.310000000 +regionImage regions=3 dims=89x44x32 +regionImage.pixelPartition sumOfRegions=125312 totalPixels=125312 complete=true + region index=0 pixelValue=2 numPixels=92423 + region index=1 pixelValue=0 numPixels=27384 + region index=2 pixelValue=1 numPixels=5505 +regionImage.encodedRegionIndexSHA 80c635480536d32ad1a5246d +surfaceCollection surfaces=2 nodes=10866 + nodeBounds x=[1.957006540,28.328177211] y=[1.920147696,13.010861278] z=[0.177419355,10.112903226] + nodeCoordsSHA 7efbd2d76f99c925445e0791 + surface[0] interiorRegion=0 exteriorRegion=1 polygons=8564 area=753.088014302 + surface[1] interiorRegion=1 exteriorRegion=2 polygons=2298 area=182.204229947 + polygonNodeIndicesSHA a9ac9c28488a361805f793c3 + polygonVolumeNeighborsSHA 21d7fa5cd23dd59837b7e652 + totalArea 935.292244249 + membraneEdgeNeighbors total=43448 SHA=520086290c17ce55723d7fd0 +geometricRegions 5 + surface membrane_region00_region11 size=753.088014302 adjacent=[region00, region11] + surface membrane_region11_region22 size=182.204229947 adjacent=[region11, region22] + volume region00 size=3562.148349587 adjacent=[membrane_region00_region11] + volume region11 size=1155.551387847 adjacent=[membrane_region00_region11, membrane_region11_region22] + volume region22 size=232.300262566 adjacent=[membrane_region11_region22] +surfaceClasses 2 + region0_region1_membrane adjacent=[region0, region1] + region1_region2_membrane adjacent=[region1, region2] diff --git a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_26454463_564x160x31.txt b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_26454463_564x160x31.txt new file mode 100644 index 0000000000..1a8409d2e2 --- /dev/null +++ b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_26454463_564x160x31.txt @@ -0,0 +1,28 @@ +geometry purkinge9_3D_crop526692774 dimension=3 +extent 27.900000000 6.500000000 6.500000000 +origin 0.000000000 0.000000000 0.000000000 +image 564x160x31 pixelClasses=2 pixelsSHA=0b18fca988bdf98b69e6c463 +subVolumes 2 + subVolume Cytpolasm(handle=1) + subVolume ExtraCellular(handle=0) +sampleSize 564x160x31 +cutoffFrequency 0.300000000 +regionImage regions=2 dims=564x160x31 +regionImage.pixelPartition sumOfRegions=2797440 totalPixels=2797440 complete=true + region index=0 pixelValue=0 numPixels=2461849 + region index=1 pixelValue=1 numPixels=335591 +regionImage.encodedRegionIndexSHA 218d27b0d5da8880bbe52a42 +surfaceCollection surfaces=1 nodes=147972 + nodeBounds x=[0.000000000,27.900000000] y=[0.616909236,5.842413664] z=[0.120480695,6.379519305] + nodeCoordsSHA 997676dce7f7860c4f088cdc + surface[0] interiorRegion=0 exteriorRegion=1 polygons=147778 area=426.276671989 + polygonNodeIndicesSHA ae9c379c26bf826773055587 + polygonVolumeNeighborsSHA 90ba4516e7e5d4e95eb00560 + totalArea 426.276671989 + membraneEdgeNeighbors total=591112 SHA=a1e5173060d1cbdc642ca292 +geometricRegions 3 + surface membrane_ExtraCellular0_Cytpolasm1 size=426.276671989 adjacent=[Cytpolasm1, ExtraCellular0] + volume Cytpolasm1 size=147.031387614 adjacent=[membrane_ExtraCellular0_Cytpolasm1] + volume ExtraCellular0 size=1031.743612386 adjacent=[membrane_ExtraCellular0_Cytpolasm1] +surfaceClasses 1 + Cytpolasm_ExtraCellular_membrane adjacent=[Cytpolasm, ExtraCellular] diff --git a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_65311813_256x256x34.txt b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_65311813_256x256x34.txt new file mode 100644 index 0000000000..33abf5bb68 --- /dev/null +++ b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_65311813_256x256x34.txt @@ -0,0 +1,34 @@ +geometry Membrane Frap_3d image_20110908_141413 dimension=3 +extent 74.240000000 74.240000000 26.000000000 +origin 0.000000000 0.000000000 0.000000000 +image 256x256x34 pixelClasses=3 pixelsSHA=140e740e3d0e52f757ffd0a4 +subVolumes 3 + subVolume PixelClass1(handle=0) + subVolume PixelClass2(handle=1) + subVolume PixelClass3(handle=2) +sampleSize 256x256x34 +cutoffFrequency 0.300000000 +regionImage regions=3 dims=256x256x34 +regionImage.pixelPartition sumOfRegions=2228224 totalPixels=2228224 complete=true + region index=0 pixelValue=0 numPixels=1949790 + region index=1 pixelValue=1 numPixels=223074 + region index=2 pixelValue=2 numPixels=55360 +regionImage.encodedRegionIndexSHA 538de21da8b8acd524c78005 +surfaceCollection surfaces=2 nodes=68307 + nodeBounds x=[4.668735837,64.246521675] y=[0.000000000,74.240000000] z=[1.181818182,25.606060606] + nodeCoordsSHA 5a450db595f37b2d3e34ba8a + surface[0] interiorRegion=0 exteriorRegion=1 polygons=52794 area=4738.640600365 + surface[1] interiorRegion=1 exteriorRegion=2 polygons=15496 area=1406.773369249 + polygonNodeIndicesSHA f979ca9c950471210d9cbbf8 + polygonVolumeNeighborsSHA c3687bd4de6cbab5380b3721 + totalArea 6145.413969614 + membraneEdgeNeighbors total=273160 SHA=cd0a449f0b28fbee66360016 +geometricRegions 5 + surface membrane_PixelClass10_PixelClass21 size=4738.640600365 adjacent=[PixelClass10, PixelClass21] + surface membrane_PixelClass21_PixelClass32 size=1406.773369249 adjacent=[PixelClass21, PixelClass32] + volume PixelClass10 size=124712.104359616 adjacent=[membrane_PixelClass10_PixelClass21] + volume PixelClass21 size=14891.899581612 adjacent=[membrane_PixelClass10_PixelClass21, membrane_PixelClass21_PixelClass32] + volume PixelClass32 size=3697.013658773 adjacent=[membrane_PixelClass21_PixelClass32] +surfaceClasses 2 + PixelClass1_PixelClass2_membrane adjacent=[PixelClass1, PixelClass2] + PixelClass2_PixelClass3_membrane adjacent=[PixelClass2, PixelClass3] diff --git a/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_95707047_208x153x83.txt b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_95707047_208x153x83.txt new file mode 100644 index 0000000000..66e5c3a8a2 --- /dev/null +++ b/vcell-core/src/test/resources/cbit/vcell/geometry/surface-golden/corpus_95707047_208x153x83.txt @@ -0,0 +1,44 @@ +geometry geom_20150608_114218 dimension=3 +extent 1.040000000 0.765000000 0.415000000 +origin 0.000000000 0.000000000 0.000000000 +image 208x153x83 pixelClasses=2 pixelsSHA=26a444a42c8219647327dbbd +subVolumes 2 + subVolume cytosol(handle=0) + subVolume rest(handle=1) +sampleSize 208x153x83 +cutoffFrequency 0.300000000 +regionImage regions=6 dims=208x153x83 +regionImage.pixelPartition sumOfRegions=2641392 totalPixels=2641392 complete=true + region index=0 pixelValue=0 numPixels=2310441 + region index=1 pixelValue=1 numPixels=39648 + region index=2 pixelValue=1 numPixels=89971 + region index=3 pixelValue=1 numPixels=35997 + region index=4 pixelValue=1 numPixels=53256 + region index=5 pixelValue=1 numPixels=112079 +regionImage.encodedRegionIndexSHA 2677caf3dbf3eeb38453cb38 +surfaceCollection surfaces=5 nodes=111100 + nodeBounds x=[0.009444670,1.031396273] y=[0.002516447,0.762483553] z=[0.005128112,0.407408537] + nodeCoordsSHA ed5e244bb0fe0991cc831710 + surface[0] interiorRegion=0 exteriorRegion=1 polygons=11178 area=0.189490647 + surface[1] interiorRegion=0 exteriorRegion=2 polygons=56994 area=0.951515636 + surface[2] interiorRegion=0 exteriorRegion=3 polygons=13664 area=0.233059999 + surface[3] interiorRegion=0 exteriorRegion=4 polygons=10682 area=0.197536300 + surface[4] interiorRegion=0 exteriorRegion=5 polygons=18622 area=0.360256108 + polygonNodeIndicesSHA 4a372b2f8c7c57f9f3d8f7d2 + polygonVolumeNeighborsSHA db0a0d372ef39c95252de2f1 + totalArea 1.931858690 + membraneEdgeNeighbors total=444560 SHA=3987bbbbc675f3c5e5a74657 +geometricRegions 11 + surface membrane_cytosol0_rest1 size=0.189490647 adjacent=[cytosol0, rest1] + surface membrane_cytosol0_rest2 size=0.951515636 adjacent=[cytosol0, rest2] + surface membrane_cytosol0_rest3 size=0.233059999 adjacent=[cytosol0, rest3] + surface membrane_cytosol0_rest4 size=0.197536300 adjacent=[cytosol0, rest4] + surface membrane_cytosol0_rest5 size=0.360256108 adjacent=[cytosol0, rest5] + volume cytosol0 size=0.287821526 adjacent=[membrane_cytosol0_rest1, membrane_cytosol0_rest2, membrane_cytosol0_rest3, membrane_cytosol0_rest4, membrane_cytosol0_rest5] + volume rest1 size=0.005073835 adjacent=[membrane_cytosol0_rest1] + volume rest2 size=0.011513772 adjacent=[membrane_cytosol0_rest2] + volume rest3 size=0.004606609 adjacent=[membrane_cytosol0_rest3] + volume rest4 size=0.006815279 adjacent=[membrane_cytosol0_rest4] + volume rest5 size=0.014342978 adjacent=[membrane_cytosol0_rest5] +surfaceClasses 1 + cytosol_rest_membrane adjacent=[cytosol, rest] From 321a19002eba91668b8a75b4275a139803ce4e71 Mon Sep 17 00:00:00 2001 From: Jim Schaff Date: Mon, 24 Aug 2026 01:30:31 -0400 Subject: [PATCH 2/2] ci(regression): run the Geometry_IT group Without this the corpus goldens compile and never execute in CI -- regression.yml drives its matrix from an explicit group table, so a tag that is not listed there is simply never selected. One shard; the whole group is ~3 s of tests on top of the ~4 min compile floor every shard already pays. Verified by executing the workflow's embedded matrix script directly rather than trusting the edit: 16 entries across 7 groups, with Geometry_IT present as a single shard scoped to vcell-core. The YAML parses. Refs #2021, #2028 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018kr8SbzXtwW3gMVUgMfDDt --- .github/workflows/regression.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index 57e071cf9c..c8b2d231a6 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -99,6 +99,11 @@ jobs: "SEDML_SBML_IT": {"count": 6, "module": CORE}, "SEDML_VCML_IT": {"count": 2, "module": CORE}, "SBML_IT": {"count": 1, "module": CORE}, + # Geometry surface goldens over real corpus models. Not a model-suite + # sweep and not slow (~3 s); it lives here rather than in the fast lane + # because it depends on the VCML corpus resources and the natural way to + # extend it is to add more models. See the README beside the goldens. + "Geometry_IT": {"count": 1, "module": CORE}, "BSTS_IT": {"count": 1, "module": "vcell-cli"}, # Not a model-suite sweep: one Oracle container proving the database # cleanup sweep's SQL is accepted by the database it actually runs