"""JobContext — frozen data contract that strategies read but cannot mutate."""importosfromdataclassesimportdataclass
[docs]@dataclass(frozen=True)classJobContext:"""Immutable data contract holding all information a strategy can observe. Strategies depend on this object but cannot mutate it, preventing accidental cross-strategy side effects. Every field is read-only after construction. Attributes ---------- job_name : str Unique identifier for this job (also used as directory name). output_dir : str Absolute path to the job's working directory. cpus : int Number of CPUs requested for the Abaqus solver run. abaqus_exe : str Path or command name for the Abaqus executable (default ``"abaqus"``). """job_name:stroutput_dir:strcpus:intabaqus_exe:str="abaqus"user_subroutine:str|None=None@propertydefinp_path(self)->str:"""Absolute path to the input file (``<output_dir>/<job_name>.inp``)."""returnos.path.join(self.output_dir,f"{self.job_name}.inp")@propertydefodb_path(self)->str:"""Absolute path to the output database (``<output_dir>/<job_name>.odb``)."""returnos.path.join(self.output_dir,f"{self.job_name}.odb")@propertydeflog_path(self)->str:"""Absolute path to Abaqus's own native job log (``<output_dir>/<job_name>.log``). This file is owned and written by the Abaqus solver process itself (``abaqus job=... interactive`` writes it as a side effect). ABQflow never opens this path for writing — see :attr:`exec_log_path` for ABQflow's own execution log, which uses a distinct filename to avoid colliding with this one. """returnos.path.join(self.output_dir,f"{self.job_name}.log")@propertydefexec_log_path(self)->str:"""Absolute path to ABQflow's own execution log (``<output_dir>/<job_name>_abqflow.log``). Deliberately distinct from :attr:`log_path` (Abaqus's native job log) so the two writers never collide on the same file. """returnos.path.join(self.output_dir,f"{self.job_name}_abqflow.log")@propertydefsta_path(self)->str:"""Absolute path to the status file (``<output_dir>/<job_name>.sta``)."""returnos.path.join(self.output_dir,f"{self.job_name}.sta")@propertydefmsg_path(self)->str:"""Absolute path to the message file (``<output_dir>/<job_name>.msg``)."""returnos.path.join(self.output_dir,f"{self.job_name}.msg")@propertydefdat_path(self)->str:"""Absolute path to the data file (``<output_dir>/<job_name>.dat``)."""returnos.path.join(self.output_dir,f"{self.job_name}.dat")