Skip to content

Current Persistent Formats

The current source owners are the format specification. Odin readers and the Python validators accept one exact current shape, reject malformed or unknown fields, and do not provide alternate readers or compatibility migrations. There is no general format-version field.

Hashes are SHA-256. Paths stored in Project records are Project-relative unless the format explicitly records an external Project descriptor or solver path. Writes are staged/atomic and canonical records are non-overwriting.

Project and catalog

Owned by project.odin and project_storage.odin.

<project-directory>/<descriptor-name>.ramal-project
projects/project-catalog.json

The Project descriptor has exactly:

project_id, display_name, phits_launcher, multiplier_file

The catalog registry has exactly:

external_paths: string[]

The descriptor identifies one Project workspace. phits_launcher and multiplier_file refer to the external PHITS installation; RAMAL does not copy that installation into the repository. Research protocols are researcher-owned and are not selected or enforced by the Project record.

Design and PHITS input

Owned by design.odin, design_phits.odin, phits.odin, and phits_document.odin.

designs/<design-id>/
  <design-id>.ramal-design
  <design-id>.inp

The JSON Design record owns RAMAL-managed input plus the editable result-field setup and target. The sibling .inp is derived solver input: ordinary PHITS text with every $ ramal:* metadata line removed. The display name comes from [Title] in the record. Result-field setup and target data stay in the JSON record; they are not emitted as PHITS comments.

When a Design uses the reusable one-dimensional industrial scan source, its managed [Source] block contains exactly one strict metadata line, for example:

$ ramal:source-scan enabled=1 axis=x min_cm=-50 max_cm=50 fwhm_cm=2 support_diameter_cm=3 positions=101 profile=uniform

The fields are the enabled flag, scan axis (x or y), absolute centre range in cm, local Gaussian FWHM in cm, RAMAL finite support diameter/cutoff in cm, odd quadrature position count (3..500), and profile (uniform). The GUI round-trips these values from this line; it never reconstructs scan intent by examining expanded <source> subsections. A valid scanned source is a normally directed s-type = 13 Gaussian on one z plane. Its generated PHITS card contains one <source> subsection per position. Uniform continuous-line nodes use normalized trapezoidal weights: h = 1/(N-1), endpoints h/2, interior nodes h, with the sum exactly 1; totfact = 1 preserves normalization per primary source electron. PHITS does not provide a native finite radial cutoff for s-type = 13; the support field is therefore RAMAL-owned preview/validation metadata, not an invented solver parameter.

The strict importer rejects malformed or duplicated scan metadata instead of guessing from solver-expanded source sections. design_solver_input removes the metadata line when producing a solver-clean Design or immutable Case input, but keeps the generated multi-source PHITS syntax. The current source API performs generic range and source-direction checks; exact containment against a finite converter face remains a project verification gate until converter ownership is exposed to the reusable geometry API.

Scene_State is in-memory editing state, not a persisted Project record.

Case

Owned by case.odin.

cases/<case-id>/
  <case-id>.ramal-case
  input.inp
  jobs/

The .ramal-case document has exactly:

project_id, case_id, display_name, source_kind, source_design_id,
created_at_utc, input_path, ramal_input, result_contract

source_kind is currently design. result_contract contains:

target, normalization_mode, particles, required_roles, region_reports

target declares its Project-owned ID, quantity, output unit and normalization, intrinsic unit and normalization, PHITS multiplier ID, source-to-output scale, and primary particle. The editable Design record separately retains setup mode (custom, guided-h10, or guided-icru95) and the target fields; the immutable Result Contract keeps its existing nine-field target shape and rechecks the generated multiplier, c1 scale, quantity, and unit. required_roles contains:

vtk, report, uncertainty_vtk, uncertainty_report

input.inp is the immutable solver-clean physical input. ramal_input retains the corresponding RAMAL-managed input, including metadata needed by the GUI, Dataset builder, and Assessment calculations. Case loading proves that removing all $ ramal:* lines from ramal_input exactly reproduces input.inp, then re-derives and verifies the immutable Result specification. Run controls belong to an Attempt and are not written back into the Case.

Optional Design Case Controls

A Design may declare a small, strict set of optional numeric Case Controls in PHITS comments. The Design remains editable; the controls describe which Design values may be specialized when one immutable Case is published. The initial supported operations are exactly:

$ ramal:case-control feature=energy-mev kind=source-energy min=0.2 max=8.0
$ ramal:case-control feature=downstream-concrete-cm kind=rpp-thickness inner=101 outer=102 axis=y side=min min=20 max=60

The numeric bounds are illustrative; the active research procedure owns its predefined physical ranges.

source-energy requires MeV on the matching numeric feature declaration and sets PHITS source energy. rpp-thickness requires cm and adjusts one min or max face of an outer RPP relative to the corresponding face of an enclosing inner RPP. Multiple target lines may share one feature and value, but every target must own a distinct physical face and remain a positive, enclosing RPP geometry. Field names and order are exact; unknown, duplicate, conflicting, non-finite, missing-feature, missing-surface, non-RPP, and physically inconsistent declarations fail closed.

Creating a Case with no values freezes the current Design values exactly. Creating one with values requires one finite, in-range value for every declared control, with no missing, extra, or duplicate feature IDs. RAMAL specializes an owned temporary Scene_State, generates and merges PHITS from that temporary scene, rejects material-cell overlaps, and re-imports and resolves the exact specialized PHITS bytes before publication. The Result contract is derived from that re-imported input. RAMAL rewrites only the controlled $ ramal:feature lines to the selected numeric values while preserving their dataset-compatible three-field shape. The Design scene and Design input bytes are not mutated.

There is no Variant object, batch-generation path, compatibility reader, schema-version field, or separate Case provenance document. Study schedules existing Cases and does not generate new Cases.

Job and Attempt

Owned by job.odin and attempt.odin.

cases/<case-id>/jobs/<job-id>/<job-id>.ramal-job
cases/<case-id>/jobs/<job-id>/attempts/<attempt-id>/
  scene.phits.inp
  manifest.json

The .ramal-job document has exactly:

project_id, case_id, job_id, display_name, maxcas, maxbch, rseed,
replica_index, execution_target, status, created_at_utc, attempts

execution_target is either local or a safe remote profile ID. It is persisted with the Job so retries retain their target even if a profile is temporarily unavailable. The embedded Attempt entries have:

attempt_id, status, phase, execution_input_path, attempt_record_path,
result_id, started_at_utc, ended_at_utc, return_code

Attempt IDs are a0001 through a9999. The strict runner in tools/run_case_attempt.py accepts:

--prepare-attempt
--execute-prepared-attempt
--verify-succeeded-attempt
--resolve-result-roles

Its manifest.json records the Attempt status and times, executed command, PHITS version, return code, execution controls, result and region-report roles, and the paths of files retained in the Attempt. The exact executed input is scene.phits.inp; logs and outputs remain beside it.

Remote transport does not alter this Job, Attempt, manifest, or Result schema. Before terminal transfer it keeps a strict operational sidecar adjacent to the Attempt, never inside it:

cases/<case-id>/jobs/<job-id>/attempts/.<attempt-id>.remote.json

The sidecar stores the selected profile, execution identity, recovery paths, tmux session, current progress, terminal state, and diagnostics. It is operational state, not evidence, and is not included in the Attempt manifest. A remote terminal Attempt contains the normal manifest plus transport files such as phits.in, remote-launch.sh, remote_phits_worker.py, phits.out, and run.log.

Remote profiles are external application configuration, not Project data:

~/Library/Application Support/RAMAL-EBX/remote-profiles.json

The remote profile document has exactly profiles and no format-version field. Each profile supplies its safe ID, display name, SSH host/user, remote root, Python/tmux/MPI/PHITS paths, hostfile, process count, and optional ssh_port, ssh_host_key_alias, and mpi_environment. ssh_port defaults to 22; ssh_host_key_alias defaults to ssh_host and preserves host-key verification when a trusted local TCP forward uses 127.0.0.1.

An AnyDesk forward tunnel with local port 2222 and remote destination 10.10.180.64:22 can be represented as a second profile without changing the ordinary direct profile:

{
  "id": "fz-mm1-anydesk",
  "display_name": "fz-mm1 MPI through AnyDesk",
  "exclusive_cluster": true,
  "ssh_user": "faiz",
  "ssh_host": "127.0.0.1",
  "ssh_port": 2222,
  "ssh_host_key_alias": "fz-mm1",
  "remote_root": "/Users/faiz/work/ramal-ebx",
  "python_path": "/usr/bin/python3",
  "tmux_path": "/opt/homebrew/bin/tmux",
  "mpirun_path": "/opt/homebrew/bin/mpirun",
  "hostfile_path": "/Users/faiz/hostfile",
  "phits_path": "/Users/faiz/phits/phits_MacGfort_MPI",
  "mpi_processes": 32
}

Result

Owned by result.odin.

cases/<case-id>/jobs/<job-id>/<result-id>.ramal-result

The .ramal-result document has exactly:

project_id, case_id, job_id, result_id, attempt_id, status, completed_at_utc

The status is completed. Opening a Result validates its canonical Case, Job, Attempt, manifest, result roles, output fields, and exact execution input before replacing the immutable Analyze scene.

Study and Assessment

Owned by study.odin and assessment.odin.

studies/<study-id>/<study-id>.ramal-study
studies/<study-id>/assessments/<assessment-id>.ramal-study-assessment

Study fields are exactly:

project_id, study_id, display_name, question, created_at_utc,
reference_case_id, inclusion_criteria, domain, evaluation_regions, members

reference_case_id is empty when no reference is required. The inclusion criteria contain max_relative_error, min_reportable_fraction, and min_reportable_voxel_count. The domain contains min_cm, max_cm, and mesh_count. Evaluation regions and members retain their exact spatial and Case/Job/replica bindings.

Assessment fields are exactly:

project_id, study_id, assessment_id, created_at_utc, status, members

Assessment member status and regional metrics are persisted. Status is meets-criteria or does-not-meet-criteria when calculation succeeds; each regional metrics object records meets_criteria. Summary counts are derived from member statuses. Result and Attempt integrity is re-verified from their canonical records.

Case feature declaration

Each Dataset-selected feature must occur exactly once in the immutable Case input:

$ ramal:feature id=energy-mev value=5.0 unit=MeV
$ ramal:feature id=converter-state value=absent unit=category

Continuous declarations use finite numeric values. Binary declarations use one of the two category IDs from the Dataset feature definition. The builder maps the category to index 0 or 1 for numeric arrays. A Case may retain additional feature declarations that a particular Dataset does not learn. This permits a Dataset to omit a constant feature without erasing the Case's physical provenance.

Feature definition

Every feature object has exactly these keys:

{
  "feature_id": "energy-mev",
  "display_name": "Incident electron energy",
  "kind": "continuous",
  "unit": "MeV",
  "minimum": 1.0,
  "maximum": 10.0,
  "categories": []
}

Rules:

  • kind is exactly continuous or binary.
  • A continuous feature has an empty categories list, a physical unit, and finite maximum > minimum.
  • A binary feature has unit: "category", minimum: 0, maximum: 1, and exactly two distinct valid record IDs in categories.
  • An illustrative binary feature is:
{
  "feature_id": "converter-state",
  "display_name": "Converter state",
  "kind": "binary",
  "unit": "category",
  "minimum": 0,
  "maximum": 1,
  "categories": ["absent", "present"]
}

Example ranges and categories describe the schema only. A research procedure must define its own physically justified values.

Dataset specification

Owned by tools/build_dataset.py and indexed by research_index.odin.

datasets/<dataset-id>/<dataset-id>.ramal-dataset

The specification has exactly these top-level keys:

{
  "dataset_id": "dataset-001",
  "display_name": "Reportable dose fields",
  "study_id": "study-001",
  "assessment_id": "assessment-0001",
  "feature_definitions": [],
  "samples": [],
  "partitioning_method": {},
  "minimum_common_coverage": 0.95
}

Each specification sample has exactly:

{
  "configuration_id": "configuration-0001",
  "member_id": "member-0001",
  "split": "train",
  "feature_values": [5.0, 0]
}

feature_values are numeric in feature-definition order. A binary value must be exactly 0 or 1.

Partitioning method

The method has exactly these keys:

{
  "algorithm": "declared-whole-configuration",
  "seed": 17,
  "paired_feature_id": "converter-state"
}

Use an empty paired_feature_id for ordinary samples. When it names a binary feature, derive each group from all other feature values. Require exactly one sample for each binary category, and require all group members to use the same partition. Count readiness by complete groups: at least two training groups, one model-selection group, and one final-test group.

The seed records the declared partition traceability. It is not permission to randomly reassign samples during building or verification.

Dataset manifest

The published manifest has exactly:

project_id, dataset_id, display_name, created_at_utc, study,
feature_definitions, target, grid, spatial_input, partitioning_method, samples,
artifacts

The arrays remain numeric:

features.npy
dose.npy
dose-rate.npy
current-multiplier.npy
relative-error.npy
splits.npy
evaluation-mask.npy
common-reportable-mask.npy
x-coordinates.npy
y-coordinates.npy
z-coordinates.npy
material-fractions.npy
dominant-material-id.npy
mass-density-g-cm3.npy
air-fraction.npy
signed-distance-cm.npy
region-masks.npy
primary-evaluation-mask.npy

dose.npy contains the scientific target in the intrinsic unit and normalization declared by target; dose-rate.npy preserves the PHITS output field in its declared output unit and normalization. current-multiplier.npy stores the exact positive set: c1[...] scale connecting them. These filenames are stable storage roles; the Dataset target metadata, not the names, defines the physical quantity. Spatial Cell arrays use canonical [z, y, x] order; material fractions have a leading sample and material channel, and region masks have leading sample and region channels. The current exact exporter supports baked, untransformed RPP room Cells and fails closed on unsupported spatial geometry.

The manifest binds every sample to its procedure, immutable Case specification, Result, Attempt manifest, feature values, partition, and current multiplier. Every verification regenerates the spatial tensors from the immutable input/specification and compares them exactly. The common-reportable-mask remains the intersection of positive reportable voxels across selected configurations. An unscored value is never rewritten as zero.

Model manifest

Owned by tools/model_pipeline.py and indexed by research_index.odin.

models/<model-id>/<model-id>.ramal-model
models/<model-id>/evaluations/final-test.ramal-model-evaluation

The Model repeats the exact Dataset feature_definitions and target specification. The finalized training procedure uses model-selection results for candidate selection and keeps the final-test partition untouched until explicit evaluation. Binary feature definitions are retained in the Model so prediction validation and the UI can enforce categories.

Prediction specification and manifest

predictions/<prediction-id>/<prediction-id>.ramal-prediction
predictions/<prediction-id>/verifications/<verification-id>.ramal-prediction-verification

The Prediction specification remains deliberately numeric:

{
  "prediction_id": "prediction-001",
  "display_name": "No converter at 5 MeV",
  "feature_values": [5.0, 0]
}

The backend rejects non-integral binary values, out-of-domain values, wrong feature counts, and mismatched feature order. The UI renders binary features as category combos and continuous features as numeric inputs.

The Prediction manifest records the selected numeric values together with the exact feature IDs and units. The Odin index repeats the same binary-integrality and domain checks and fails closed on invalid prediction records.

Final-test evaluation

For every candidate algorithm, final-test evidence has:

{
  "aggregate_metrics": {},
  "configuration_metrics": [],
  "category_metrics": {
    "converter-state": {
      "absent": {
        "sample_count": 1,
        "aggregate_metrics": {},
        "configuration_metrics": []
      },
      "present": {
        "sample_count": 1,
        "aggregate_metrics": {},
        "configuration_metrics": []
      }
    }
  }
}

The exact object is reproduced during verification. Aggregate scores alone are insufficient whenever category-specific performance is part of the claim.

Dataset physical boundary

A Dataset inherits its physical boundary from its immutable Cases and shared Result specification. The current scalar feature declarations do not replace the underlying geometry or source data provenance. The current builder requires every selected Result to share one exact grid and target specification; it does not encode a spatially variable material geometry as an ML input.

Non-record runtime state

Simulation, Study_Run, and ML_Task are transient state. Project, Design, Case, Job, Attempt, Result, Study, Assessment, Dataset, Model, Prediction, and Prediction Verification are persisted domain records. Catalogs and Research_Index are rebuilt runtime indexes.