Loading DMT/core/docu_dut_lib.py +91 −18 Original line number Diff line number Diff line Loading @@ -26,7 +26,17 @@ from typing import Dict, List, Mapping, Sequence, Optional, Union from joblib import Parallel, delayed from scipy import interpolate from DMT.config import COMMAND_TEX, DATA_CONFIG from DMT.core import DutType, DutLib, specifiers, sub_specifiers, specifiers_ss_para from DMT.core import ( DutType, DutLib, specifiers, sub_specifiers, MCard, DutCircuit, DutMeas, Sweep, SimCon, ) from DMT.core.plot import MIX, PLOT_STYLES, natural_scales, Plot from DMT.external.os import recursive_copy, rmtree Loading Loading @@ -307,7 +317,10 @@ class DocuDutLib(object): self, dut_lib: DutLib, devices: Optional[Sequence[Mapping[str, object]]] = None, date=None, date: Optional[str] = None, modelcard_dict: Optional[Dict[DutType, MCard]] = None, DutCircuitClass: Optional[DutCircuit] = None, dut_class_kwargs: Optional[Dict] = None, ): self.dut_lib = dut_lib Loading Loading @@ -354,6 +367,31 @@ class DocuDutLib(object): self.plts: List[Plot] = [] self.modelcard_dict = modelcard_dict self.DutCircuitClass = DutCircuitClass if dut_class_kwargs is None: self.dut_class_kwargs = {} else: self.dut_class_kwargs = dut_class_kwargs def get_dut_sim(self, dut_meas: DutMeas) -> DutCircuit: """Retrieve a circuit dut view which should be compared to the given dut_meas""" if self.DutCircuitClass is not None: return self.DutCircuitClass( database_dir=None, dut_type=dut_meas.dut_type, input_circuit=self.modelcard_dict[dut_meas.dut_type], technology=dut_meas.technology, # needed for scaling! width=dut_meas.width, length=dut_meas.length, contact_config=dut_meas.contact_config, nfinger=dut_meas.nfinger, reference_node=dut_meas.reference_node, **self.dut_class_kwargs, ) else: return None def generate_docu( self, target_base_path: Union[str, Path], Loading @@ -376,16 +414,17 @@ class DocuDutLib(object): """ self.create_all_plots(plot_specs) # TODO # technology -> one lib can have more than one technology... # mcard # ADD data from mcard simulation if show and len(self.plts) > 1: for plt in self.plts[:-1]: if show and self.plts: for plt in self.plts: plt.plot_pyqtgraph(show=False) self.plts[-1].plot_pyqtgraph(show=True) self.plts[0].show_pyqtgraph() for plt in self.plts: plt.mw_pg = None plt.pw_pg = None # remove the plot from the object to allow Parallel prcessing # pickle is used to transfer between processes self.generate_all_plots(target_base_path, save_tikz_settings) Loading Loading @@ -415,6 +454,7 @@ class DocuDutLib(object): 'ymax' : 300, #optional, float: Maximum Value on y-axis to be displayed 'ymin' : 0, #optional, float: Minimum Value on y-axis to be displayed 'no_at' : True, #optional, Bool: if True, do not display the "at" quantities in the legend. 'simulate' : True, #optional, Bool: if True, a matching simulation is added to the plot, if not given, default is True }, """ Loading @@ -424,6 +464,7 @@ class DocuDutLib(object): "dut_type": DutType.npn, "no_at": False, # no at_specifier= in legend } sim_con = SimCon() # set defaults for plot_spec in plot_specs: Loading @@ -441,9 +482,7 @@ class DocuDutLib(object): valid_plots = PLOT_DEFAULTS[plot_spec["dut_type"]].keys() if not plot_type in valid_plots: raise IOError( "Plot type " + plot_type + " not valid. Valid: " f"Plot type {plot_type} not valid. Valid: " + " ".join(str(PLOT_DEFAULTS.keys())) + " ." ) Loading @@ -452,7 +491,7 @@ class DocuDutLib(object): raise IOError("Plot style not valid. Valid: " + " ".join(PLOT_STYLES)) if not "key" in plot_spec.keys(): raise IOError("Database key not specified for plot of type " + plot_type + " .") raise IOError(f"Database key not specified for plot of type {plot_type}.") # matching key? if "exact_match" not in plot_spec.keys(): Loading @@ -476,14 +515,20 @@ class DocuDutLib(object): self.plts = [] for plot_spec in plot_specs: plot_type = plot_spec["type"] print("Generating plots of type " + plot_type + " .") print(f"Generating plots of type {plot_type}.") style = plot_spec["style"] print("Chosen plot style: " + style) print(f"Chosen plot style: {style}") for dut in self.duts: if dut.dut_type != plot_spec["dut_type"]: continue if plot_spec.get( "simulate", PLOT_DEFAULTS[dut.dut_type][plot_type].get("simulate", True) ): dut_sim = self.get_dut_sim(dut) else: dut_sim = None quantity_x = plot_spec.get( "quantity_x", PLOT_DEFAULTS[dut.dut_type][plot_type]["quantity_x"] Loading Loading @@ -549,8 +594,8 @@ class DocuDutLib(object): except AttributeError: at_scale_ = natural_scales[at_] if at_ == specifiers.CURRENT + "B" or at_ == specifiers.CURRENT_DENSITY + "B": at_scale_ = at_scale_ * 1e3 # if at_ == specifiers.CURRENT + "B" or at_ == specifiers.CURRENT_DENSITY + "B": # at_scale_ = at_scale_ * 1e3 at_scale.append(at_scale_) Loading @@ -576,6 +621,9 @@ class DocuDutLib(object): temp, plot_spec[specifiers.TEMPERATURE] ): temps.append(dut.get_key_temperature(key)) elif specifiers.TEMPERATURE not in plot_spec: temps.append(dut.get_key_temperature(key)) temps = list(set(temps)) for temp in temps: Loading Loading @@ -762,6 +810,31 @@ class DocuDutLib(object): peaks["jc"].append(np.tile(jc_peak, 10)) peaks["vbc"].append(np.tile(point[0], 10)) if dut_sim is not None: # get a sweep sweep = Sweep.get_sweep_from_dataframe( data=df_tmp, temperature=temp, outputdef=[quantity_x, quantity_y], # othervar={}, ) # simulate sim_con.append_simulation(dut=dut_sim, sweep=sweep) sim_con.run_and_read() # add to plot df_sim = dut_sim.get_data(sweep=sweep) df_sim.ensure_specifier_column( quantity_x, area=AE0_drawn, ports=dut.ac_ports ) df_sim.ensure_specifier_column( quantity_y, area=AE0_drawn, ports=dut.ac_ports ) plt.add_data_set( df_sim[quantity_x].to_numpy(), df_sim[quantity_y].to_numpy(), label=label + " sim", ) plt.x_limits = x_limits plt.y_limits = y_limits Loading DMT/core/sweep.py +3 −2 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ Features: * Clear syntax and definition to create a well described simulation independent of the simulator interface. """ # DMT_core # Copyright (C) from 2022 SemiMod # Copyright (C) until 2021 Markus Müller, Mario Krattenmacher and Pascal Kuthe Loading Loading @@ -57,9 +58,9 @@ def get_sweepdef( data : DataFrame Frame to extract the sweepdefs from inner_sweep_voltage : SpecifierStr | None, optional A specifier that determiens the inner sweep voltage, by default None A specifier that determins the inner sweep voltage, by default None outer_sweep_voltage : SpecifierStr | None, optional A specifier that determiens the inner outer voltage, by default None A specifier that determins the inner outer voltage, by default None outer_sweep_voltage : SpecifierStr | None, optional A voltage at a third possible contact, that is not swept but may differ from zero. decimals_potentials : int, optional Loading test/test_interface_ngspice/test_DocuDutLib_simu.py 0 → 100644 +225 −0 Original line number Diff line number Diff line """ Test case for DocuDutLib with simulation comparisions I know.... the simulation data and the measurement data do not align!! They are from two different technologies, but those are the one we have currently at hand. """ import types import logging import shutil from pathlib import Path from DMT.config import COMMANDS from DMT.core import ( DutMeas, DutType, DocuDutLib, DutLib, specifiers, sub_specifiers, Technology, MCard, ) from DMT.core.dut_view import DutView from DMT.ngspice import DutNgspice from test_dut_ngspice_osdi import get_circuit folder_path = Path(__file__).resolve().parent test_path = folder_path.parent tmp_path = test_path / "tmp" test_data_path = test_path / "test_core_no_interfaces" / "test_data" # -->Start main function # --->Setup for log logging.basicConfig( level=logging.DEBUG, format="%(levelname)s - %(message)s", filename=folder_path.parent.parent / "logs" / "test_docudutlib_simu.log", filemode="w", ) class TechDummy(Technology): def __init__(self): super().__init__(name="dummy") def scale_modelcard( self, mcard: MCard, lE0: float, bE0: float, nfinger: int, config: str, dut: DutView = None, lE_drawn_ref: float = None, bE_drawn_ref: float = None, ) -> MCard: # nothing to do here return mcard @staticmethod def deserialize(): return TechDummy() def serialize(self): return { "class": str(self.__class__), "args": [], "kwargs": {}, "constructor": "deserialize", } def create_lib(): """Create a dut lib.""" # -->Define subroutine at first # --->Subroutine: filter_dut def filter_dut(dut_name): if "dummies" in dut_name: return None elif "TLM" in dut_name: return None elif dut_name == "": return None else: dut_transistor = DutMeas( database_dir=tmp_path, dut_type=DutType.npn, force=True, wafer=96, die="y", width=float(0.25e-6), length=float(0.25e-6), contact_config="CBEBC", name="dut_meas_npn", reference_node="E", technology=TechDummy(), ) return dut_transistor # --->Arrange DMT class to dmt lib = DutLib( save_dir=tmp_path / "dut_lib_save", force=True, AC_filter_names=[("freq_vbc", "ac")], DC_filter_names=[("fgummel", "dc")], ) # --->Add source measurement information in dmt and to duts lib.import_directory( import_dir=test_data_path, dut_filter=filter_dut, dut_level=1, force=True, ) lib.dut_ref = lib.duts[0] # --->Add the open and short dummies to the lib dut_short = DutMeas( database_dir=tmp_path, name="dut_short_npn", dut_type=DutType.deem_short_bjt, reference_node="E", force=True, wafer=96, die="y", width=float(0.25e-6), length=float(0.25e-6), technology=TechDummy(), ) dut_short.add_data(test_data_path / "dummy_short_freq.mdm", key="ac") dut_short.add_data(test_data_path / "short_dc.mdm", key="dc") dut_open = DutMeas( database_dir=tmp_path, name="dut_open_npn", dut_type=DutType.deem_open_bjt, reference_node="E", force=True, wafer=96, die="y", width=float(0.25e-6), length=float(0.25e-6), technology=TechDummy(), ) dut_open.add_data(test_data_path / "dummy_open_freq.mdm", key="ac") lib.add_duts([dut_short, dut_open]) # --->Clean the names of all dataframes, e.g. VB=>V_B for dut_a in lib: dut_a.clean_data( fallback={ "S_DEEMB(1,1)": None, "S_DEEMB(2,1)": None, "S_DEEMB(1,2)": None, "S_DEEMB(2,2)": None, } ) # emulate forced specifiers col_vb = specifiers.VOLTAGE + "B" col_ve = specifiers.VOLTAGE + "E" col_vc = specifiers.VOLTAGE + "C" for key in lib.dut_ref.data.keys(): lib.dut_ref.data[key][col_vb + sub_specifiers.FORCED] = lib.dut_ref.data[key][col_vb] lib.dut_ref.data[key][col_vc + sub_specifiers.FORCED] = lib.dut_ref.data[key][col_vc] lib.dut_ref.data[key][col_ve + sub_specifiers.FORCED] = lib.dut_ref.data[key][col_ve] return lib def create_mcard(): mc_D21 = MCard( ["C", "B", "E", "S", "T"], default_module_name="", default_subckt_name="", va_file=folder_path.parent / "test_core_no_interfaces" / "test_va_code" / "hicuml2" / "hicumL2V2p4p0_release.va", ) mc_D21.load_model_parameters( folder_path.parent / "test_core_no_interfaces" / "test_modelcards" / "IHP_ECE704_03_para_D21.mat", ) mc_D21.update_from_vae(remove_old_parameters=True) mc_D21.get_circuit = types.MethodType(get_circuit, mc_D21) return mc_D21 def test_docu_with_sim(): COMMANDS["openvaf"] = "openvaf" lib_test = create_lib() docu = DocuDutLib( lib_test, modelcard_dict={DutType.npn: create_mcard()}, DutCircuitClass=DutNgspice, dut_class_kwargs={ "get_circuit_arguments": {"use_build_in": False}, "command_openvaf": "openvaf", }, ) docu_path = tmp_path / "docu_dut_lib_sim" docu.generate_docu( docu_path, plot_specs=[{"type": "gummel_vbc", "key": "fgummel", "style": "xtraction_color"}], show=False, # not possible in CI/CD save_tikz_settings={ "width": "3in", "height": "5in", "standalone": True, "svg": False, "build": False, # not possible in CI/CD "mark_repeat": 20, "clean": False, # Remove all files except *.pdf files in plots }, ) shutil.rmtree(docu_path) if __name__ == "__main__": mcard = create_mcard() lib_test = test_docu_with_sim() test/test_interface_ngspice/test_dut_ngspice_osdi.py +1 −3 Original line number Diff line number Diff line """ test ngspice input file generation. """ import types import copy from pathlib import Path from DMT.config import COMMANDS COMMANDS["OPENVAF"] = "openvaf" from DMT.core import DutType, Sweep, specifiers, SimCon, Plot, MCard from DMT.core.circuit import ( Circuit, Loading Loading
DMT/core/docu_dut_lib.py +91 −18 Original line number Diff line number Diff line Loading @@ -26,7 +26,17 @@ from typing import Dict, List, Mapping, Sequence, Optional, Union from joblib import Parallel, delayed from scipy import interpolate from DMT.config import COMMAND_TEX, DATA_CONFIG from DMT.core import DutType, DutLib, specifiers, sub_specifiers, specifiers_ss_para from DMT.core import ( DutType, DutLib, specifiers, sub_specifiers, MCard, DutCircuit, DutMeas, Sweep, SimCon, ) from DMT.core.plot import MIX, PLOT_STYLES, natural_scales, Plot from DMT.external.os import recursive_copy, rmtree Loading Loading @@ -307,7 +317,10 @@ class DocuDutLib(object): self, dut_lib: DutLib, devices: Optional[Sequence[Mapping[str, object]]] = None, date=None, date: Optional[str] = None, modelcard_dict: Optional[Dict[DutType, MCard]] = None, DutCircuitClass: Optional[DutCircuit] = None, dut_class_kwargs: Optional[Dict] = None, ): self.dut_lib = dut_lib Loading Loading @@ -354,6 +367,31 @@ class DocuDutLib(object): self.plts: List[Plot] = [] self.modelcard_dict = modelcard_dict self.DutCircuitClass = DutCircuitClass if dut_class_kwargs is None: self.dut_class_kwargs = {} else: self.dut_class_kwargs = dut_class_kwargs def get_dut_sim(self, dut_meas: DutMeas) -> DutCircuit: """Retrieve a circuit dut view which should be compared to the given dut_meas""" if self.DutCircuitClass is not None: return self.DutCircuitClass( database_dir=None, dut_type=dut_meas.dut_type, input_circuit=self.modelcard_dict[dut_meas.dut_type], technology=dut_meas.technology, # needed for scaling! width=dut_meas.width, length=dut_meas.length, contact_config=dut_meas.contact_config, nfinger=dut_meas.nfinger, reference_node=dut_meas.reference_node, **self.dut_class_kwargs, ) else: return None def generate_docu( self, target_base_path: Union[str, Path], Loading @@ -376,16 +414,17 @@ class DocuDutLib(object): """ self.create_all_plots(plot_specs) # TODO # technology -> one lib can have more than one technology... # mcard # ADD data from mcard simulation if show and len(self.plts) > 1: for plt in self.plts[:-1]: if show and self.plts: for plt in self.plts: plt.plot_pyqtgraph(show=False) self.plts[-1].plot_pyqtgraph(show=True) self.plts[0].show_pyqtgraph() for plt in self.plts: plt.mw_pg = None plt.pw_pg = None # remove the plot from the object to allow Parallel prcessing # pickle is used to transfer between processes self.generate_all_plots(target_base_path, save_tikz_settings) Loading Loading @@ -415,6 +454,7 @@ class DocuDutLib(object): 'ymax' : 300, #optional, float: Maximum Value on y-axis to be displayed 'ymin' : 0, #optional, float: Minimum Value on y-axis to be displayed 'no_at' : True, #optional, Bool: if True, do not display the "at" quantities in the legend. 'simulate' : True, #optional, Bool: if True, a matching simulation is added to the plot, if not given, default is True }, """ Loading @@ -424,6 +464,7 @@ class DocuDutLib(object): "dut_type": DutType.npn, "no_at": False, # no at_specifier= in legend } sim_con = SimCon() # set defaults for plot_spec in plot_specs: Loading @@ -441,9 +482,7 @@ class DocuDutLib(object): valid_plots = PLOT_DEFAULTS[plot_spec["dut_type"]].keys() if not plot_type in valid_plots: raise IOError( "Plot type " + plot_type + " not valid. Valid: " f"Plot type {plot_type} not valid. Valid: " + " ".join(str(PLOT_DEFAULTS.keys())) + " ." ) Loading @@ -452,7 +491,7 @@ class DocuDutLib(object): raise IOError("Plot style not valid. Valid: " + " ".join(PLOT_STYLES)) if not "key" in plot_spec.keys(): raise IOError("Database key not specified for plot of type " + plot_type + " .") raise IOError(f"Database key not specified for plot of type {plot_type}.") # matching key? if "exact_match" not in plot_spec.keys(): Loading @@ -476,14 +515,20 @@ class DocuDutLib(object): self.plts = [] for plot_spec in plot_specs: plot_type = plot_spec["type"] print("Generating plots of type " + plot_type + " .") print(f"Generating plots of type {plot_type}.") style = plot_spec["style"] print("Chosen plot style: " + style) print(f"Chosen plot style: {style}") for dut in self.duts: if dut.dut_type != plot_spec["dut_type"]: continue if plot_spec.get( "simulate", PLOT_DEFAULTS[dut.dut_type][plot_type].get("simulate", True) ): dut_sim = self.get_dut_sim(dut) else: dut_sim = None quantity_x = plot_spec.get( "quantity_x", PLOT_DEFAULTS[dut.dut_type][plot_type]["quantity_x"] Loading Loading @@ -549,8 +594,8 @@ class DocuDutLib(object): except AttributeError: at_scale_ = natural_scales[at_] if at_ == specifiers.CURRENT + "B" or at_ == specifiers.CURRENT_DENSITY + "B": at_scale_ = at_scale_ * 1e3 # if at_ == specifiers.CURRENT + "B" or at_ == specifiers.CURRENT_DENSITY + "B": # at_scale_ = at_scale_ * 1e3 at_scale.append(at_scale_) Loading @@ -576,6 +621,9 @@ class DocuDutLib(object): temp, plot_spec[specifiers.TEMPERATURE] ): temps.append(dut.get_key_temperature(key)) elif specifiers.TEMPERATURE not in plot_spec: temps.append(dut.get_key_temperature(key)) temps = list(set(temps)) for temp in temps: Loading Loading @@ -762,6 +810,31 @@ class DocuDutLib(object): peaks["jc"].append(np.tile(jc_peak, 10)) peaks["vbc"].append(np.tile(point[0], 10)) if dut_sim is not None: # get a sweep sweep = Sweep.get_sweep_from_dataframe( data=df_tmp, temperature=temp, outputdef=[quantity_x, quantity_y], # othervar={}, ) # simulate sim_con.append_simulation(dut=dut_sim, sweep=sweep) sim_con.run_and_read() # add to plot df_sim = dut_sim.get_data(sweep=sweep) df_sim.ensure_specifier_column( quantity_x, area=AE0_drawn, ports=dut.ac_ports ) df_sim.ensure_specifier_column( quantity_y, area=AE0_drawn, ports=dut.ac_ports ) plt.add_data_set( df_sim[quantity_x].to_numpy(), df_sim[quantity_y].to_numpy(), label=label + " sim", ) plt.x_limits = x_limits plt.y_limits = y_limits Loading
DMT/core/sweep.py +3 −2 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ Features: * Clear syntax and definition to create a well described simulation independent of the simulator interface. """ # DMT_core # Copyright (C) from 2022 SemiMod # Copyright (C) until 2021 Markus Müller, Mario Krattenmacher and Pascal Kuthe Loading Loading @@ -57,9 +58,9 @@ def get_sweepdef( data : DataFrame Frame to extract the sweepdefs from inner_sweep_voltage : SpecifierStr | None, optional A specifier that determiens the inner sweep voltage, by default None A specifier that determins the inner sweep voltage, by default None outer_sweep_voltage : SpecifierStr | None, optional A specifier that determiens the inner outer voltage, by default None A specifier that determins the inner outer voltage, by default None outer_sweep_voltage : SpecifierStr | None, optional A voltage at a third possible contact, that is not swept but may differ from zero. decimals_potentials : int, optional Loading
test/test_interface_ngspice/test_DocuDutLib_simu.py 0 → 100644 +225 −0 Original line number Diff line number Diff line """ Test case for DocuDutLib with simulation comparisions I know.... the simulation data and the measurement data do not align!! They are from two different technologies, but those are the one we have currently at hand. """ import types import logging import shutil from pathlib import Path from DMT.config import COMMANDS from DMT.core import ( DutMeas, DutType, DocuDutLib, DutLib, specifiers, sub_specifiers, Technology, MCard, ) from DMT.core.dut_view import DutView from DMT.ngspice import DutNgspice from test_dut_ngspice_osdi import get_circuit folder_path = Path(__file__).resolve().parent test_path = folder_path.parent tmp_path = test_path / "tmp" test_data_path = test_path / "test_core_no_interfaces" / "test_data" # -->Start main function # --->Setup for log logging.basicConfig( level=logging.DEBUG, format="%(levelname)s - %(message)s", filename=folder_path.parent.parent / "logs" / "test_docudutlib_simu.log", filemode="w", ) class TechDummy(Technology): def __init__(self): super().__init__(name="dummy") def scale_modelcard( self, mcard: MCard, lE0: float, bE0: float, nfinger: int, config: str, dut: DutView = None, lE_drawn_ref: float = None, bE_drawn_ref: float = None, ) -> MCard: # nothing to do here return mcard @staticmethod def deserialize(): return TechDummy() def serialize(self): return { "class": str(self.__class__), "args": [], "kwargs": {}, "constructor": "deserialize", } def create_lib(): """Create a dut lib.""" # -->Define subroutine at first # --->Subroutine: filter_dut def filter_dut(dut_name): if "dummies" in dut_name: return None elif "TLM" in dut_name: return None elif dut_name == "": return None else: dut_transistor = DutMeas( database_dir=tmp_path, dut_type=DutType.npn, force=True, wafer=96, die="y", width=float(0.25e-6), length=float(0.25e-6), contact_config="CBEBC", name="dut_meas_npn", reference_node="E", technology=TechDummy(), ) return dut_transistor # --->Arrange DMT class to dmt lib = DutLib( save_dir=tmp_path / "dut_lib_save", force=True, AC_filter_names=[("freq_vbc", "ac")], DC_filter_names=[("fgummel", "dc")], ) # --->Add source measurement information in dmt and to duts lib.import_directory( import_dir=test_data_path, dut_filter=filter_dut, dut_level=1, force=True, ) lib.dut_ref = lib.duts[0] # --->Add the open and short dummies to the lib dut_short = DutMeas( database_dir=tmp_path, name="dut_short_npn", dut_type=DutType.deem_short_bjt, reference_node="E", force=True, wafer=96, die="y", width=float(0.25e-6), length=float(0.25e-6), technology=TechDummy(), ) dut_short.add_data(test_data_path / "dummy_short_freq.mdm", key="ac") dut_short.add_data(test_data_path / "short_dc.mdm", key="dc") dut_open = DutMeas( database_dir=tmp_path, name="dut_open_npn", dut_type=DutType.deem_open_bjt, reference_node="E", force=True, wafer=96, die="y", width=float(0.25e-6), length=float(0.25e-6), technology=TechDummy(), ) dut_open.add_data(test_data_path / "dummy_open_freq.mdm", key="ac") lib.add_duts([dut_short, dut_open]) # --->Clean the names of all dataframes, e.g. VB=>V_B for dut_a in lib: dut_a.clean_data( fallback={ "S_DEEMB(1,1)": None, "S_DEEMB(2,1)": None, "S_DEEMB(1,2)": None, "S_DEEMB(2,2)": None, } ) # emulate forced specifiers col_vb = specifiers.VOLTAGE + "B" col_ve = specifiers.VOLTAGE + "E" col_vc = specifiers.VOLTAGE + "C" for key in lib.dut_ref.data.keys(): lib.dut_ref.data[key][col_vb + sub_specifiers.FORCED] = lib.dut_ref.data[key][col_vb] lib.dut_ref.data[key][col_vc + sub_specifiers.FORCED] = lib.dut_ref.data[key][col_vc] lib.dut_ref.data[key][col_ve + sub_specifiers.FORCED] = lib.dut_ref.data[key][col_ve] return lib def create_mcard(): mc_D21 = MCard( ["C", "B", "E", "S", "T"], default_module_name="", default_subckt_name="", va_file=folder_path.parent / "test_core_no_interfaces" / "test_va_code" / "hicuml2" / "hicumL2V2p4p0_release.va", ) mc_D21.load_model_parameters( folder_path.parent / "test_core_no_interfaces" / "test_modelcards" / "IHP_ECE704_03_para_D21.mat", ) mc_D21.update_from_vae(remove_old_parameters=True) mc_D21.get_circuit = types.MethodType(get_circuit, mc_D21) return mc_D21 def test_docu_with_sim(): COMMANDS["openvaf"] = "openvaf" lib_test = create_lib() docu = DocuDutLib( lib_test, modelcard_dict={DutType.npn: create_mcard()}, DutCircuitClass=DutNgspice, dut_class_kwargs={ "get_circuit_arguments": {"use_build_in": False}, "command_openvaf": "openvaf", }, ) docu_path = tmp_path / "docu_dut_lib_sim" docu.generate_docu( docu_path, plot_specs=[{"type": "gummel_vbc", "key": "fgummel", "style": "xtraction_color"}], show=False, # not possible in CI/CD save_tikz_settings={ "width": "3in", "height": "5in", "standalone": True, "svg": False, "build": False, # not possible in CI/CD "mark_repeat": 20, "clean": False, # Remove all files except *.pdf files in plots }, ) shutil.rmtree(docu_path) if __name__ == "__main__": mcard = create_mcard() lib_test = test_docu_with_sim()
test/test_interface_ngspice/test_dut_ngspice_osdi.py +1 −3 Original line number Diff line number Diff line """ test ngspice input file generation. """ import types import copy from pathlib import Path from DMT.config import COMMANDS COMMANDS["OPENVAF"] = "openvaf" from DMT.core import DutType, Sweep, specifiers, SimCon, Plot, MCard from DMT.core.circuit import ( Circuit, Loading