modify documents
This commit is contained in:
@@ -19,6 +19,69 @@ def write_json(path: Path, payload: dict):
|
||||
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
||||
|
||||
|
||||
def write_text(path: Path, text: str = "ok\n"):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(text, encoding="utf-8")
|
||||
|
||||
|
||||
def ready_metadata(source_hash: str) -> dict:
|
||||
return {
|
||||
"schema_version": "abaqus-user-subroutine-artifact-v1",
|
||||
"feature_id": "umat",
|
||||
"model_id": "single-element",
|
||||
"artifact_status": "ready-for-comparison",
|
||||
"abaqus": {"version": "2024", "precision": "double"},
|
||||
"compiler": {"vendor": "Intel oneAPI", "name": "ifx", "version": "2024"},
|
||||
"subroutine": {
|
||||
"entry_points": ["UMAT"],
|
||||
"source_files": [
|
||||
{
|
||||
"path": "src/fortran/abaqus/UMAT.for",
|
||||
"language": "Fortran",
|
||||
"sha256": source_hash,
|
||||
}
|
||||
],
|
||||
},
|
||||
"input_file": "model.inp",
|
||||
"outputs": {
|
||||
"tails": {
|
||||
"msg": "job.msg.tail.txt",
|
||||
"dat": "job.dat.tail.txt",
|
||||
"log": "job.log.tail.txt",
|
||||
"sta": "job.sta.tail.txt",
|
||||
},
|
||||
"csv": {"stresses": "extracted/stresses.csv"},
|
||||
},
|
||||
"extraction": {
|
||||
"source_odb": "job.odb",
|
||||
"tool": "Abaqus Python",
|
||||
"extracted_at": "2026-06-10T00:00:00+09:00",
|
||||
"csv_directory": "extracted",
|
||||
"script": "extraction/extract_odb_to_csv.py",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def create_ready_bundle(root: Path) -> tuple[Path, dict]:
|
||||
source = root / "src" / "fortran" / "abaqus" / "UMAT.for"
|
||||
write_text(source, " subroutine umat()\n end\n")
|
||||
source_hash = hashlib.sha256(source.read_bytes()).hexdigest()
|
||||
|
||||
model_dir = root / "references" / "umat" / "single-element"
|
||||
for name in [
|
||||
"model.inp",
|
||||
"job.msg.tail.txt",
|
||||
"job.dat.tail.txt",
|
||||
"job.log.tail.txt",
|
||||
"job.sta.tail.txt",
|
||||
"extracted/stresses.csv",
|
||||
"extraction/extract_odb_to_csv.py",
|
||||
]:
|
||||
write_text(model_dir / name)
|
||||
|
||||
return model_dir, ready_metadata(source_hash)
|
||||
|
||||
|
||||
class ValidateReferenceArtifactsTests(unittest.TestCase):
|
||||
def test_missing_references_directory_is_valid(self):
|
||||
validator = load_validate_reference_artifacts()
|
||||
@@ -52,7 +115,7 @@ class ValidateReferenceArtifactsTests(unittest.TestCase):
|
||||
"feature_id": "umat",
|
||||
"model_id": "single-element",
|
||||
"artifact_status": "ready-for-comparison",
|
||||
"abaqus": {"version": "2024", "precision": "double", "command": "abaqus job=case user=UMAT.for"},
|
||||
"abaqus": {"version": "2024", "precision": "double"},
|
||||
"compiler": {"vendor": "Intel oneAPI", "name": "ifx", "version": "2024"},
|
||||
"subroutine": {
|
||||
"entry_points": ["UMAT"],
|
||||
@@ -61,7 +124,7 @@ class ValidateReferenceArtifactsTests(unittest.TestCase):
|
||||
"input_file": "model.inp",
|
||||
"outputs": {
|
||||
"tails": {"msg": "job.msg.tail.txt", "dat": "job.dat.tail.txt", "log": "job.log.tail.txt"},
|
||||
"csv": {"stresses": "stresses.csv"},
|
||||
"csv": {"stresses": "extracted/stresses.csv"},
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -69,53 +132,60 @@ class ValidateReferenceArtifactsTests(unittest.TestCase):
|
||||
errors = validator.validate_root(root)
|
||||
|
||||
self.assertTrue(any("missing input_file" in error for error in errors))
|
||||
self.assertTrue(any("missing output tail" in error for error in errors))
|
||||
self.assertTrue(any("missing output tail sta" in error for error in errors))
|
||||
self.assertTrue(any("missing ready-for-comparison key extraction" in error for error in errors))
|
||||
self.assertTrue(any("missing csv output" in error for error in errors))
|
||||
self.assertTrue(any("missing source file" in error for error in errors))
|
||||
|
||||
def test_ready_for_comparison_accepts_external_bundle_without_abaqus_command(self):
|
||||
validator = load_validate_reference_artifacts()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
model_dir, payload = create_ready_bundle(root)
|
||||
payload["extraction"]["odb_sha256_file"] = "result.odb.sha256"
|
||||
write_text(model_dir / "result.odb.sha256", "0" * 64 + " job.odb\n")
|
||||
write_json(model_dir / "metadata.json", payload)
|
||||
|
||||
self.assertEqual(validator.validate_root(root), [])
|
||||
|
||||
def test_ready_for_comparison_checks_source_sha256(self):
|
||||
validator = load_validate_reference_artifacts()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
source = root / "src" / "fortran" / "abaqus" / "UMAT.for"
|
||||
source.parent.mkdir(parents=True)
|
||||
source.write_text(" subroutine umat()\n end\n", encoding="utf-8")
|
||||
source_hash = hashlib.sha256(source.read_bytes()).hexdigest()
|
||||
model_dir = root / "references" / "umat" / "single-element"
|
||||
for name in ["model.inp", "job.msg.tail.txt", "job.dat.tail.txt", "job.log.tail.txt", "stresses.csv"]:
|
||||
(model_dir / name).parent.mkdir(parents=True, exist_ok=True)
|
||||
(model_dir / name).write_text("ok\n", encoding="utf-8")
|
||||
write_json(
|
||||
model_dir / "metadata.json",
|
||||
{
|
||||
"schema_version": "abaqus-user-subroutine-artifact-v1",
|
||||
"feature_id": "umat",
|
||||
"model_id": "single-element",
|
||||
"artifact_status": "ready-for-comparison",
|
||||
"abaqus": {"version": "2024", "precision": "double", "command": "abaqus job=case user=UMAT.for"},
|
||||
"compiler": {"vendor": "Intel oneAPI", "name": "ifx", "version": "2024"},
|
||||
"subroutine": {
|
||||
"entry_points": ["UMAT"],
|
||||
"source_files": [
|
||||
{
|
||||
"path": "src/fortran/abaqus/UMAT.for",
|
||||
"language": "Fortran",
|
||||
"sha256": "0" * len(source_hash),
|
||||
}
|
||||
],
|
||||
},
|
||||
"input_file": "model.inp",
|
||||
"outputs": {
|
||||
"tails": {"msg": "job.msg.tail.txt", "dat": "job.dat.tail.txt", "log": "job.log.tail.txt"},
|
||||
"csv": {"stresses": "stresses.csv"},
|
||||
},
|
||||
},
|
||||
)
|
||||
model_dir, payload = create_ready_bundle(root)
|
||||
payload["subroutine"]["source_files"][0]["sha256"] = "0" * 64
|
||||
write_json(model_dir / "metadata.json", payload)
|
||||
|
||||
errors = validator.validate_root(root)
|
||||
|
||||
self.assertTrue(any("sha256 mismatch" in error for error in errors))
|
||||
|
||||
def test_ready_for_comparison_rejects_csv_outside_extracted_directory(self):
|
||||
validator = load_validate_reference_artifacts()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
model_dir, payload = create_ready_bundle(root)
|
||||
payload["outputs"]["csv"] = {"stresses": "stresses.csv"}
|
||||
write_text(model_dir / "stresses.csv")
|
||||
write_json(model_dir / "metadata.json", payload)
|
||||
|
||||
errors = validator.validate_root(root)
|
||||
|
||||
self.assertTrue(any("csv output stresses must match extracted/*.csv" in error for error in errors))
|
||||
|
||||
def test_ready_for_comparison_checks_optional_odb_sha256_file(self):
|
||||
validator = load_validate_reference_artifacts()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
model_dir, payload = create_ready_bundle(root)
|
||||
payload["extraction"]["odb_sha256_file"] = "result.odb.sha256"
|
||||
write_text(model_dir / "result.odb.sha256", "not-a-sha\n")
|
||||
write_json(model_dir / "metadata.json", payload)
|
||||
|
||||
errors = validator.validate_root(root)
|
||||
|
||||
self.assertTrue(any("invalid odb_sha256_file" in error for error in errors))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user