Source code for ecdtools.ibis

import re
import logging
from decimal import Decimal

import textparser
from textparser import Sequence
from textparser import choice
from textparser import ZeroOrMore
from textparser import OneOrMore
from textparser import AnyUntil
from textparser import Not
from textparser import Tag
from textparser import tokenize_init
from textparser import Token
from textparser import TokenizeError
from textparser import Optional


__version__ = '0.1.0'

LOGGER = logging.getLogger(__name__)

RE_NUMERICAL = re.compile(r'(-?\d+\.?\d*([eE][+-]?\d+)?)(\w?)(\w*)')

SUFFIX_TO_VALUE = {
    'T': Decimal('1e12'),
    'G': Decimal('1e9'),
    'M': Decimal('1e6'),
    'k': Decimal('1e3'),
    'm': Decimal('1e-3'),
    'u': Decimal('1e-6'),
    'n': Decimal('1e-9'),
    'p': Decimal('1e-12'),
    'f': Decimal('1e-15')
}


class Error(Exception):
    pass


class InternalError(Exception):
    pass


class TypMinMax(object):

    def __init__(self):
        self.typical = None
        self.minimum = None
        self.maximum = None


class Package(object):

    def __init__(self):
        self.r_pkg = TypMinMax()
        self.l_pkg = TypMinMax()
        self.c_pkg = TypMinMax()


class Pin(object):

    def __init__(self):
        self.name = None
        self.signal_name = None
        self.model_name = None
        self.r_pin = None
        self.l_pin = None
        self.c_pin = None


class DiffPin(object):

    def __init__(self):
        self.name = None
        self.inv_pin = None
        self.vdiff = None
        self.tdelay_typ = None
        self.tdelay_min = None
        self.tdelay_max = None


class Component(object):

    def __init__(self):
        self.name = None
        self.si_location = None
        self.timing_location = None
        self.manufacturer = None
        self.package = Package()
        self.pins = []
        self.diff_pins = []


class AddSubmodel(object):

    def __init__(self):
        self.submodel = None
        self.submodel_mode = None


class Ramp(object):

    def __init__(self):
        self.dv_dt_r = None
        self.dv_dt_f = None
        self.r_load = None


class WaveformTable(object):

    def __init__(self):
        self.samples = []


class Waveform(object):

    def __init__(self):
        self.r_fixture = None
        self.v_fixture = TypMinMax()
        self.table = WaveformTable()


class ModelSelectorModel(object):

    def __init__(self, name, description):
        self.name = name
        self.description = description


class ModelSelector(object):

    def __init__(self):
        self.name = None
        self.models = []


class Model(object):

    def __init__(self):
        self.name = None
        self.model_type = None
        self.polarity = None
        self.enable = None
        self.vinl = None
        self.vinh = None
        self.c_comp = TypMinMax()
        self.vmeas = None
        self.cref = None
        self.vref = None
        self.rref = None
        self.temperature_range = TypMinMax()
        self.voltage_range = TypMinMax()
        self.pullup_reference = TypMinMax()
        self.pulldown_reference = TypMinMax()
        self.power_clamp_reference = TypMinMax()
        self.gnd_clamp_reference = TypMinMax()
        self.gnd_clamp = None
        self.power_clamp = None
        self.pullup = None
        self.pulldown = None
        self.ramp = None
        self.falling_waveforms = []
        self.rising_waveforms = []
        self.add_submodel = []


class SubmodelSpec(object):

    def __init__(self):
        self.v_trigger_r = TypMinMax()
        self.v_trigger_f = TypMinMax()
        self.off_delay = TypMinMax()


class Submodel(object):

    def __init__(self):
        self.name = None
        self.submodel_type = None
        self.submodel_spec = None


KEYWORDS = set([
    '[ibis ver]',
    '[comment char]',
    '[file name]',
    '[file rev]',
    '[date]',
    '[source]',
    '[notes]',
    '[disclaimer]',
    '[copyright]',
    '[component]',
    '[manufacturer]',
    '[package]',
    '[pin]',
    '[diff pin]',
    '[series switch groups]',
    '[model selector]',
    '[model]',
    '[add submodel]',
    '[temperature range]',
    '[voltage range]',
    '[pullup reference]',
    '[pulldown reference]',
    '[power clamp reference]',
    '[gnd clamp reference]',
    '[gnd clamp]',
    '[power clamp]',
    '[pullup]',
    '[pulldown]',
    '[ramp]',
    '[falling waveform]',
    '[rising waveform]',
    '[submodel]',
    '[submodel spec]',
    '[end]'
])


class Parser(textparser.Parser):

    def tokenize(self, string):
        token_specs = [
            ('SKIP',     r'\r+|\s*\|[^\n]*'),
            ('NL',       r'\n'),
            ('KEYWORD',  r'\[.+?\]'),
            ('WORD',     r'[^ \n\t\r\f\v=]+'),
            ('WS',       r'[ \t\r\f\v]+'),
            ('EQ',       r'='),
            ('MISMATCH', r'.')
        ]

        tokens, token_regex = tokenize_init(token_specs)

        for mo in re.finditer(token_regex, string, re.DOTALL):
            kind = mo.lastgroup

            if kind == 'SKIP':
                pass
            elif kind != 'MISMATCH':
                value = mo.group(kind)

                if kind == 'KEYWORD':
                    keyword = value.lower().replace('_', ' ')

                    if keyword in KEYWORDS:
                        kind = keyword

                tokens.append(Token(kind, value, mo.start()))
            else:
                raise TokenizeError(string, mo.start())

        return tokens

    def grammar(self):
        nls = OneOrMore(Sequence('NL', Optional('WS')))

        any_until_keyword = AnyUntil(Sequence('NL', choice(*KEYWORDS)))

        any_until_nl = AnyUntil(choice('NL', '__EOF__'))

        sub_parameter = Tag('SubParameter',
                            Sequence(nls, 'WORD', 'WS', 'WORD'))

        sub_parameter_typ_min_max = Tag('SubParameterTypMinMax',
                                        Sequence(nls, 'WORD',
                                                 'WS', 'WORD',
                                                 'WS', 'WORD',
                                                 'WS', 'WORD'))

        numerical_sub_parameter = Tag('NumericalSubParameter',
                                      Sequence(nls,
                                               'WORD',
                                               Optional('WS'),
                                               'EQ',
                                               Optional('WS'),
                                               'WORD'))

        ibis_ver = Sequence(Optional(nls),
                            '__SOF__',
                            Optional(nls),
                            '[ibis ver]', any_until_nl)

        comment_char = Sequence('[comment char]')

        file_name = Sequence('[file name]', any_until_nl)

        file_rev = Sequence('[file rev]', any_until_nl)

        date = Sequence('[date]', any_until_nl)

        source = Sequence('[source]', any_until_keyword)

        notes = Sequence('[notes]', any_until_keyword)

        disclaimer = Sequence('[disclaimer]', any_until_keyword)

        copyright_ = Sequence('[copyright]', any_until_keyword)

        component = Sequence('[component]', any_until_nl,
                             ZeroOrMore(Sequence(nls, 'WORD', 'WS', 'WORD')))

        manufacturer = Sequence('[manufacturer]', any_until_nl)

        package = Sequence('[package]',
                           ZeroOrMore(Sequence(nls, 'WORD',
                                               'WS', 'WORD',
                                               'WS', 'WORD',
                                               'WS', 'WORD')))

        pin = Sequence('[pin]',
                       'WS', 'WORD',
                       'WS', 'WORD',
                       Optional(Sequence('WS', 'WORD',
                                         'WS', 'WORD',
                                         'WS', 'WORD')),
                       ZeroOrMore(choice(Tag('All',
                                             Sequence(nls,
                                                      Optional('WS'), 'WORD',
                                                      'WS', 'WORD',
                                                      'WS', 'WORD',
                                                      'WS', 'WORD',
                                                      'WS', 'WORD',
                                                      'WS', 'WORD')),
                                         Tag('Triple',
                                             Sequence(nls,
                                                      Optional('WS'), 'WORD',
                                                      'WS', 'WORD',
                                                      'WS', 'WORD')))))

        diff_pin = Sequence('[diff pin]',
                            'WS', 'WORD',
                            'WS', 'WORD',
                            'WS', 'WORD',
                            'WS', 'WORD',
                            'WS', 'WORD',
                            ZeroOrMore(Sequence(nls, 'WORD',
                                                'WS', 'WORD',
                                                'WS', 'WORD',
                                                'WS', 'WORD',
                                                'WS', 'WORD',
                                                'WS', 'WORD')))

        series_switch_groups = Sequence('[series switch groups]',
                                        ZeroOrMore(Sequence(nls, any_until_nl)))

        model_selector = Sequence('[model selector]', 'WS', 'WORD',
                                  ZeroOrMore(Sequence(nls,
                                                      'WORD',
                                                      'WS',
                                                      any_until_nl)))

        model = Sequence('[model]', 'WS', 'WORD',
                         ZeroOrMore(choice(Tag('Quad',
                                               Sequence(nls, 'WORD',
                                                        'WS', 'WORD',
                                                        'WS', 'WORD',
                                                        'WS', 'WORD')),
                                           sub_parameter,
                                           numerical_sub_parameter)))

        add_submodel = Sequence('[add submodel]',
                                ZeroOrMore(Sequence(nls, 'WORD', 'WS', 'WORD')))

        temperature_range = Sequence('[temperature range]',
                                     'WS', 'WORD',
                                     'WS', 'WORD',
                                     'WS', 'WORD')

        voltage_range = Sequence('[voltage range]',
                                 'WS', 'WORD',
                                 'WS', 'WORD',
                                 'WS', 'WORD')

        pullup_reference = Sequence('[pullup reference]',
                                    'WS', 'WORD',
                                    'WS', 'WORD',
                                    'WS', 'WORD')

        pulldown_reference = Sequence('[pulldown reference]',
                                      'WS', 'WORD',
                                      'WS', 'WORD',
                                      'WS', 'WORD')

        power_clamp_reference = Sequence('[power clamp reference]',
                                         'WS', 'WORD',
                                         'WS', 'WORD',
                                         'WS', 'WORD')

        gnd_clamp_reference = Sequence('[gnd clamp reference]',
                                       'WS', 'WORD',
                                       'WS', 'WORD',
                                       'WS', 'WORD')

        quad_table = ZeroOrMore(Sequence(nls,
                                         Optional('WS'), 'WORD',
                                         'WS', 'WORD',
                                         'WS', 'WORD',
                                         'WS', 'WORD'))

        gnd_clamp = Sequence('[gnd clamp]', quad_table)

        power_clamp = Sequence('[power clamp]', quad_table)

        pullup = Sequence('[pullup]', quad_table)

        pulldown = Sequence('[pulldown]', quad_table)

        ramp = Sequence('[ramp]',
                        ZeroOrMore(choice(numerical_sub_parameter,
                                          sub_parameter_typ_min_max)))

        waveform = ZeroOrMore(choice(Tag('TableEntry',
                                         Sequence(nls,
                                                  Optional('WS'), 'WORD',
                                                  'WS', 'WORD',
                                                  'WS', 'WORD',
                                                  'WS', 'WORD')),
                                     numerical_sub_parameter))

        falling_waveform = Sequence('[falling waveform]', waveform)

        rising_waveform = Sequence('[rising waveform]', waveform)

        submodel = Sequence('[submodel]', 'WS', 'WORD',
                            OneOrMore(sub_parameter))

        submodel_spec = Sequence('[submodel spec]',
                                 OneOrMore(sub_parameter_typ_min_max))

        unknown_keyword = Sequence('KEYWORD', any_until_keyword)

        end = Sequence('[end]')

        ibis_file = Sequence(
            ibis_ver,
            ZeroOrMore(Sequence(nls,
                                choice(comment_char,
                                       file_name,
                                       file_rev,
                                       date,
                                       source,
                                       notes,
                                       disclaimer,
                                       copyright_,
                                       component,
                                       manufacturer,
                                       package,
                                       pin,
                                       diff_pin,
                                       series_switch_groups,
                                       model_selector,
                                       model,
                                       add_submodel,
                                       temperature_range,
                                       voltage_range,
                                       pullup_reference,
                                       pulldown_reference,
                                       power_clamp_reference,
                                       gnd_clamp_reference,
                                       gnd_clamp,
                                       power_clamp,
                                       pullup,
                                       pulldown,
                                       ramp,
                                       falling_waveform,
                                       rising_waveform,
                                       submodel,
                                       submodel_spec,
                                       unknown_keyword,
                                       end))))

        return ibis_file


[docs]class IbsFile(object): """An .ibs file. """ def __init__(self, string, transform): self._ibis_version = None self._file_name = None self._file_revision = None self._date = None self._source = None self._notes = None self._disclaimer = None self._copyright = None self._components = [] self._model_selectors = [] self._models = [] self._submodels = [] self._transform = transform string = string.replace('\r', '') string = re.sub(r'[ \t]+\n', '\n', string) tokens = Parser().parse(string, token_tree=True, match_sof=True) self._ibis_version = self._load_string([tokens[0][4]]) for item in tokens[1]: keyword = item[1][0].kind data = item[1][1:] if keyword == '[file name]': self._file_name = self._load_string(data) elif keyword == '[file rev]': self._file_revision = self._load_string(data) elif keyword == '[date]': self._date = self._load_string(data) elif keyword == '[source]': self._source = self._load_string(data) elif keyword == '[notes]': self._notes = self._load_string(data) elif keyword == '[disclaimer]': self._disclaimer = self._load_string(data) elif keyword == '[copyright]': self._copyright = self._load_string(data) elif keyword == '[component]': self._load_component(data) elif keyword == '[manufacturer]': self._components[-1].manufacturer = self._load_string(data) elif keyword == '[package]': self._load_package(data) elif keyword == '[pin]': self._load_pin(data) elif keyword == '[diff pin]': self._load_diff_pin(data) elif keyword == '[model selector]': self._load_model_selector(data) elif keyword == '[model]': self._load_model(data) elif keyword == '[add submodel]': self._load_add_submodel(data) elif keyword == '[temperature range]': self._load_temperature_range(data) elif keyword == '[voltage range]': self._load_voltage_range(data) elif keyword == '[pullup reference]': self._load_pullup_reference(data) elif keyword == '[pulldown reference]': self._load_pulldown_reference(data) elif keyword == '[power clamp reference]': self._load_power_clamp_reference(data) elif keyword == '[gnd clamp reference]': self._load_gnd_clamp_reference(data) elif keyword == '[gnd clamp]': self._models[-1].gnd_clamp = self._load_4_columns(data) elif keyword == '[power clamp]': self._models[-1].power_clamp = self._load_4_columns(data) elif keyword == '[pullup]': self._models[-1].pullup = self._load_4_columns(data) elif keyword == '[pulldown]': self._models[-1].pulldown = self._load_4_columns(data) elif keyword == '[ramp]': self._load_ramp(data) elif keyword == '[falling waveform]': waveform = self._load_waveform(data) self._models[-1].falling_waveforms.append(waveform) elif keyword == '[rising waveform]': waveform = self._load_waveform(data) self._models[-1].rising_waveforms.append(waveform) elif keyword == '[submodel]': self._load_submodel(data) elif keyword == '[submodel spec]': self._load_submodel_spec(data) elif keyword == '[end]': pass else: LOGGER.debug('Unsupported keyword %s.', item[1][0].value) @property def component_names(self): """A list of all component names. """ return sorted([component.name for component in self._components]) @property def model_selector_names(self): """A list of all model selector names. """ return sorted([model_selector.name for model_selector in self._model_selectors]) @property def model_names(self): """A list of all model names. """ return sorted([model.name for model in self._models])
[docs] def get_component_by_name(self, name): """Get the component named `name`. """ for component in self._components: if component.name == name: return component raise Error('Expected component name {}, but got {}.'.format( format_or(self.component_names), name))
[docs] def get_model_selector_by_name(self, name): """Get the model selector named `name`. """ for model_selector in self._model_selectors: if model_selector.name == name: return model_selector raise Error('Expected model selector name {}, but got {}.'.format( format_or(self.model_selector_names), name))
[docs] def get_model_by_name(self, name): """Get the model named `name`. """ for model in self._models: if model.name == name: return model raise Error('Expected model name {}, but got {}.'.format( format_or(self.model_names), name))
def _load_component(self, tokens): component = Component() component.name = tokens[0][1].value for sub_param in tokens[1]: if sub_param[1].value == 'Si_location': component.si_location = sub_param[3].value elif sub_param[1].value == 'Timing_location': component.timing_location = sub_param[3].value else: LOGGER.debug('Unsupported [Component] sub-parameter %s.', sub_param[1].value) self._components.append(component) def _load_package(self, tokens): package = self._components[-1].package for _, sub_param, _, typical, _, minimum, _, maximum in tokens[0]: if sub_param.value == 'R_pkg': package.r_pkg.typical = self._load_numerical(typical) package.r_pkg.minimum = self._load_numerical(minimum) package.r_pkg.maximum = self._load_numerical(maximum) elif sub_param.value == 'L_pkg': package.l_pkg.typical = self._load_numerical(typical) package.l_pkg.minimum = self._load_numerical(minimum) package.l_pkg.maximum = self._load_numerical(maximum) elif sub_param.value == 'C_pkg': package.c_pkg.typical = self._load_numerical(typical) package.c_pkg.minimum = self._load_numerical(minimum) package.c_pkg.maximum = self._load_numerical(maximum) else: raise Error('Invalid [Package] sub-parameter %s.', sub_param.value) def _load_pin(self, tokens): pins = self._components[-1].pins for tag, data in tokens[5]: pin = Pin() if tag == 'All': pin.name = data[2].value pin.signal_name = data[4].value pin.model_name = data[6].value pin.r_pin = self._load_numerical(data[8]) pin.l_pin = self._load_numerical(data[10]) pin.c_pin = self._load_numerical(data[12]) elif tag == 'Triple': pin.name = data[2].value pin.signal_name = data[4].value pin.model_name = data[6].value else: raise InternalError('Bad tag {}.'.format(tag)) pins.append(pin) def _load_diff_pin(self, tokens): diff_pins = self._components[-1].diff_pins for line in tokens[10]: diff_pin = DiffPin() diff_pin.name = line[1].value diff_pin.inv_pin = line[3].value diff_pin.vdiff = line[5].value diff_pin.tdelay_typ = line[7].value diff_pin.tdelay_min = line[9].value diff_pin.tdelay_max = line[11].value diff_pins.append(diff_pin) def _load_model_selector(self, tokens): model_selector = ModelSelector() model_selector.name = tokens[1].value for _, name, _, description in tokens[2]: description = self._load_string([[None] + description]) model = ModelSelectorModel(name.value, description) model_selector.models.append(model) self._model_selectors.append(model_selector) def _load_model(self, tokens): model = Model() model.name = tokens[1].value for tag, data in tokens[2]: if tag == 'SubParameter': name, value = self._load_sub_parameter(data) if name == 'Model_type': model.model_type = value elif name == 'Polarity': model.polarity = value elif name == 'Enable': model.enable = value else: LOGGER.debug('Unsupported [Model] sub-parameter %s.', name) elif tag == 'NumericalSubParameter': name, value = self._load_numerical_sub_parameter(data) if name == 'Vinl': model.vinl = value elif name == 'Vinh': model.vinh = value elif name == 'Vmeas': model.vmeas = value elif name == 'Cref': model.cref = value elif name == 'Vref': model.vref = value elif name == 'Rref': model.rref = value else: LOGGER.debug('Unsupported [Model] numerical sub-parameter %s.', name) elif tag == 'Quad': if data[1].value =='C_comp': model.c_comp.typical = self._load_numerical(data[3]) model.c_comp.minimum = self._load_numerical(data[5]) model.c_comp.maximum = self._load_numerical(data[7]) else: LOGGER.debug('Unsupported [Model] data %s.', data[1].value) else: raise InternalError('Bad tag {}.'.format(tag)) self._models.append(model) def _load_add_submodel(self, tokens): for _, name, _, value in tokens[0]: add_submodel = AddSubmodel() add_submodel.submodel = name.value add_submodel.submodel_mode = value.value self._models[-1].add_submodel.append(add_submodel) def _load_temperature_range(self, tokens): self._models[-1].temperature_range.typical = self._load_numerical(tokens[1]) self._models[-1].temperature_range.minimum = self._load_numerical(tokens[5]) self._models[-1].temperature_range.maximum = self._load_numerical(tokens[3]) def _load_voltage_range(self, tokens): self._models[-1].voltage_range.typical = self._load_numerical(tokens[1]) self._models[-1].voltage_range.minimum = self._load_numerical(tokens[3]) self._models[-1].voltage_range.maximum = self._load_numerical(tokens[5]) def _load_pullup_reference(self, tokens): self._models[-1].pullup_reference.typical = self._load_numerical(tokens[1]) self._models[-1].pullup_reference.minimum = self._load_numerical(tokens[3]) self._models[-1].pullup_reference.maximum = self._load_numerical(tokens[5]) def _load_pulldown_reference(self, tokens): self._models[-1].pulldown_reference.typical = self._load_numerical(tokens[1]) self._models[-1].pulldown_reference.minimum = self._load_numerical(tokens[3]) self._models[-1].pulldown_reference.maximum = self._load_numerical(tokens[5]) def _load_power_clamp_reference(self, tokens): self._models[-1].power_clamp_reference.typical = self._load_numerical(tokens[1]) self._models[-1].power_clamp_reference.minimum = self._load_numerical(tokens[3]) self._models[-1].power_clamp_reference.maximum = self._load_numerical(tokens[5]) def _load_gnd_clamp_reference(self, tokens): self._models[-1].gnd_clamp_reference.typical = self._load_numerical(tokens[1]) self._models[-1].gnd_clamp_reference.minimum = self._load_numerical(tokens[3]) self._models[-1].gnd_clamp_reference.maximum = self._load_numerical(tokens[5]) def _load_ramp(self, tokens): ramp = Ramp() for tag, data in tokens[0]: if tag == 'SubParameterTypMinMax': name, typical, minimum, maximum = self._load_sub_parameter_typ_min_max( data) if name == 'dV/dt_r': ramp.dv_dt_r = (self._load_ramp_value(typical), self._load_ramp_value(minimum), self._load_ramp_value(maximum)) elif name == 'dV/dt_f': ramp.dv_dt_f = (self._load_ramp_value(typical), self._load_ramp_value(minimum), self._load_ramp_value(maximum)) else: raise Error('Invalid [Ramp] sub-parameter {}.'.format(name)) elif tag == 'NumericalSubParameter': name, value = self._load_numerical_sub_parameter(data) if name == 'R_load': ramp.r_load = value else: raise Error( 'Invalid [Ramp] numerical sub-parameter {}.'.format( name)) else: raise InternalError('Bad tag {}.'.format(tag)) self._models[-1].ramp = ramp def _load_waveform(self, tokens): waveform = Waveform() for tag, data in tokens[0]: if tag == 'NumericalSubParameter': name, value = self._load_numerical_sub_parameter(data) if name == 'R_fixture': waveform.r_fixture = value elif name == 'V_fixture_min': waveform.v_fixture.minimum = value elif name == 'V_fixture_max': waveform.v_fixture.maximum = value elif name == 'V_fixture': waveform.v_fixture.typical = value else: LOGGER.debug( 'Unsupported [Rising/Falling Waveform] numerical ' 'sub-parameter %s.', name) elif tag == 'TableEntry': waveform.table.samples.append((self._load_numerical(data[2]), self._load_numerical(data[4]), self._load_numerical(data[6]), self._load_numerical(data[8]))) else: raise InternalError('Bad tag {}.'.format(tag)) return waveform def _load_submodel(self, tokens): submodel = Submodel() submodel.name = tokens[1].value for tag, data in tokens[2]: if tag == 'SubParameter': name, value = self._load_sub_parameter(data) if name == 'Submodel_type': submodel.submodel_type = value else: LOGGER.debug('Unsupported [Submodel] sub-parameter %s.', name) else: raise InternalError('Bad tag {}.'.format(tag)) self._submodels.append(submodel) def _load_submodel_spec(self, tokens): submodel_spec = SubmodelSpec() for tag, data in tokens[0]: if tag == 'SubParameterTypMinMax': (name, typical, minimum, maximum) = self._load_numerical_sub_parameter_typ_min_max( data) if name == 'V_trigger_r': submodel_spec.v_trigger_r.typical = typical submodel_spec.v_trigger_r.minimum = minimum submodel_spec.v_trigger_r.maximum = maximum elif name == 'V_trigger_f': submodel_spec.v_trigger_f.typical = typical submodel_spec.v_trigger_f.minimum = minimum submodel_spec.v_trigger_f.maximum = maximum elif name == 'Off_delay': submodel_spec.off_delay.typical = typical submodel_spec.off_delay.minimum = minimum submodel_spec.off_delay.maximum = maximum else: LOGGER.debug( 'Unsupported [Submodel spec] sub-parameter %s.', name) else: raise InternalError('Bad tag {}.'.format(tag)) self._submodels[-1].submodel_spec = submodel_spec def _load_numerical(self, data): value = data.value if self._transform: if value == 'NA': value = None else: value = convert_numerical(value) return value def _load_sub_parameter(self, data): return data[1].value, data[3].value def _load_numerical_sub_parameter(self, data): if self._transform: value = self._load_numerical(data[5]) else: value = data[5].value return data[1].value, value def _load_sub_parameter_typ_min_max(self, data): return data[1].value, data[3].value, data[5].value, data[7].value def _load_numerical_sub_parameter_typ_min_max(self, data): return (data[1].value, self._load_numerical(data[3]), self._load_numerical(data[5]), self._load_numerical(data[7])) def _load_string(self, data): return ''.join([text.value for text in data[0][1:]]) def _load_4_columns(self, data): return [ (self._load_numerical(v1), self._load_numerical(v2), self._load_numerical(v3), self._load_numerical(v4)) for _, _, v1, _, v2, _, v3, _, v4 in data[0] ] def _load_ramp_value(self, data): if data == 'NA': if self._transform: data = None else: dv, dt = data.split('/') if self._transform: dv = convert_numerical(dv) dt = convert_numerical(dt) data = (dv, dt) return data @property def ibis_version(self): """The IBIS version string. """ return self._ibis_version @property def file_name(self): """The file name string. """ return self._file_name @property def file_revision(self): """The file revision string. """ return self._file_revision @property def date(self): """The date string. """ return self._date @property def source(self): """The source string. """ return self._source @property def notes(self): """The notes string. """ return self._notes @property def disclaimer(self): """The disclaimer string. """ return self._disclaimer @property def copyright(self): """The copyright string. """ return self._copyright @property def components(self): """A list of all components. """ return self._components @property def models(self): """A list of all models. """ return self._models @property def model_selectors(self): """A list of all model selectors. """ return self._model_selectors @property def submodels(self): """A list of all submodels. """ return self._submodels
[docs]def split_numerical(string): """Split given string into a number, suffix and unit tuple. >>> split_numerical('1.1kOhm') ('1.1', 'k', 'Ohm') """ mo = RE_NUMERICAL.match(string) if not mo: raise Error('Expected a numerical string, but got {}.'.format(string)) number, _, suffix, unit = mo.groups() if suffix not in SUFFIX_TO_VALUE: unit = suffix + unit suffix = '' return number, suffix, unit
[docs]def convert_numerical(string): """Convert given string to a Decimal value. >>> convert_numerical('1.1kOhm') Decimal('1.1e3') """ number, suffix, _ = split_numerical(string) value = Decimal(number) if suffix: value *= SUFFIX_TO_VALUE[suffix] return value
[docs]def load_file(filename, transform=False): """Load given IBIS file and return an IbsFile object with its contents. Give `transform` as ``True`` to convert numerical numbers from strings to ``decimal.Decimal`` and ``'NA'`` to ``None``. """ with open(filename, 'r') as fin: string = fin.read() return IbsFile(string, transform)
def format_or(items): items = [str(item) for item in items] if len(items) == 0: return '' elif len(items) == 1: return items[0] else: return '{} or {}'.format(', '.join(items[:-1]), items[-1])