3030 NoiseSpaceDPSScaler ,
3131 NoScalingScaler ,
3232)
33- from sampleworks .utils .cif_utils import resolve_mixed_hetatm_atom_altlocs
33+ from sampleworks .utils .cif_utils import add_category_to_cif , resolve_mixed_hetatm_atom_altlocs
3434from sampleworks .utils .guidance_constants import (
3535 GuidanceType ,
3636 StructurePredictor ,
@@ -265,7 +265,7 @@ def get_reward_function_and_structure(
265265
266266
267267def save_everything (
268- output_dir : str | Path ,
268+ args : GuidanceConfig | argparse . Namespace ,
269269 losses : list [Any ],
270270 refined_structure : dict ,
271271 traj_denoised : list [Any ],
@@ -283,8 +283,10 @@ def save_everything(
283283
284284 Parameters
285285 ----------
286- output_dir : str | Path
287- Directory to write all output files into. Created if it doesn't exist.
286+ args : GuidanceConfig | argparse.Namespace
287+ The arguments for the guidance run. This method directly uses args.output_dir,
288+ and creates that directory if it does not exist. The result of args.as_dict() is
289+ written to a JSON file in the same directory, and inserted into the output CIF file.
288290 losses : list[Any]
289291 Per-step loss values (may contain ``None`` entries for unguided steps).
290292 refined_structure : dict
@@ -304,7 +306,7 @@ def save_everything(
304306 Optional model-space atom template. When provided (mismatch runs),
305307 this template is used for final structure and trajectory saving.
306308 """
307- output_dir = Path (output_dir )
309+ output_dir = Path (args . output_dir )
308310 output_dir .mkdir (parents = True , exist_ok = True )
309311
310312 logger .info ("Saving results" )
@@ -327,10 +329,20 @@ def save_everything(
327329 else :
328330 atom_array = base_atom_array
329331
332+ metadata = args .as_dict ()
333+
330334 final_structure = CIFFile ()
331335 set_structure (final_structure , atom_array )
336+ add_category_to_cif (final_structure , metadata , category_name = "sampleworks" )
332337 final_structure .write (str (output_dir / "refined.cif" ))
333338
339+ # write out the job parameters to a JSON file in the same directory as the refined.cif file
340+ # Even though this is technically duplicated, keep it around as a backup in case metadata
341+ # is lost in some CIF transform.
342+ with open (Path (output_dir ) / "job_metadata.json" , "w" ) as fp :
343+ # use the GuidanceConfig's as_dict() method to avoid serializing PosixPath objects
344+ json .dump (metadata , fp )
345+
334346 # Two calls to save_trajectory, very similar, but saving different trajectories!
335347 save_trajectory (
336348 scaler_type ,
@@ -565,7 +577,7 @@ def _run_guidance(
565577 model_atom_array = result .metadata .get ("model_atom_array" ) if result .metadata else None
566578
567579 save_everything (
568- args . output_dir ,
580+ args ,
569581 losses ,
570582 refined_structure ,
571583 traj_denoised ,
@@ -641,10 +653,6 @@ def run_guidance_job_queue(job_queue_path: str) -> list[JobResult]:
641653 logger .info (f"Running job { i + 1 } /{ len (job_queue )} : { job } " )
642654
643655 job_result = run_guidance (job , job .guidance_type , model_wrapper , device )
644- # write out the job parameters to a JSON file in the same directory as the refined.cif file
645- with open (Path (job_result .output_dir ) / "job_metadata.json" , "w" ) as fp :
646- # use the GuidanceConfig's as_dict() method to avoid serializing PosixPath objects
647- json .dump (job .as_dict (), fp )
648656
649657 job_results .append (job_result )
650658 torch .cuda .empty_cache () # just in case
0 commit comments