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 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]