This commit uses global pre allocated work space to dramatically reduce memory usage and allocation time
97 lines
4.2 KiB
Python
97 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Refine a saved STROID mesh once, retaining the original and provenance.
|
|
|
|
Run with a Python environment containing the multiblock-capable STROID build.
|
|
The output is a complete, already-refined mesh: pass it to the validation
|
|
experiment without any further refinement, including during saved-field replay.
|
|
"""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
import stroid
|
|
from stroid import _stroid
|
|
from stroid.IO import LoadStroidMesh, SaveStroidMesh
|
|
from stroid.refinement import UniformRefinement
|
|
|
|
|
|
def digest(path):
|
|
with Path(path).open("rb") as stream:
|
|
return hashlib.file_digest(stream, "sha256").hexdigest()
|
|
|
|
|
|
def counts(mesh):
|
|
result = stroid.stats.ComputeMeshStats(
|
|
mesh, stroid.stats.MeshStatFeatures.ELEMENT_COUNT
|
|
).element_counts
|
|
return {name: getattr(result, name) for name in
|
|
("total", "core", "envelope", "vacuum", "other")}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("input", type=Path)
|
|
parser.add_argument("output_directory", type=Path,
|
|
help="New directory; existing directories are refused")
|
|
args = parser.parse_args()
|
|
source = args.input.resolve(strict=True)
|
|
original_digest = digest(source)
|
|
mesh = LoadStroidMesh(str(source))
|
|
if not hasattr(mesh.config, "core_mapping"):
|
|
raise RuntimeError("STROID is too old: no core_mapping support")
|
|
if not mesh.has_mesh() or not mesh.has_rmesh():
|
|
raise RuntimeError("Both physical and logical reference meshes are required")
|
|
before = counts(mesh)
|
|
initial_level = mesh.refinement_levels
|
|
mapping = mesh.config.core_mapping
|
|
order = mesh.config.order
|
|
args.output_directory.mkdir(exist_ok=False)
|
|
print(f"Loaded {mesh}; mapping={mapping}, geometry order={order}, "
|
|
f"stored refinement level={initial_level}", flush=True)
|
|
|
|
# This is an ADDITIONAL level on the loaded mesh, not regeneration from
|
|
# MeshConfig.refinement_levels. STROID rebuilds the high-order geometry.
|
|
UniformRefinement(mesh, 1)
|
|
|
|
after = counts(mesh)
|
|
if mesh.refinement_levels != initial_level + 1:
|
|
raise RuntimeError("STROID did not advance exactly one refinement level")
|
|
if any(after[name] != 8 * count for name, count in before.items()):
|
|
raise RuntimeError(f"Expected eight children per hex: {before} -> {after}")
|
|
if mesh.config.core_mapping != mapping or mesh.config.order != order:
|
|
raise RuntimeError("Refinement changed mapping strategy or geometry order")
|
|
target = args.output_directory / "refined.smesh"
|
|
SaveStroidMesh(mesh, str(target), "One additional UniformRefinement of " + str(source))
|
|
reloaded = LoadStroidMesh(str(target))
|
|
if counts(reloaded) != after or reloaded.refinement_levels != initial_level + 1:
|
|
raise RuntimeError("Saved refinement failed its load/metadata round trip")
|
|
if reloaded.config.core_mapping != mapping or reloaded.config.order != order:
|
|
raise RuntimeError("Saved refinement lost its mapping/order configuration")
|
|
if digest(source) != original_digest:
|
|
raise RuntimeError("Input mesh changed during the operation")
|
|
provenance = {
|
|
"source": str(source), "source_sha256": original_digest,
|
|
"refined_mesh": str(target.resolve()), "refined_sha256": digest(target),
|
|
"operation": "stroid.refinement.UniformRefinement(loaded_mesh, 1)",
|
|
"additional_levels": 1, "initial_level": initial_level,
|
|
"final_level": mesh.refinement_levels,
|
|
"geometry_order": order, "core_mapping": mapping,
|
|
"counts_before": before, "counts_after": after,
|
|
"python": sys.executable, "stroid_version": stroid.__version__,
|
|
"stroid_extension": _stroid.__file__,
|
|
"stroid_extension_sha256": digest(_stroid.__file__),
|
|
"geometry_policy": "STROID reprojects refined logical geometry; not fixed physical-polynomial subdivision",
|
|
"downstream_extra_refinements": 0,
|
|
}
|
|
with (args.output_directory / "refinement.json").open("x") as stream:
|
|
json.dump(provenance, stream, indent=2)
|
|
stream.write("\n")
|
|
print(f"Saved {mesh} to {target}; load with extra refinement=0", flush=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|