Source code for qiskit_metal.analyses.simulation.scattering_impedance

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

from typing import Union, Tuple
import pandas as pd

from qiskit_metal.designs import QDesign  # pylint: disable=unused-import

from ... import Dict
from ..core import QSimulation


[docs] class ScatteringImpedanceSim(QSimulation): """Uses drivenmodal simulation to extract the impedance. Default Setup: * name (str): Name of driven modal setup. Defaults to "Setup". * freq_ghz (int): Frequency in GHz. Defaults to 5. * max_delta_s (float): Absolute value of maximum difference in scattering parameter S. Defaults to 0.1. * max_passes (int): Maximum number of passes. Defaults to 10. * min_passes (int): Minimum number of passes. Defaults to 1. * min_converged (int): Minimum number of converged passes. Defaults to 1. * pct_refinement (int): Percent refinement. Defaults to 30. * basis_order (int): Basis order. Defaults to 1. * vars (Dict): Variables (key) and values (value) to define in the renderer. * sweep_setup (Dict): Description of the drivenmodal sweep * name (str): Name of sweep. Defaults to "Sweep". * start_ghz (float): Starting frequency of sweep in GHz. Defaults to 2.0. * stop_ghz (float): Ending frequency of sweep in GHz. Defaults to 8.0. * count (int): Total number of frequencies. Defaults to 101. * step_ghz (float): Difference between adjacent frequencies. Defaults to None. * type (str): Type of sweep. Defaults to "Fast". * save_fields (bool): Whether or not to save fields. Defaults to False. Data Labels: * sweep_name (str): Name given to the current sweep. * param_z (pd.DataFrame): Impedance matrix. * param_y (pd.DataFrame): Admittance matrix. * param_s (pd.DataFrame): Scattering matrix. """ default_setup = Dict(freq_ghz=5, max_delta_s=0.1, max_passes=10, min_passes=1, min_converged=1, pct_refinement=30, basis_order=1, vars=Dict(Lj='10 nH', Cj='0 fF'), sweep_setup=Dict(name="Sweep", start_ghz=2.0, stop_ghz=8.0, count=101, step_ghz=None, type="Fast", save_fields=False)) """Default setup.""" # supported labels for data generated from the simulation data_labels = ['sweep_name', 'params_z', 'params_y', 'params_s'] """Default data labels.""" def __init__(self, design: 'QDesign' = None, renderer_name: str = 'hfss'): """Compute drivenmodal and then extracts impedance, admittance and scattering paramters. Args: design (QDesign): Pointer to the main qiskit-metal design. Used to access the QRenderer. Defaults to None. renderer_name (str, optional): Which renderer to use. Defaults to 'hfss'. """ # set design and renderer super().__init__(design, renderer_name) def _analyze(self): """Executes the analysis step of the Run. First it initializes the renderer setup to prepare for drivenmodal analysis, then it executes it. Finally it recovers the output of the analysis and stores it in self.params_z/params_y/params_s. """ self.sim_setup_name, self.sweep_name = self.renderer.initialize_drivenmodal( **self.setup) self.renderer.analyze_sweep(self.sweep_name, self.sim_setup_name) # TODO: return the impedance, admittance and scattering matrices for later use
[docs] def get_impedance(self, param_name: list = ['Z11', 'Z21']): """Create the impedance plot. Args: param_name (list): List of strings describing which impedance values to return. Defaults to ['Z11', 'Z21']. """ # TODO: move the plot-making to this analysis module. Renderer should recover full data return self.renderer.plot_params(param_name)
[docs] def get_admittance(self, param_name: list = ['Y11', 'Y21']): """Create the impedance plot. Args: param_name (list): List of strings describing which admittance values to return. Defaults to ['Y11', 'Y21']. """ # TODO: move the plot in this analysis module. Renderer should recover the entire data return self.renderer.plot_params(param_name)
[docs] def get_scattering(self, param_name: list = ['S11', 'S21']): """Create the scattering plot. Args: param_name (list): List of strings describing which scattering values to return. Defaults to ['S11', 'S21']. """ # TODO: move the plot in this analysis module. Renderer should recover the entire data return self.renderer.plot_params(param_name)
[docs] def run_sim( # pylint: disable=arguments-differ self, name: str = None, components: Union[list, None] = None, open_terminations: Union[list, None] = None, port_list: Union[list, None] = None, jj_to_port: Union[list, None] = None, ignored_jjs: Union[list, None] = None, box_plus_buffer: bool = True) -> Tuple[str, str]: """Executes the entire drivenmodal analysis and convergence result export. First it makes sure the tool is running. Then it does what's necessary to render the design. Finally it runs the setup and sweep defined in this class. You need to modify the setup ahead. You can modify the setup by using the methods defined in the QAnalysis super-class. After this method concludes you can inspect the output using this class properties. Args: name (str): reference name for the components selection. If None, it will use the design.name. Defaults to None. components (Union[list, None], optional): List of components to render. Defaults to None. open_terminations (Union[list, None], optional): List of tuples of pins that are open. Defaults to None. port_list (Union[list, None], optional): List of tuples of pins to be rendered as ports. Format element: (component_name, pin_name, impedance (float)). Defaults to None. jj_to_port (Union[list, None], optional): List of tuples of jj's to be rendered as ports. Format element: (component_name(str), element_name(str), impedance(float), draw_ind(bool)). If draw_ind=True, a 10nH Inductance is draw, else it is omitted. Defaults to None. ignored_jjs (Union[list, None], optional): List of tuples of jj's that shouldn't be rendered. Defaults to None. box_plus_buffer (bool, optional): Either calculate a bounding box based on the location of rendered geometries or use chip size from design class. Defaults to True. Returns: (str, str): Name of the design and name of the setup """ # save input variables to run(). This line must be the first in the method if components is not None: argm = locals() del argm['self'] self.save_run_args(**argm) # wipe data from the previous run (if any) self.clear_data() if not self.renderer_initialized: self._initialize_renderer() vars_to_initialize = self.setup.vars renderer_design_name = self._render( name=name, solution_type='drivenmodal', selection=components, open_pins=open_terminations, port_list=port_list, jj_to_port=jj_to_port, ignored_jjs=ignored_jjs, box_plus_buffer=box_plus_buffer, vars_to_initialize=vars_to_initialize) self._analyze() return renderer_design_name, self.sim_setup_name
@property def sweep_name(self) -> str: """Getter Returns: str: Name of the sweep being executed. """ return self.get_data('sweep_name') @sweep_name.setter def sweep_name(self, data: str): """Setter Args: data (str): Name of the sweep being executed. """ if not isinstance(data, str): self.logger.warning( 'Unsupported type %s. Only accepts str. Please try again.', {type(data)}) return self.set_data('sweep_name', data) @property def param_z(self) -> pd.DataFrame: """Getter Returns: str: Impedance matrix. """ return self.get_data('param_z') @param_z.setter def param_z(self, data: pd.DataFrame): """Setter Args: data (pd.DataFrame): Impedance matrix. """ if not isinstance(data, pd.DataFrame): self.logger.warning( 'Unsupported type %s. Only accepts pd.DataFrame. Please try again.', {type(data)}) return self.set_data('param_z', data) @property def param_y(self) -> pd.DataFrame: """Getter Returns: str: Admittance matrix. """ return self.get_data('param_y') @param_y.setter def param_y(self, data: pd.DataFrame): """Setter Args: data (pd.DataFrame): Admittance matrix. """ if not isinstance(data, pd.DataFrame): self.logger.warning( 'Unsupported type %s. Only accepts pd.DataFrame. Please try again.', {type(data)}) return self.set_data('param_y', data) @property def param_s(self) -> pd.DataFrame: """Getter Returns: str: Scattering matrix. """ return self.get_data('param_s') @param_s.setter def param_s(self, data: pd.DataFrame): """Setter Args: data (pd.DataFrame): Scattering matrix. """ if not isinstance(data, pd.DataFrame): self.logger.warning( 'Unsupported type %s. Only accepts pd.DataFrame. Please try again.', {type(data)}) return self.set_data('param_s', data)