diff --git a/qiskit_experiments/framework/base_experiment.py b/qiskit_experiments/framework/base_experiment.py index 7a800c03ad..e08ae49721 100644 --- a/qiskit_experiments/framework/base_experiment.py +++ b/qiskit_experiments/framework/base_experiment.py @@ -304,7 +304,7 @@ def run( # Run jobs jobs = experiment._run_jobs(circuits, **run_opts) experiment_data.add_data(jobs) - experiment._add_job_metadata(experiment_data, jobs, **run_opts) + experiment._add_job_metadata(experiment_data.metadata, jobs, **run_opts) # Optionally run analysis if analysis and self.__analysis_class__ is not None: @@ -515,7 +515,6 @@ def _metadata(self) -> Dict[str, any]: "experiment_type": self._type, "num_qubits": self.num_qubits, "physical_qubits": list(self.physical_qubits), - "job_metadata": [], } # Add additional metadata if subclasses specify it for key, val in self._additional_metadata().items(): @@ -530,22 +529,23 @@ def _additional_metadata(self) -> Dict[str, any]: """ return {} - def _add_job_metadata(self, experiment_data: ExperimentData, jobs: BaseJob, **run_options): + def _add_job_metadata(self, metadata: Dict[str, Any], jobs: BaseJob, **run_options): """Add runtime job metadata to ExperimentData. Args: - experiment_data: the experiment data container. + metadata: the metadata dict to update with job data. jobs: the job objects. run_options: backend run options for the job. """ - metadata = { - "job_ids": [job.job_id() for job in jobs], - "experiment_options": copy.copy(self.experiment_options.__dict__), - "transpile_options": copy.copy(self.transpile_options.__dict__), - "analysis_options": copy.copy(self.analysis_options.__dict__), - "run_options": copy.copy(run_options), - } - experiment_data._metadata["job_metadata"].append(metadata) + metadata["job_metadata"] = [ + { + "job_ids": [job.job_id() for job in jobs], + "experiment_options": copy.copy(self.experiment_options.__dict__), + "transpile_options": copy.copy(self.transpile_options.__dict__), + "analysis_options": copy.copy(self.analysis_options.__dict__), + "run_options": copy.copy(run_options), + } + ] def fix_class_docs(wrapped_cls): diff --git a/qiskit_experiments/framework/composite/composite_analysis.py b/qiskit_experiments/framework/composite/composite_analysis.py index 33bdf9e931..6841f6c19f 100644 --- a/qiskit_experiments/framework/composite/composite_analysis.py +++ b/qiskit_experiments/framework/composite/composite_analysis.py @@ -66,10 +66,9 @@ def _run_analysis(self, experiment_data: ExperimentData, **options): # analysis classes composite_exp = experiment_data.experiment component_exps = composite_exp.component_experiment() - if "component_job_metadata" in experiment_data.metadata: - component_metadata = experiment_data.metadata["component_job_metadata"][-1] - else: - component_metadata = [{}] * composite_exp.num_experiments + component_metadata = experiment_data.metadata.get( + "component_metadata", [{}] * composite_exp.num_experiments + ) # Initialize component data for updating and get the experiment IDs for # the component child experiments in case there are other child experiments @@ -94,7 +93,7 @@ def _run_analysis(self, experiment_data: ExperimentData, **options): sub_exp_data.add_data(sub_data) # Add component job metadata - sub_exp_data.metadata["job_metadata"] = [component_metadata[i]] + sub_exp_data.metadata.update(component_metadata[i]) # Run analysis # Since copy for replace result is handled at the parent level diff --git a/qiskit_experiments/framework/composite/composite_experiment.py b/qiskit_experiments/framework/composite/composite_experiment.py index 0070e928d8..f97be35f0b 100644 --- a/qiskit_experiments/framework/composite/composite_experiment.py +++ b/qiskit_experiments/framework/composite/composite_experiment.py @@ -13,7 +13,6 @@ Composite Experiment abstract base class. """ -import copy from typing import List, Sequence, Optional from abc import abstractmethod import warnings @@ -93,13 +92,17 @@ def _initialize_experiment_data(self): return experiment_data def _additional_metadata(self): - return {"component_job_metadata": []} + """Add component experiment metadata""" + return { + "component_metadata": [sub_exp._metadata() for sub_exp in self.component_experiment()] + } - def _add_job_metadata(self, experiment_data, jobs, **run_options): - # Extract component metadata - component_metadata = [] + def _add_job_metadata(self, metadata, jobs, **run_options): + super()._add_job_metadata(metadata, jobs, **run_options) # Add sub-experiment options - for sub_exp in self.component_experiment(): + for sub_metadata, sub_exp in zip( + metadata["component_metadata"], self.component_experiment() + ): # Run and transpile options are always overridden if ( sub_exp.run_options != sub_exp._default_run_options() @@ -109,17 +112,7 @@ def _add_job_metadata(self, experiment_data, jobs, **run_options): "Sub-experiment run and transpile options" " are overridden by composite experiment options." ) - component_metadata.append( - { - "job_ids": [job.job_id() for job in jobs], - "experiment_options": copy.copy(sub_exp.experiment_options.__dict__), - "transpile_options": copy.copy(sub_exp.transpile_options.__dict__), - "analysis_options": copy.copy(sub_exp.analysis_options.__dict__), - "run_options": copy.copy(run_options), - } - ) - super()._add_job_metadata(experiment_data, jobs, **run_options) - experiment_data._metadata["component_job_metadata"].append(component_metadata) + sub_exp._add_job_metadata(sub_metadata, jobs, **run_options) def _postprocess_transpiled_circuits(self, circuits, **run_options): for expr in self._experiments: