Source code for ahkab.ahkab

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
# ahkab.py
# The frontend of the simulator
# Copyright 2006 Giuseppe Venturini

# This file is part of the ahkab simulator.
#
# Ahkab is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 2 of the License.
#
# Ahkab is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License v2
# along with ahkab.  If not, see <http://www.gnu.org/licenses/>.

"""

Introduction
============

This is the core module of the simulator. It provides helper functions to save
you the need to call directly the functions in most submodules.

Do you have a circuit?
======================

To run a simulation, you'll need a circuit first: a circuit can be described
with a simulation deck or with a circuit object.

Define your circuit by means of a Circuit object
------------------------------------------------

In a Python script, describing the circuit through the
:class:`ahkab.circuit.Circuit` interface is a very versatile a choice.

Refer to :class:`ahkab.circuit.Circuit` for a complete description of the
process and the documentation of several helper functions to assist you in this
task.

You may then jump to :ref:`create-simulation-object`.

Define your circuit by means of a netlist file
----------------------------------------------

The circuit description can also be provided as a text file, also known as
netlist deck, for historical reason. This file will also typically include
simulation and post-processing directives, such as plotting.

The netlist should be described according to the rules in
:doc:`help/Netlist-Syntax`.

If you have a netlist (simulation deck) available, you have several possibilities.

The first, assuming your netlist defines some simulation would be to run it:

* you may call ``ahkab`` from the command line. The command line interface is
  described in :doc:`help/Command-Line-Help`.
* you may call :func:`main` directly from Python. Running the simulation through
  :func:`main` function allows to process the result in Python.

Alternatively, you may parse the netlist through
:func:`ahkab.netlist_parser.parse_circuit`, which will return the circuit
instance, all the simulations defined in the deck and all the post-processing
directives as well.

You may now modify the circuit and simulation objects as you please, or create
new ones, as well as run them as described in the :ref:`run-it` section.

.. _create-simulation-object:

How to create a simulation object
=================================

Next, you need to have a simulation object you would like to run.

The following functions are available to quickly create a simulation object:

.. autosummary::
    new_ac
    new_dc
    new_op
    new_pss
    new_pz
    new_symbolic
    new_tran

Click on one of the above hyperlinks to be taken to the corresponding
documentation section.

.. note::

    The functions above allow you to specify an output file. This is due to two
    main reasons:

    * Saving to a file allows you to keep a copy of the simulation results,
      which you can then inspect at a later time.
    * Simulation results may take an uncomfortably large amount of memory. The
      approach we take is that we save everything to file, and only load the
      data to memory when the user actually accesses it.

    In order for the latter to work when no output file is specified, ``ahkab``
    stores the simulation data in a temporary file provided by your OS. When the
    user exits the Python interpreter (or IPython or debugger), the file is
    removed.

.. _run-it:

Run it!
=======

Once you have a circuit and one or more simulations, it's time to run them!

The following methods are available to do so:

.. autosummary::
    run
    queue

The :func:`run` function will return the results in dictionary form.

Extras
======

The core module also contains a few extra methods which were deemed important
enough to be inserted here.

In particular, the :func:`get_op_x0` method allows the user to quickly compute
an operating point to be used to specify the linearization point for a more
complex analysis and :func:`icmodified_x0` allows the user to modify said
operating point to take into account the user-specified initial conditions in
the circuit description.

Lastly, :func:`set_temperature` can be used to quickly set the simulation
temperature.

All methods in alphabetical order
==================================

"""

from __future__ import (unicode_literals, absolute_import,
                        division, print_function)

import atexit
import copy
import os
import sys
import tempfile

from optparse import OptionParser

import numpy as np
import scipy as sp
import sympy
import tabulate
try:
    import matplotlib
    plotting_available = True
except ImportError:
    plotting_available = False

# analyses
from . import dc_analysis
from . import transient
from . import ac
from . import pss
from . import symbolic
from . import pz

# parser
from . import netlist_parser

# misc
from . import options
from . import constants
from . import utilities

# post-processing
from . import fourier

# data display
from . import plotting
from . import printing

#py3 compat
from .py3compat import text_type

from .__version__ import __version__

global _queue, _x0s, _print

_queue = []
_print = False
_x0s = {None: None}

[docs]def new_op(guess=None, x0=None, outfile=None, verbose=0): """Assembles an OP analysis and returns the analysis object. The analysis itself can then be run with: ``ahkab.run(...)`` or queued with ``ahkab.queue(...)`` and then run subsequently. **Parameters:** guess : boolean, optional if set to True, the analysis will start from an initial guess, hopefully speeding up the convergence of stiff circuits. x0 : matrix, optional In alternative to the ``guess`` option above, one can provide an explicit starting point to the OP algorithm, setting x0 to an opportunely sized ``numpy`` array. FIXME mention help method here If both x0 and guess are set, x0 takes the precedence. outfile : string, optional the filename of the output file where the results will be written. ``.opinfo`` is automatically added at the end to prevent different analyses from overwriting each-other's results. If unset or set to None, defaults to ``stdout``, if the simulator was called from the command line, otherwise, if the simulator is run from an interactive session, a temporary file will be used to store the data. verbose : int, optional the verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** an : dict the analysis description .. seealso:: :func:`run`, :func:`queue` """ if guess is None: guess = options.dc_use_guess if outfile is None or outfile == 'stdout': if options.cli: outfile = 'stdout' else: tmpfile = tempfile.NamedTemporaryFile(suffix='.op', delete=False) outfile = tmpfile.name tmpfile.close() atexit.register(os.remove, outfile) else: outfile += '.op' return {'type': 'op', 'guess': guess, 'x0': x0, 'outfile': outfile, 'verbose': verbose}
[docs]def new_dc(start, stop, points, source, sweep_type='LINEAR', guess=True, x0=None, outfile=None, verbose=0): """Assembles a DC sweep analysis and returns the analysis object. The analysis itself can be run with: ``ahkab.run(...)`` or queued and then run subsequently. **Parameters:** start : float the start value for the sweep. stop : float the stop value for the sweep (included in the sweep points). points : int the number of sweep points. source : string the ``part_id`` of the independent current or voltage source to be swept. sweep_type : string, optional can be set to either ``options.dc_lin_step`` (linear stepping) or ``options.dc_log_step`` (log10 stepping). Defaults to linear. guess : boolean, optional if set to ``True``, the analysis will start from an initial guess, hopefully speeding up the convergence of particularly stiff circuits. x0 : ``numpy`` array, optional if the ``guess`` option above is not used, one can provide a starting point directly, setting ``x0`` to an opportunely sized ``numpy`` array. If both ``x0`` and ``guess`` are set, ``x0`` takes the precedence. outfile : string, optional the filename of the output file where the results will be written. '.dc' is automatically added at the end to prevent different analyses from overwriting each-other's results. If unset or set to ``None``, defaults to ``stdout``, if the simulator was called from the command line, otherwise, if the simulator is run from an interactive session, a temporary file will be used to store the data. verbose : int, optional the verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** an : dict the analysis description .. seealso:: :func:`run`, :func:`queue` """ if outfile is None or outfile == 'stdout': if options.cli: outfile = 'stdout' else: tmpfile = tempfile.NamedTemporaryFile(suffix='.dc', delete=False) outfile = tmpfile.name tmpfile.close() atexit.register(os.remove, outfile) else: outfile += '.dc' return { 'type': 'dc', 'start': float(start), 'stop': float(stop), 'step': float(stop - start) / float(points - 1), 'source': source, 'x0': x0, 'outfile': outfile, 'guess': guess, 'sweep_type': sweep_type, 'verbose': verbose}
[docs]def new_tran(tstart, tstop, tstep, x0='op', method=transient.TRAP, use_step_control=True, outfile=None, verbose=0): """Assembles a TRAN analysis and returns the analysis object. The analysis itself can be run with ``ahkab.run(...)`` or queued with ``ahkab.queue(...)`` and then run subsequently. **Parameters:** tstart : float the start time for the transient analysis. tstop : float the stop time. tstep :float the time step. If the step control is active, this is the minimum time step value that will be allowed during simulation. x0 : ``numpy`` array, optional the optional initial conditions point, :math:`x0 = x(t=0)`. method : string , optional the differentiation method to be used. Can be set to 'IMPLICIT_EULER', 'TRAP', 'GEAR4', 'GEAR5' or 'GEAR6'. It defaults to 'TRAP'. use_step_control : boolean, optional Whether ste control should be enabled or not. if set to ``False``, the differentiation method will use a fixed time step equal to ``tstep``. outfile : string, optional the filename of the output file where the results will be written. '.tran' is automatically added at the end to prevent different analyses from overwriting each-other's results. If unset or set to ``None``, defaults to ``stdout``, if the simulator was called from the command line, otherwise, if the simulator is run from an interactive session, a temporary file will be used to store the data. verbose : int, optional the verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** an : dict the analysis description .. seealso:: :func:`run`, :func:`queue` """ if outfile is None or outfile == 'stdout': if options.cli: outfile = 'stdout' else: tmpfile = tempfile.NamedTemporaryFile(suffix='.tran', delete=False) outfile = tmpfile.name tmpfile.close() atexit.register(os.remove, outfile) else: outfile += '.tran' return {"type": "tran", "tstart": tstart, "tstop": tstop, "tstep": tstep, "method": method, "use_step_control": use_step_control, 'x0': x0, 'outfile': outfile, 'verbose': verbose}
[docs]def new_ac(start, stop, points, x0='op', sweep_type='LOG', outfile=None, verbose=0): """Assembles an AC analysis and returns the analysis object. The analysis itself can be run with ``ahkab.run(...)`` or queued with ``ahkab.queue(...)`` and then run subsequently. **Parameters:** start : float the start angular frequency, :math:`\omega _{start}`. stop : float the stop angular frequency, :math:`\omega _{stop}` (included in the sweep). points : float the number of points to be used the discretize the `[start, stop]` interval. x0 : string or ndarray, optional The linearization point for the AC analysis. If set to 'op' (default), the latest Operating point analysis will be used. Otherwise, you may supply your own linearization point in ndarray format. sweep_type : string, optional It can be set to either ``options.ac_lin_step`` (linear stepping) or ``options.ac_log_step`` (log10 stepping). Defaults to logarithmic stepping. outfile : string, optional the filename of the output file where the results will be written. '.ac' is automatically added at the end to prevent different analyses from overwriting each-other's results. If unset or set to ``None``, defaults to ``stdout``, if the simulator was called from the command line, otherwise, if the simulator is run from an interactive session, a temporary file will be used to store the data. verbose : int, optional the verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** an : dict the analysis object (a dict) .. seealso:: :func:`run`, :func:`queue` """ if outfile is None or outfile == 'stdout': if options.cli: outfile = 'stdout' else: tmpfile = tempfile.NamedTemporaryFile(suffix='.ac', delete=False) outfile = tmpfile.name tmpfile.close() atexit.register(os.remove, outfile) else: outfile += '.ac' return { 'type': 'ac', 'start': start, 'stop': stop, 'points': points, 'sweep_type': sweep_type, 'x0': x0, 'outfile': outfile, 'verbose': verbose}
[docs]def new_pss(period, x0=None, points=None, method=options.BFPSS, autonomous=False, outfile=None, verbose=0): """Assembles a Periodic Steady State (PSS) analysis and returns the analysis object. The analysis itself can be run with: ``ahkab.run(...)`` or queued with ``ahkab.queue(...)`` and then run subsequently. **Parameters:** period : float the time period of the solution, in seconds. This value is required, autonomous circuits are currently unsupported. x0 : ``numpy`` array, optional the starting point solution, used at :math:`t=0`. points : int, optional the number of points to use to discretize the PSS solution. If not set, if method is 'shooting', defaults to ``options.shooting_default_points`` method : string, optional The method to be employed to attempt a PSS solution of the circuit. It can be either ``ahkab.BFPSS`` or ``ahkab.SHOOTING``. autonomous : bool, optional Whether the circuit is autonomous or not. Non-autonomous circuits are currently unsupported! mna, Tf, D : ``numpy`` arrays, optional The matrices to be used to solve the circuit. They are optional, if they have already been computed, reusing them saves time. outfile : string, optional The filename of the output file where the results will be written. '.tran' is automatically added at the end to prevent different analyses from overwriting each-other's results. If unset or set to ``None``, defaults to ``stdout``, if the simulator was called from the command line, otherwise, if the simulator is run from an interactive session, a temporary file will be used to store the data. verbose : int, optional The verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** an : dict the analysis object (a dict) .. seealso:: :func:`run`, :func:`queue` """ if outfile is None or outfile == 'stdout': if options.cli: outfile = 'stdout' else: tmpfile = tempfile.NamedTemporaryFile(suffix='.'+method.lower(), delete=False) outfile = tmpfile.name tmpfile.close() atexit.register(os.remove, outfile) else: outfile += '.' + method.lower() return { 'type': "pss", "method": method, 'period': period, 'points': points, 'autonomous': autonomous, 'x0': x0, 'outfile': outfile, 'verbose': verbose}
[docs]def new_pz(input_source=None, output_port=None, shift=0.0, MNA=None, outfile=None, x0='op', verbose=0): """Assembles a Pole-Zero analysis and returns the analysis object. The analysis itself can be run with: ``ahkab.run(...)`` or queued with ``ahkab.queue(...)`` and then run subsequently. **Parameters:** input_source : str or instance the input source for zero calculation output_port : tuple or single node the output port. If it is composed of only one node, then the second node is assumed to be GND. shift : float, optional Perform the calculation at a shifted freq ``shift``. MNA : ndarray, optional the numpy matrix to be used to solve the circuit. It is optional, but, if it's already been computed, reusing it will save time. outfile : string, optional The filename of the output file where the results will be written. '.pz' is automatically added at the end to prevent different analyses from overwriting each-other's results. If unset or set to ``None``, defaults to ``stdout``, if the simulator was called from the command line, otherwise, if the simulator is run from an interactive session, a temporary file will be used to store the data. x0 : ``numpy`` array or str, optional the optional linearization point. If set to a string, it must be the result of an .OP analysis (use ``'op'``) or an .IC condition defined in the netlist. It has no effect on linear circuits. verbose : int, optional The verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** an : the analysis description object, a dict instance. """ if outfile is None or outfile == 'stdout': if options.cli: outfile = 'stdout' else: tmpfile = tempfile.NamedTemporaryFile(suffix='.pz', delete=False) outfile = tmpfile.name tmpfile.close() atexit.register(os.remove, outfile) else: outfile += '.pz' return {'type': "pz", 'input_source':input_source, 'x0':x0, 'output_port':output_port, 'shift':shift, 'MNA':MNA, 'outfile':outfile, 'verbose':verbose}
[docs]def new_symbolic(source=None, ac_enable=True, r0s=False, subs=None, outfile=None, verbose=0): """Assembles a Symbolic analysis and returns the analysis object. The analysis itself can be run with ``ahkab.run(...)`` or queued with ``ahkab.queue(...)`` and then run subsequently. **Parameters:** source : string, optional if ``source`` is set, the transfer function between the current or voltage source ``source`` and each circuit unknown will be evaluated, with symbolic evaluation of DC gain, poles and zeros. ``source`` is to be set to the ``part_id`` of an independent current or voltage source in the circuit, eg. ``'V1'`` or ``'Iin'``. This computation should be avoided for large circuit, as indiscriminate transfer function, gain and singularities evaluation in large circuits can result in very long run times and needs a significant amount of RAM, on top of an already resource intensive symbolic analysis. We suggest manually evaluating selected transfer functions of interest instead. ac_enable : bool, optional If set to ``True`` (default), the frequency-dependent elements will be considered, otherwise the algorithm will focus on low frequency solutions, where all capacitors are replaced with open circuits and all inductors are short circuits, usually providing a much easier circuit. r0s : bool, optional If set to ``True``, the finite output conductances of transistors ``go`` (where :math:`go = 1/r_0`) will be taken into account, otherwise they will be considered infinite (default). The finite output conductances generally introduce a significant additional complexity in large circuits, sometimes of interest to the designer, sometimes simply introducing 2nd and 3rd order effects of little-to-no interest, which would produce no significant contribution in a numerical analysis, but come at a high computation price in a symbolic analysis. A possible approach in those cases may be disabling this option and explicitly introducing additional conductances where deemed of interest. subs : dict, optional ``subs`` is a dictionary of substitutions to be performed before attempting to solve the circuit. For example, if two resistances ``R1`` and ``R2`` are to be equal, set ``subs={'R2':'R1'}`` and ``R1`` will be replaced by an instance of ``R2``. This may simplify the solution (or allow finding one in reasonable time for complex circuits). outfile : string, optional The filename of the output file where the results will be written. '.symbolic' is automatically added at the end to prevent different analyses from overwriting each-other's results. If unset or set to ``None``, defaults to ``stdout``, if the simulator was called from the command line, otherwise, if the simulator is run from an interactive session, a temporary file will be used to store the data. verbose : int, optional The verbosity level, from 0 (silent, default) to 6 (debug). **Returns:** an : dict the analysis description .. seealso:: :func:`run`, :func:`queue` """ if outfile is None or outfile == 'stdout': if options.cli: outfile = 'stdout' else: tmpfile = tempfile.NamedTemporaryFile(suffix='.symbolic', delete=False) outfile = tmpfile.name tmpfile.close() atexit.register(os.remove, outfile) else: outfile += '.symbolic' return { 'type': "symbolic", 'source': source, 'ac_enable': ac_enable, 'r0s': r0s, 'subs': subs, 'outfile': outfile, 'verbose': verbose}
[docs]def queue(*analysis): """Queue one or more analyses to execute them subsequently with :func:`run`. **Parameters** analysis : one or more analysis descriptions. The analyses to be queued. **Returns:** None """ global _queue for an in analysis: # let's hope the user knows what he's doing! _queue += [copy.deepcopy(an)]
[docs]def run(circ, an_list=None): """Run analyses on a circuit. **Parameters:** circ : circuit instance The circuit to be simulated. an_list : list, optional the list of analyses to be performed. If unset, it defaults to those queued with ``queue``. **Returns:** results : dict the results (in dict form) .. seealso:: :func:`queue` """ results = {} if not an_list: an_list = _queue else: an_list = copy.deepcopy(an_list) if type(an_list) == tuple: an_list = list(an_list) elif type(an_list) == dict: an_list = [an_list] # run(mycircuit, op1) while len(an_list): an_item = an_list.pop(0) an_type = an_item.pop('type') if 'x0' in an_item and isinstance(an_item['x0'], text_type): printing.print_warning("%s has x0 set to %s, unavailable. Using 'None'." % (an_type.upper(), an_item['x0'])) an_item['x0'] = None r = analysis[an_type](circ, **an_item) results.update({an_type: r}) if an_type == 'op': _x0s.update({'op': r}) _x0s.update({'op+ic': icmodified_x0(circ, r)}) _handle_netlist_ics(circ, an_list, ic_list=[]) return results
[docs]def new_x0(circ, icdict): """Builds an ``x0`` matrix from user supplied values. Supplying a custom x0 can be useful: - To aid convergence in tough circuits. - To start a transient simulation from a particular x0 **Parameters:** circ : circuit instance The circuit icdict : dict a dictionary specifying the node voltages and branch currents, where appropriate, in V and A, respectively, assembled as shown in the next section. All unspecified node voltages default to ``0`` V and all unspecified currents default to 0. The user-specified values are to be provided as follows: - to specify a nodal voltage: ``{'V(node)':<voltage value>}`` - to specify a branch current: ``'I(<element>)':<current value>}`` Examples: - ``{'V(n1)':2.3, 'V(n2)':0.45, ...}`` - ``{'I(L1)':1.03e-3, I(V4):2.3e-6, ...}`` .. note:: This simulator uses the normal convention, also known as the `Passive sign convention <https://en.wikipedia.org/wiki/Passive_sign_convention>`_. **Returns:** x0 : ``numpy`` array The assembled x0. """ return dc_analysis.build_x0_from_user_supplied_ic(circ, icdict)
[docs]def icmodified_x0(circ, x0): """Modify ``x0`` to take into account the ICs in the circuit. **Parameters:** circ : circuit instance The circuit instance from which the initial conditions are to be extracted. x0 : ``numpy`` array The vector to which the initial conditions are to be applied. """ return dc_analysis.modify_x0_for_ic(circ, x0)
[docs]def get_op_x0(circ): """Shorthand to specify and run an OP analysis to get a linearization point. **Parameters:** circ : circuit instance The circuit instance for which the linearization point is sought. **Returns:** x0 : an OP solution object The linearization point. """ return run(circ, [new_op()])
[docs]def set_temperature(T): """Set the simulation temperature, in Celsius.""" T = float(T) if T > 300: printing.print_warning("The temperature will be set to %f \xB0 C.") constants.T = utilities.Celsius2Kelvin(T)
[docs]def process_postproc(postproc_list, title, results, outfilename): """Runs the post-processing operations, such as plotting. Not meant for end users. deprecated in 0.10 **Parameters:** postproc_list : list, list of post processing operations title : string the deck title results: dict the results to be plotted (which may include including ones that are not needed too). outfilename: string if the plots are saved to disk, this is the filename without extension """ show_plots = False skip_plots = False for postproc in postproc_list: if postproc['type'] == "plot" and outfilename == 'stdout': skip_plots = True printing.print_warning("Plotting and printing the results to " + "stdout are incompatible options. " + "Plotting skipped.") break for index, postproc in enumerate(postproc_list): if postproc['type'] == "plot" and not skip_plots: plotting.plot_results(title, postproc["l2l1"], results[postproc["analysis"]], "%s-%d.%s" % (outfilename, index, options.plotting_outtype)) show_plots = True elif postproc['type'] == "four": for v in postproc['variables']: f, F, THD = fourier.fourier(v, results['tran'], postproc['fund']) printing.print_fourier(v, f, F, THD, outfile='stdout') elif postproc['type'] == "fft": postproc.pop('type') # get rid of spurious entry f, F, THD = fourier.spicefft(tran_results=results['tran'], **postproc) printing.print_spicefft(postproc['label'], f, F, THD, uformat=postproc['uformat'], window=postproc['window'], outfile=outfilename + '.lis'*(outfilename!='stdout')) if show_plots and options.plotting_show_plots: plotting.show_plots()
analysis = {'op': dc_analysis.op_analysis, 'dc': dc_analysis.dc_analysis, 'tran': transient.transient_analysis, 'ac': ac.ac_analysis, 'pss': pss.pss_analysis, 'symbolic': symbolic.symbolic_analysis, 'temp': set_temperature, 'pz':pz.calculate_singularities}
[docs]def main(filename, outfile="stdout", verbose=3): """Method to call ahkab from a Python script with a netlist file. **Parameters:** filename : string The netlist filename. outfile : string, optional The outfiles base name, the suffixes shown below will be added. With the exception of the magic value ``stdout`` which causes ahkab to print out instead of to disk. verbose : int, optional the verbosity level, from 0 (silent) to 6 (debug). It defaults to 3, the same as running ahkab through its command line interface. Filename suffixes, for each analysis: - Alternate Current (AC): ``.ac`` - Direct Current (DC): ``.dc`` - Operating Point (OP): ``.opinfo`` - Periodic Steady State (PSS): ``.pss`` - Pole-zero Analysis (PZ): ``.pz`` - TRANsient (TRAN): ``.tran`` - Symbolic: ``.symbolic`` **Returns:** res : dict A dictionary containing the computed results. """ printing.print_info_line( ("This is ahkab %s running with:" % (__version__), 6), verbose) printing.print_info_line( (" Python %s" % (sys.version.split('\n')[0],), 6), verbose) printing.print_info_line((" Numpy %s" % (np.__version__), 6), verbose) printing.print_info_line((" Scipy %s" % (sp.__version__), 6), verbose) printing.print_info_line((" Sympy %s" % (sympy.__version__), 6), verbose) printing.print_info_line((" Tabulate %s" % (tabulate.__version__), 6), verbose) if plotting_available: printing.print_info_line((" Matplotlib %s" % (matplotlib.__version__), 6), verbose) printing.print_info_line((" -> backend: %s" % (matplotlib.get_backend()), 6), verbose) printing.print_info_line((" -> matplotlibrc: %s" % (matplotlib.matplotlib_fname()), 6), verbose) else: printing.print_info_line( (" Matplotlib not found.", 6), verbose) read_netlist_from_stdin = (filename is None or filename == "-") (circ, directives, postproc_direct) = netlist_parser.parse_circuit( filename, read_netlist_from_stdin) printing.print_info_line(("Checking circuit for common mistakes...", 6), verbose, print_nl=False) check, reason = utilities.check_circuit(circ) if not check: printing.print_general_error(reason) sys.exit(3) printing.print_info_line(("done.", 6), verbose) if verbose > 3 or _print: print("Parsed circuit:") print(circ) print("Models:") for m in circ.models: circ.models[m].print_model() print("") ic_list = netlist_parser.parse_ics(directives) _handle_netlist_ics(circ, an_list=[], ic_list=ic_list) results = {} for an in netlist_parser.parse_analysis(circ, directives): if 'outfile' not in list(an.keys()) or not an['outfile']: an.update( {'outfile': outfile + ("." + an['type']) * (outfile != 'stdout')}) if 'verbose' in list(an.keys()) and (an['verbose'] is None or an['verbose'] < verbose) \ or not 'verbose' in list(an.keys()): an.update({'verbose': verbose}) _handle_netlist_ics(circ, [an], ic_list=[]) if verbose >= 4: printing.print_info_line(("Requested an.:", 4), verbose) printing.print_analysis(an) results.update(run(circ, [an])) postproc_list = netlist_parser.parse_postproc(circ, postproc_direct) if len(postproc_list) > 0 and len(results): process_postproc(postproc_list, circ.title, results, outfile) return results
def _handle_netlist_ics(circ, an_list, ic_list): for ic in ic_list: ic_label = list(ic.keys())[0] icdict = ic[ic_label] _x0s.update({ic_label: new_x0(circ, icdict)}) for an in an_list: if 'x0' in an and isinstance(an['x0'], text_type): if an['x0'] in list(_x0s.keys()): an['x0'] = _x0s[an['x0']] elif an_list.index(an) == 0: raise ValueError(("The x0 '%s' is not available." % an["x0"]) +\ (an['x0'] == 'op' or an['x0'] == 'op+ic')* " Perhaps you forgot to define an .OP?")