Skip to content

Output Data Handling ​

A simulation saves three classes of output under <project-dir>/Output/ for post-simulation analysis, plus three analysis logs:

ClassFilesWritten by
Pivotal events (branch points)Output/PE/PEFolder_<id/1000>/ZPENode_<id>.txtBranchCluster::savePENodeToFile()
End statesOutput/ES/ESFolder_<id/1000>/ZESNode_<id>.txt, Output/ES/ES_summary.txtBranchEndState::saveInfoToFile(), BranchRecord::endSimulation()
Key parameter historiesOutput/KPS/KPSFolder_<id/1000>/ZKPS_<id>.txt, ZDIA_<id>.txt, ZPIF_<id>.txtKeyParameterHistory::outputHistoryToFile()
Analysis logsOutput/ES/Scenario info.txt, Output/ES/Procedure data.txt, Output/ES/Scan data.txtAnalysisInfoContainer::saveInfoToFile()

Files are grouped in sub-folders of 1000 ids (BranchRecord::size_of_subfolder, set in the BranchRecord constructor): the folder number is the integer quotient of the id by 1000. The id of a pivotal-event file is the branch id; the id of an end-state file and of the three history files is the sequence id. The file contents are described in Outputs.

Pivotal events ​

The branch information is held in BranchRecord::branch_cluster. A BranchCluster is one branching node and holds one or more branches, so saving one cluster writes one ZPENode_<id>.txt per branch. BranchCluster::savePENodeToFile() remembers the size and hash of what it last wrote for each branch id (g_sim.pe_file_state) and skips a node whose content has not changed.

  • In a serial run the clusters stay in memory for the whole run. When AdsidacCallback::restartForNewSequence() finds no unexplored branch, it saves every cluster and then clears branch_cluster.
  • In an MPI run each worker saves every cluster of its branch record after every sequence (save_sequence_outputs() in Client.cpp), into rank_N/Output/PE/. The same node can therefore exist on several ranks in different states of completeness; the merge resolves this (below).

With --aggregate-pe a node is appended as a record to ZPENodes_agg.txt instead of being written to its own file. See Output layouts.

End states ​

In a serial run an end state is saved as soon as it is generated: BranchRecord::addAnEndState() calls BranchEndState::saveInfoToFile(). In an MPI run addAnEndState() does not write, because the id it assigns is local to the rank; save_sequence_outputs() sets the global sequence id and then writes the file. The BranchEndState objects stay in BranchRecord::end_state until the end of the run, because BranchRecord::endSimulation() writes Output/ES/ES_summary.txt from them (one header line and one line per end state). In an MPI run the summary is rebuilt from the merged ZESNode files (adsidac::merge::build_es_summary()).

Analysis logs ​

During a sequence AnalysisInfoContainer (g_sim.Aux_info) accumulates three lists in memory: the statements sent out by the CommandControlCenter (addRecord()), the procedure-step data (addProcedureData()) and the scan-queue data (addScanQueueData()). When the sequence ends, saveInfoToFile() appends one block per list, headed by a banner with the sequence number, to Scenario info.txt, Procedure data.txt and Scan data.txt.

clearAnalysisInfoContainerRecord() and clearAnalysisInfoContainerForRestart() release the container's memory; copyAnalysisInfoContainer() and copyAnalysisInfoContainerForRestart() make deep copies. A restart snapshot (RestartNodeInfo) holds a copy taken at the branch point, and a restarted sequence starts from that copy, so its block contains the records from the beginning of the transient.

Key parameter histories ​

KeyParameterHistory (g_sim.KPS) holds a vector of KeyParameterHistoryUnit objects, one per recorded time step. outputHistoryToFile() writes three files per sequence:

  • ZKPS_<id>.txt: the time history of the control panel indicators;
  • ZDIA_<id>.txt: the confidence level of each diagnosis event, per operator;
  • ZPIF_<id>.txt: the dynamic performance influencing factors (system criticality, time-constraint loading, information loading).

Each file starts with a line giving the number of columns and rows, followed by a label row, a unit row and one row per time step.

A restart snapshot holds a copy of the history up to the branch point. When a new sequence restarts, g_sim.KPS is cleared and the snapshot's history is copied back, so every file in the KPS folder contains the time history from the beginning of the transient to the end of its sequence.

MPI consolidation and merge modes ​

Everything above describes what one process writes. Under MPI each rank writes the same classes into its own rank_N/Output/, and the run ends with a consolidation into the shared Output/ whose mechanics live in Global/OutputMerge.h and Global/PEOutput.h:

  • --merge=now (default): every worker renames its own end-state and history files into the shared buckets at shutdown (a metadata operation; global sequence ids make collisions between ranks impossible), compacts its own pivotal-event aggregate last-wins (with --aggregate-pe), and stages its analysis logs as ordered part files. Rank 0 concatenates the parts in rank order, rebuilds ES_summary.txt from the merged ZESNode files, moves per-file PE nodes in rank order (the highest rank is the deterministic winner when a node exists on several ranks), and renumbers the PE class sequentially. In the per-file layout the renumbering changes file names only and is journaled through renumber.map; in the aggregate layout the records are collected and rewritten. After it, all nodes are ZPENode_0 to ZPENode_<N-1> in PEFolder_0.
  • --merge=serial: rank 0 copies every file in a single pass. The merged output is the same.
  • --merge=defer + --merge-only: the run ends at tree completion, Output/MERGE_PENDING.txt records the state, and a separate --merge-only invocation (no mpirun, threaded over rank directories, idempotent) consolidates or recovers the project on any allocation. A checkpoint-stop always merges inline, and --resume refuses while a merge is pending.

User-facing behavior and guarantees: Output layouts and Running.

ADS-IDAC Engine Documentation