InSpice 1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- inspice-1.6/InSpice/Cache/__init__.py +174 -0
- inspice-1.6/InSpice/Config/ConfigInstall.py +65 -0
- inspice-1.6/InSpice/Config/__init__.py +0 -0
- inspice-1.6/InSpice/Config/logging.yml +51 -0
- inspice-1.6/InSpice/DeviceLibrary/__init__.py +105 -0
- inspice-1.6/InSpice/Doc/ExampleTools.py +49 -0
- inspice-1.6/InSpice/Doc/__init__.py +0 -0
- inspice-1.6/InSpice/Export/Hdf5.py +126 -0
- inspice-1.6/InSpice/Export/__init__.py +0 -0
- inspice-1.6/InSpice/KiCad/__init__.py +150 -0
- inspice-1.6/InSpice/Logging/Logging.py +94 -0
- inspice-1.6/InSpice/Logging/__init__.py +0 -0
- inspice-1.6/InSpice/Math/Calculus.py +164 -0
- inspice-1.6/InSpice/Math/__init__.py +46 -0
- inspice-1.6/InSpice/Physics/MaterialProperties.py +40 -0
- inspice-1.6/InSpice/Physics/PhysicalConstants.py +64 -0
- inspice-1.6/InSpice/Physics/Resistor.py +30 -0
- inspice-1.6/InSpice/Physics/SemiConductor.py +66 -0
- inspice-1.6/InSpice/Physics/__init__.py +0 -0
- inspice-1.6/InSpice/Plot/BodeDiagram.py +60 -0
- inspice-1.6/InSpice/Plot/__init__.py +0 -0
- inspice-1.6/InSpice/Probe/Plot.py +43 -0
- inspice-1.6/InSpice/Probe/WaveForm.py +497 -0
- inspice-1.6/InSpice/Probe/__init__.py +0 -0
- inspice-1.6/InSpice/Scripts/Library.py +125 -0
- inspice-1.6/InSpice/Scripts/__init__.py +0 -0
- inspice-1.6/InSpice/Scripts/cir2py.py +96 -0
- inspice-1.6/InSpice/Scripts/inspice_post_installation.py +470 -0
- inspice-1.6/InSpice/Scripts/pyspice_post_installation.py +470 -0
- inspice-1.6/InSpice/Spice/AnalysisParameters.py +526 -0
- inspice-1.6/InSpice/Spice/BasicElement.py +1728 -0
- inspice-1.6/InSpice/Spice/DeviceModel.py +130 -0
- inspice-1.6/InSpice/Spice/Element.py +680 -0
- inspice-1.6/InSpice/Spice/ElementParameter.py +375 -0
- inspice-1.6/InSpice/Spice/FakeDipole.py +90 -0
- inspice-1.6/InSpice/Spice/HighLevelElement.py +866 -0
- inspice-1.6/InSpice/Spice/Library/Library.py +316 -0
- inspice-1.6/InSpice/Spice/Library/SpiceInclude.py +576 -0
- inspice-1.6/InSpice/Spice/Library/__init__.py +28 -0
- inspice-1.6/InSpice/Spice/Library/product-categories/digi-key.yaml +435 -0
- inspice-1.6/InSpice/Spice/Library/product-categories/infineon.yaml +38 -0
- inspice-1.6/InSpice/Spice/Library/product-categories/mouser.yaml +115 -0
- inspice-1.6/InSpice/Spice/Netlist.py +745 -0
- inspice-1.6/InSpice/Spice/NgSpice/ManualExampleExtractor.py +147 -0
- inspice-1.6/InSpice/Spice/NgSpice/ManualExamples.py +7902 -0
- inspice-1.6/InSpice/Spice/NgSpice/RawFile.py +234 -0
- inspice-1.6/InSpice/Spice/NgSpice/Server.py +159 -0
- inspice-1.6/InSpice/Spice/NgSpice/Shared.py +1339 -0
- inspice-1.6/InSpice/Spice/NgSpice/SimulationType.py +90 -0
- inspice-1.6/InSpice/Spice/NgSpice/Simulator.py +126 -0
- inspice-1.6/InSpice/Spice/NgSpice/__init__.py +23 -0
- inspice-1.6/InSpice/Spice/NgSpice/api.h +76 -0
- inspice-1.6/InSpice/Spice/Parser/Ast.py +950 -0
- inspice-1.6/InSpice/Spice/Parser/ElementData.py +141 -0
- inspice-1.6/InSpice/Spice/Parser/HighLevelParser.py +1321 -0
- inspice-1.6/InSpice/Spice/Parser/Parser.py +582 -0
- inspice-1.6/InSpice/Spice/Parser/SpiceSyntax.py +156 -0
- inspice-1.6/InSpice/Spice/Parser/Translator.py +563 -0
- inspice-1.6/InSpice/Spice/Parser/__init__.py +35 -0
- inspice-1.6/InSpice/Spice/Parser/parsetab.py +82 -0
- inspice-1.6/InSpice/Spice/RawFile.py +410 -0
- inspice-1.6/InSpice/Spice/Simulation.py +791 -0
- inspice-1.6/InSpice/Spice/Simulator.py +164 -0
- inspice-1.6/InSpice/Spice/StringTools.py +98 -0
- inspice-1.6/InSpice/Spice/Xyce/RawFile.py +175 -0
- inspice-1.6/InSpice/Spice/Xyce/Server.py +140 -0
- inspice-1.6/InSpice/Spice/Xyce/Simulation.py +42 -0
- inspice-1.6/InSpice/Spice/Xyce/Simulator.py +76 -0
- inspice-1.6/InSpice/Spice/Xyce/__init__.py +0 -0
- inspice-1.6/InSpice/Spice/__init__.py +85 -0
- inspice-1.6/InSpice/Spice/unit.py +100 -0
- inspice-1.6/InSpice/Tools/EnumFactory.py +176 -0
- inspice-1.6/InSpice/Tools/PathTools.py +60 -0
- inspice-1.6/InSpice/Tools/TextBuffer.py +59 -0
- inspice-1.6/InSpice/Tools/__init__.py +0 -0
- inspice-1.6/InSpice/Unit/SiUnits.py +330 -0
- inspice-1.6/InSpice/Unit/Unit.py +1907 -0
- inspice-1.6/InSpice/Unit/__init__.py +238 -0
- inspice-1.6/InSpice/__init__.py +39 -0
- inspice-1.6/InSpice.egg-info/PKG-INFO +117 -0
- inspice-1.6/InSpice.egg-info/SOURCES.txt +186 -0
- inspice-1.6/InSpice.egg-info/dependency_links.txt +1 -0
- inspice-1.6/InSpice.egg-info/entry_points.txt +2 -0
- inspice-1.6/InSpice.egg-info/requires.txt +11 -0
- inspice-1.6/InSpice.egg-info/top_level.txt +1 -0
- inspice-1.6/LICENSE.txt +661 -0
- inspice-1.6/MANIFEST.in +14 -0
- inspice-1.6/PKG-INFO +117 -0
- inspice-1.6/README.md +79 -0
- inspice-1.6/examples/.travis/travis.py +3 -0
- inspice-1.6/examples/Settings.py +12 -0
- inspice-1.6/examples/advanced-usages/index.rst +5 -0
- inspice-1.6/examples/advanced-usages/internal-device-parameters.py +93 -0
- inspice-1.6/examples/analyses/analyses.py +201 -0
- inspice-1.6/examples/analyses/pole_zero_analysis.py +60 -0
- inspice-1.6/examples/analyses/test_pole_zero.cir +11 -0
- inspice-1.6/examples/basic-usages/index.rst +5 -0
- inspice-1.6/examples/basic-usages/netlist-manipulations.py +70 -0
- inspice-1.6/examples/basic-usages/raw-spice.py +36 -0
- inspice-1.6/examples/basic-usages/skidl-like.py +177 -0
- inspice-1.6/examples/basic-usages/subcircuit.py +62 -0
- inspice-1.6/examples/basic-usages/unit.py +107 -0
- inspice-1.6/examples/c-examples/ngspice-shared/test-module.py +68 -0
- inspice-1.6/examples/c-examples/ngspice-shared/test.py +225 -0
- inspice-1.6/examples/c-examples/ngspice_cb/examples/adder_mos.cir +66 -0
- inspice-1.6/examples/data-analysis/fft.py +103 -0
- inspice-1.6/examples/diode/RingModulator.py +41 -0
- inspice-1.6/examples/diode/diode-characteristic-curve.py +204 -0
- inspice-1.6/examples/diode/diode-recovery-time.py +158 -0
- inspice-1.6/examples/diode/index.rst +7 -0
- inspice-1.6/examples/diode/rectification.py +152 -0
- inspice-1.6/examples/diode/ring-modulator.py +92 -0
- inspice-1.6/examples/diode/voltage-multiplier.py +70 -0
- inspice-1.6/examples/diode/zener-characteristic-curve.py +79 -0
- inspice-1.6/examples/electricity/three-phase.py +99 -0
- inspice-1.6/examples/filter/low-pass-rc-filter.py +59 -0
- inspice-1.6/examples/filter/rlc-filter.py +124 -0
- inspice-1.6/examples/fundamental-laws/index.rst +61 -0
- inspice-1.6/examples/fundamental-laws/millman-theorem.py +81 -0
- inspice-1.6/examples/fundamental-laws/thevenin-norton-theorem.py +91 -0
- inspice-1.6/examples/fundamental-laws/voltage-current-divider.py +79 -0
- inspice-1.6/examples/index.rst +11 -0
- inspice-1.6/examples/kicadrw/dump-netlist.py +28 -0
- inspice-1.6/examples/ngspice-shared/external-source.py +100 -0
- inspice-1.6/examples/ngspice-shared/index.rst +12 -0
- inspice-1.6/examples/ngspice-shared/ngspice-interpreter.py +87 -0
- inspice-1.6/examples/operational-amplifier/OperationalAmplifier-api-brainstorming.py +58 -0
- inspice-1.6/examples/operational-amplifier/OperationalAmplifier.py +59 -0
- inspice-1.6/examples/operational-amplifier/astable.py +57 -0
- inspice-1.6/examples/operational-amplifier/operational-amplifier.py +50 -0
- inspice-1.6/examples/passive/capacitor-inductor.py +116 -0
- inspice-1.6/examples/persistance/SimulateCircuit.py +39 -0
- inspice-1.6/examples/persistance/cache.py +40 -0
- inspice-1.6/examples/persistance/hdf5.py +40 -0
- inspice-1.6/examples/persistance/index.rst +5 -0
- inspice-1.6/examples/persistance/pickling.py +87 -0
- inspice-1.6/examples/persistance/test-diskcache.py +80 -0
- inspice-1.6/examples/power-supplies/HP54501A.py +28 -0
- inspice-1.6/examples/power-supplies/capacitive-half-wave-rectification-post-zener.py +74 -0
- inspice-1.6/examples/power-supplies/capacitive-half-wave-rectification-pre-zener.py +78 -0
- inspice-1.6/examples/power-supplies/hp54501a-cem.py +68 -0
- inspice-1.6/examples/power-supplies/kicad/capacitive-half-wave-rectification-pre-zener/capacitive-half-wave-rectification-pre-zener.cir +13 -0
- inspice-1.6/examples/power-supplies/rectification.py +152 -0
- inspice-1.6/examples/relay/relay.py +71 -0
- inspice-1.6/examples/resistor/resistor-bridge.py +32 -0
- inspice-1.6/examples/resistor/voltage-divider.py +37 -0
- inspice-1.6/examples/skywater/print_subcircuit_nodes.py +54 -0
- inspice-1.6/examples/spice-examples/ac-coupled-amplifier.cir +18 -0
- inspice-1.6/examples/spice-examples/ac-coupled-transistor-amplifier.cir +25 -0
- inspice-1.6/examples/spice-examples/astable.cir +33 -0
- inspice-1.6/examples/spice-examples/diode-ac.cir +11 -0
- inspice-1.6/examples/spice-examples/diode.cir +18 -0
- inspice-1.6/examples/spice-examples/low-pass-rc-filter.cir +12 -0
- inspice-1.6/examples/spice-examples/operational-amplifier-model-1.cir +31 -0
- inspice-1.6/examples/spice-examples/operational-amplifier-model-2.cir +56 -0
- inspice-1.6/examples/spice-examples/resistor-bridge.cir +15 -0
- inspice-1.6/examples/spice-examples/small-signal-amplifier-with-diodes.cir +26 -0
- inspice-1.6/examples/spice-examples/small-signal-amplifier.cir +16 -0
- inspice-1.6/examples/spice-examples/transform-less-power-supply.cir +48 -0
- inspice-1.6/examples/spice-examples/transistor.cir +14 -0
- inspice-1.6/examples/spice-examples/transistor2.cir +9 -0
- inspice-1.6/examples/spice-examples/voltage-divider.cir +7 -0
- inspice-1.6/examples/spice-parser/bootstrap-example.py +60 -0
- inspice-1.6/examples/spice-parser/index.rst +3 -0
- inspice-1.6/examples/spice-parser/kicad-example.py +151 -0
- inspice-1.6/examples/spice-parser/kicad-pyspice-example/kicad-pyspice-example.cir +17 -0
- inspice-1.6/examples/spice-parser/kicad-spice-example/netlist/kicad-spice-example.default.cir +28 -0
- inspice-1.6/examples/spice-parser/kicad-spice-example/netlist/kicad-spice-example.number-node.cir +28 -0
- inspice-1.6/examples/spice-parser/kicad-spice-example/netlist/kicad-spice-example.using-X.cir +28 -0
- inspice-1.6/examples/spice-parser/kicad-spice-example/spice/components.cir +31 -0
- inspice-1.6/examples/spice-parser/kicad-spice-example/spice/example.cir +25 -0
- inspice-1.6/examples/spice-parser/parse-ngspice-examples.py +98 -0
- inspice-1.6/examples/spice-parser/parse-subcircuit-example.py +35 -0
- inspice-1.6/examples/spice-parser/raw_spice_parser.py +104 -0
- inspice-1.6/examples/spice-parser/raw_spice_parser_LM358.py +78 -0
- inspice-1.6/examples/switched-power-supplies/buck-converter.py +131 -0
- inspice-1.6/examples/switched-power-supplies/buck-converter_ngshared.py +170 -0
- inspice-1.6/examples/transformer/Transformer.py +54 -0
- inspice-1.6/examples/transformer/transformer-example.py +55 -0
- inspice-1.6/examples/transistor/ac-coupled-amplifier.py +66 -0
- inspice-1.6/examples/transistor/nmos-transistor.py +63 -0
- inspice-1.6/examples/transistor/transistor.py +145 -0
- inspice-1.6/examples/transmission-lines/time-delay.py +43 -0
- inspice-1.6/examples/xspice/input_clipper.py +57 -0
- inspice-1.6/examples/xspice/xspice.py +167 -0
- inspice-1.6/pyproject.toml +54 -0
- inspice-1.6/setup.cfg +4 -0
- inspice-1.6/setup.py +53 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
#
|
|
3
|
+
# InSpice - A Spice Package for Python
|
|
4
|
+
# Copyright (C) 2021 Fabrice Salvaire
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
#
|
|
19
|
+
####################################################################################################
|
|
20
|
+
|
|
21
|
+
# Simulation outputs should be identical if
|
|
22
|
+
# same simulator and version
|
|
23
|
+
# same inputs
|
|
24
|
+
|
|
25
|
+
__all__ = ["SimulationCache"]
|
|
26
|
+
|
|
27
|
+
####################################################################################################
|
|
28
|
+
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
import hashlib
|
|
31
|
+
|
|
32
|
+
# http://www.grantjenks.com/docs/diskcache
|
|
33
|
+
from diskcache import Cache
|
|
34
|
+
|
|
35
|
+
####################################################################################################
|
|
36
|
+
|
|
37
|
+
class SpiceInclude:
|
|
38
|
+
|
|
39
|
+
INCLUDE_PREFIX = '.include '
|
|
40
|
+
|
|
41
|
+
##############################################
|
|
42
|
+
|
|
43
|
+
def __init__(self, path: str | Path):
|
|
44
|
+
self._path = Path(path)
|
|
45
|
+
self._inner_includes = []
|
|
46
|
+
self._walk()
|
|
47
|
+
self._digest = self.sha1()
|
|
48
|
+
self._recursive_digest = self._compute_recursive_digest()
|
|
49
|
+
|
|
50
|
+
##############################################
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def path(self) -> Path:
|
|
54
|
+
return self._path
|
|
55
|
+
|
|
56
|
+
##############################################
|
|
57
|
+
|
|
58
|
+
def _compute_digest(self, func) -> str:
|
|
59
|
+
with open(self._path, 'rb') as fh:
|
|
60
|
+
_ = func(fh.read()).hexdigest()
|
|
61
|
+
return _
|
|
62
|
+
|
|
63
|
+
##############################################
|
|
64
|
+
|
|
65
|
+
def sha1(self) -> str:
|
|
66
|
+
return self._compute_digest(hashlib.sha1)
|
|
67
|
+
|
|
68
|
+
##############################################
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def parse_include(self, line):
|
|
72
|
+
line = line.strip()
|
|
73
|
+
if line.startswith(self.INCLUDE_PREFIX):
|
|
74
|
+
path = line[len(self.INCLUDE_PREFIX):].strip()
|
|
75
|
+
if path:
|
|
76
|
+
return Path(path)
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
##############################################
|
|
80
|
+
|
|
81
|
+
def _walk(self) -> None:
|
|
82
|
+
with open(self._path, 'r') as fh:
|
|
83
|
+
for line in fh.readlines():
|
|
84
|
+
path = self.parse_include(line)
|
|
85
|
+
if path is not None:
|
|
86
|
+
include = SpiceInclude(path)
|
|
87
|
+
self._inner_includes.append(include)
|
|
88
|
+
|
|
89
|
+
##############################################
|
|
90
|
+
|
|
91
|
+
def _compute_recursive_digest(self) -> str:
|
|
92
|
+
if self._inner_includes:
|
|
93
|
+
return self._digest + '[' + '/'.join([_.digest for _ in self._inner_includes]) + ']'
|
|
94
|
+
else:
|
|
95
|
+
return self._digest
|
|
96
|
+
|
|
97
|
+
##############################################
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def digest(self) -> str:
|
|
101
|
+
return self._digest
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def recursive_digest(self) -> str:
|
|
105
|
+
return self._recursive_digest
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def inner_includes(self) -> str:
|
|
109
|
+
return iter(self._inner_includes)
|
|
110
|
+
|
|
111
|
+
####################################################################################################
|
|
112
|
+
|
|
113
|
+
class SimulationCache:
|
|
114
|
+
|
|
115
|
+
##############################################
|
|
116
|
+
|
|
117
|
+
def __init__(self, path: str | Path=None):
|
|
118
|
+
"""
|
|
119
|
+
Cache directory will be set to a temporary directory like "/tmp/diskcache-...", if *Path* is None.
|
|
120
|
+
"""
|
|
121
|
+
self._cache = Cache(path)
|
|
122
|
+
|
|
123
|
+
##############################################
|
|
124
|
+
|
|
125
|
+
def __del__(self):
|
|
126
|
+
# Each thread that accesses a cache should also call close on the cache.
|
|
127
|
+
self._cache.close()
|
|
128
|
+
|
|
129
|
+
##############################################
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def impl(self) -> Cache:
|
|
133
|
+
return self._cache
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
def directory(self) -> str:
|
|
137
|
+
return self._cache.directory
|
|
138
|
+
|
|
139
|
+
##############################################
|
|
140
|
+
|
|
141
|
+
def simulation_key(self, simulation) -> str:
|
|
142
|
+
raw_spice_code = str(simulation)
|
|
143
|
+
lines = []
|
|
144
|
+
# Replace .include lines by recursive digest
|
|
145
|
+
for line in raw_spice_code.splitlines():
|
|
146
|
+
# for path in simulation.circuit.includes:
|
|
147
|
+
path = SpiceInclude.parse_include(line)
|
|
148
|
+
if path is not None:
|
|
149
|
+
include = SpiceInclude(path)
|
|
150
|
+
lines.append(f'.include {include.path.name} {include.recursive_digest}')
|
|
151
|
+
else:
|
|
152
|
+
lines.append(line)
|
|
153
|
+
# Replace os.linesep to a portable separator
|
|
154
|
+
spice_code = '@@'.join(lines)
|
|
155
|
+
return f'{simulation.simulator_name}/{simulation.simulator_version}/{spice_code}'
|
|
156
|
+
|
|
157
|
+
##############################################
|
|
158
|
+
|
|
159
|
+
def add(self, analysis):
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
##############################################
|
|
163
|
+
|
|
164
|
+
def get(self, simulation):
|
|
165
|
+
pass
|
|
166
|
+
|
|
167
|
+
####################################################################################################
|
|
168
|
+
|
|
169
|
+
class CachedSimulation:
|
|
170
|
+
|
|
171
|
+
##############################################
|
|
172
|
+
|
|
173
|
+
def __init__(self, spice_code):
|
|
174
|
+
pass
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
####################################################################################################
|
|
8
|
+
|
|
9
|
+
from InSpice.Tools import PathTools
|
|
10
|
+
|
|
11
|
+
####################################################################################################
|
|
12
|
+
|
|
13
|
+
class OsFactory:
|
|
14
|
+
|
|
15
|
+
##############################################
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
if sys.platform.startswith('linux'):
|
|
19
|
+
self._name = 'linux'
|
|
20
|
+
elif sys.platform.startswith('win'):
|
|
21
|
+
self._name = 'windows'
|
|
22
|
+
elif sys.platform.startswith('darwin'):
|
|
23
|
+
self._name = 'osx'
|
|
24
|
+
|
|
25
|
+
##############################################
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def name(self):
|
|
29
|
+
return self._name
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def on_linux(self):
|
|
33
|
+
return self._name == 'linux'
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def on_windows(self):
|
|
37
|
+
return self._name == 'windows'
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def on_osx(self):
|
|
41
|
+
return self._name == 'osx'
|
|
42
|
+
|
|
43
|
+
OS = OsFactory()
|
|
44
|
+
|
|
45
|
+
####################################################################################################
|
|
46
|
+
|
|
47
|
+
_this_file = Path(__file__).absolute()
|
|
48
|
+
|
|
49
|
+
class Path:
|
|
50
|
+
|
|
51
|
+
InSpice_module_directory = _this_file.parents[1]
|
|
52
|
+
config_directory = _this_file.parent
|
|
53
|
+
|
|
54
|
+
####################################################################################################
|
|
55
|
+
|
|
56
|
+
class Logging:
|
|
57
|
+
|
|
58
|
+
default_config_file = 'logging.yml'
|
|
59
|
+
directories = (Path.config_directory,)
|
|
60
|
+
|
|
61
|
+
##############################################
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def find(config_file):
|
|
65
|
+
return PathTools.find(config_file, Logging.directories)
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
#
|
|
3
|
+
# ANSI Codes
|
|
4
|
+
#
|
|
5
|
+
# RESET \033[0m
|
|
6
|
+
# COLOR \033[1;%dm
|
|
7
|
+
# BOLD \033[1m
|
|
8
|
+
#
|
|
9
|
+
####################################################################################################
|
|
10
|
+
|
|
11
|
+
version: 1
|
|
12
|
+
|
|
13
|
+
####################################################################################################
|
|
14
|
+
|
|
15
|
+
formatters:
|
|
16
|
+
|
|
17
|
+
simple:
|
|
18
|
+
format: '%(asctime)s - %(name)s - %(module)s.%(levelname)s - %(message)s'
|
|
19
|
+
|
|
20
|
+
ansi:
|
|
21
|
+
format: '<ESC>[1;32m%(asctime)s<ESC>[0m - <ESC>[1;34m%(name)s.%(funcName)s<ESC>[0m - <ESC>[1;31m%(levelname)s<ESC>[0m - %(message)s'
|
|
22
|
+
|
|
23
|
+
####################################################################################################
|
|
24
|
+
|
|
25
|
+
handlers:
|
|
26
|
+
|
|
27
|
+
console:
|
|
28
|
+
class: logging.StreamHandler
|
|
29
|
+
# level: INFO
|
|
30
|
+
# formatter: ansi
|
|
31
|
+
stream: ext://sys.stdout
|
|
32
|
+
|
|
33
|
+
####################################################################################################
|
|
34
|
+
|
|
35
|
+
# InSpice.Doc.ExampleTools.find_libraries
|
|
36
|
+
root:
|
|
37
|
+
# level: CRITICAL
|
|
38
|
+
# level: ERROR
|
|
39
|
+
level: WARNING
|
|
40
|
+
# level: INFO
|
|
41
|
+
# level: DEBUG
|
|
42
|
+
handlers: [console]
|
|
43
|
+
|
|
44
|
+
####################################################################################################
|
|
45
|
+
|
|
46
|
+
loggers:
|
|
47
|
+
|
|
48
|
+
InSpice:
|
|
49
|
+
# level: DEBUG
|
|
50
|
+
level: INFO
|
|
51
|
+
# level: WARNING
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
#
|
|
3
|
+
# InSpice - A Spice Package for Python
|
|
4
|
+
# Copyright (C) 2017 Fabrice Salvaire
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
#
|
|
19
|
+
####################################################################################################
|
|
20
|
+
|
|
21
|
+
####################################################################################################
|
|
22
|
+
|
|
23
|
+
class Manufacturer:
|
|
24
|
+
|
|
25
|
+
##############################################
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
name,
|
|
30
|
+
url=None,
|
|
31
|
+
):
|
|
32
|
+
self._name = name
|
|
33
|
+
self._url = url
|
|
34
|
+
|
|
35
|
+
##############################################
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def name(self):
|
|
39
|
+
return self._name
|
|
40
|
+
|
|
41
|
+
@name.setter
|
|
42
|
+
def name(self, value):
|
|
43
|
+
self._name = value
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def url(self):
|
|
47
|
+
return self._url
|
|
48
|
+
|
|
49
|
+
@url.setter
|
|
50
|
+
def url(self, value):
|
|
51
|
+
self._url = value
|
|
52
|
+
|
|
53
|
+
####################################################################################################
|
|
54
|
+
|
|
55
|
+
class Footprint:
|
|
56
|
+
|
|
57
|
+
##############################################
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
name,
|
|
62
|
+
):
|
|
63
|
+
self._name = name
|
|
64
|
+
|
|
65
|
+
##############################################
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def name(self):
|
|
69
|
+
return self._name
|
|
70
|
+
|
|
71
|
+
@name.setter
|
|
72
|
+
def name(self, value):
|
|
73
|
+
self._name = value
|
|
74
|
+
|
|
75
|
+
####################################################################################################
|
|
76
|
+
|
|
77
|
+
class Device:
|
|
78
|
+
|
|
79
|
+
##############################################
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
name,
|
|
84
|
+
manufacturer,
|
|
85
|
+
datasheet_url=None,
|
|
86
|
+
model_url=None
|
|
87
|
+
):
|
|
88
|
+
# part
|
|
89
|
+
# part_number
|
|
90
|
+
# footprint
|
|
91
|
+
# description
|
|
92
|
+
# device_category x/y
|
|
93
|
+
# pins
|
|
94
|
+
# features / parameters
|
|
95
|
+
self._name = name
|
|
96
|
+
|
|
97
|
+
##############################################
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def name(self):
|
|
101
|
+
return self._name
|
|
102
|
+
|
|
103
|
+
@name.setter
|
|
104
|
+
def name(self, value):
|
|
105
|
+
self._name = value
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
#
|
|
3
|
+
# InSpice - A Spice Package for Python
|
|
4
|
+
# Copyright (C) 2017 Fabrice Salvaire
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
#
|
|
19
|
+
####################################################################################################
|
|
20
|
+
|
|
21
|
+
__all__ = ['find_libraries', 'LIBRARY_PATH']
|
|
22
|
+
|
|
23
|
+
####################################################################################################
|
|
24
|
+
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
import logging
|
|
27
|
+
import os
|
|
28
|
+
import sys
|
|
29
|
+
|
|
30
|
+
####################################################################################################
|
|
31
|
+
|
|
32
|
+
_module_logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
####################################################################################################
|
|
35
|
+
|
|
36
|
+
LIBRARY_PATH = 'spice-library'
|
|
37
|
+
|
|
38
|
+
def find_libraries(root: str='examples') -> Path:
|
|
39
|
+
try:
|
|
40
|
+
library_path = os.environ['InSpiceLibraryPath']
|
|
41
|
+
except KeyError:
|
|
42
|
+
examples_root = Path(sys.argv[0]).resolve() # path of the Python file
|
|
43
|
+
while True:
|
|
44
|
+
examples_root = examples_root.parents[1]
|
|
45
|
+
if examples_root.name == root:
|
|
46
|
+
break
|
|
47
|
+
library_path = examples_root.joinpath(LIBRARY_PATH)
|
|
48
|
+
_module_logger.info(f'SPICE library path is {library_path}')
|
|
49
|
+
return library_path
|
|
File without changes
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
####################################################################################################
|
|
2
|
+
#
|
|
3
|
+
# InSpice - A Spice Package for Python
|
|
4
|
+
# Copyright (C) 2021 Fabrice Salvaire
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Affero General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
#
|
|
19
|
+
####################################################################################################
|
|
20
|
+
|
|
21
|
+
__all__ = ["Hdf5File"]
|
|
22
|
+
|
|
23
|
+
####################################################################################################
|
|
24
|
+
|
|
25
|
+
# File structure
|
|
26
|
+
# using h5ls -r simulation.hdf5
|
|
27
|
+
#
|
|
28
|
+
# / Group
|
|
29
|
+
# /version Dataset {SCALAR}
|
|
30
|
+
# /simulation Group
|
|
31
|
+
# /abscissas Group
|
|
32
|
+
# /abscissas/time Dataset {10038}
|
|
33
|
+
# /branches Group
|
|
34
|
+
# /branches/e.xdz.ev1 Dataset {10038}
|
|
35
|
+
# /branches/...
|
|
36
|
+
# /elements Group
|
|
37
|
+
# /internal_parameters Group
|
|
38
|
+
# /nodes Group
|
|
39
|
+
# /nodes/1 Dataset {10038}
|
|
40
|
+
# /nodes/...
|
|
41
|
+
|
|
42
|
+
# h5dump -g "/simulation" simulation.hdf5
|
|
43
|
+
# h5dump -d "/abscissas/time" simulation.hdf5
|
|
44
|
+
# h5dump -d "/nodes/1" simulation.hdf5
|
|
45
|
+
|
|
46
|
+
####################################################################################################
|
|
47
|
+
|
|
48
|
+
import pickle
|
|
49
|
+
|
|
50
|
+
import numpy as np
|
|
51
|
+
|
|
52
|
+
# https://docs.h5py.org/en/stable/index.html
|
|
53
|
+
import h5py
|
|
54
|
+
|
|
55
|
+
####################################################################################################
|
|
56
|
+
|
|
57
|
+
class Hdf5File:
|
|
58
|
+
|
|
59
|
+
_VERSION = 1
|
|
60
|
+
|
|
61
|
+
##############################################
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def save(cls, analysis, path):
|
|
65
|
+
self = cls(path, 'w')
|
|
66
|
+
self._save(analysis)
|
|
67
|
+
|
|
68
|
+
##############################################
|
|
69
|
+
|
|
70
|
+
def __init__(self, path, mode=None):
|
|
71
|
+
self._file = h5py.File(path, mode)
|
|
72
|
+
|
|
73
|
+
##############################################
|
|
74
|
+
|
|
75
|
+
def _save(self, analysis):
|
|
76
|
+
self._file["version"] = self._VERSION
|
|
77
|
+
|
|
78
|
+
simulation = analysis.simulation
|
|
79
|
+
group = self._file.create_group("simulation")
|
|
80
|
+
attrs = group.attrs
|
|
81
|
+
attrs["simulator"] = simulation.simulator.SIMULATOR
|
|
82
|
+
attrs["simulator_version"] = simulation.simulator_version
|
|
83
|
+
attrs["simulation_date"] = str(simulation.simulation_date)
|
|
84
|
+
attrs["simulation_duration"] = str(simulation.simulation_duration)
|
|
85
|
+
attrs["spice_circuit"] = str(simulation.circuit)
|
|
86
|
+
attrs["spice_simulation"] = str(simulation) # Fixme: remove desk
|
|
87
|
+
# https://docs.h5py.org/en/stable/strings.html#how-to-store-raw-binary-data
|
|
88
|
+
attrs["pickled_simulation"] = np.void(pickle.dumps(simulation))
|
|
89
|
+
|
|
90
|
+
self._abscissa = self._file.create_group("abscissas")
|
|
91
|
+
for list_name in ("nodes", "branches", "elements", "internal_parameters"):
|
|
92
|
+
group = self._file.create_group(list_name)
|
|
93
|
+
for waveform in getattr(analysis, list_name).values():
|
|
94
|
+
self._add_waveform(group, waveform)
|
|
95
|
+
|
|
96
|
+
##############################################
|
|
97
|
+
|
|
98
|
+
def _add_waveform_common(self, group, waveform):
|
|
99
|
+
dset = group.create_dataset(
|
|
100
|
+
waveform.name,
|
|
101
|
+
data=waveform,
|
|
102
|
+
compression="gzip", compression_opts=9
|
|
103
|
+
# compression="lzf
|
|
104
|
+
)
|
|
105
|
+
attrs = dset.attrs
|
|
106
|
+
attrs["unit"] = str(waveform.unit)
|
|
107
|
+
return dset
|
|
108
|
+
|
|
109
|
+
##############################################
|
|
110
|
+
|
|
111
|
+
def _add_abscissa(self, abscissa):
|
|
112
|
+
# Fixme: is time always unique ???
|
|
113
|
+
# See https://docs.h5py.org/en/stable/high/group.html#hard-links
|
|
114
|
+
if abscissa.name not in self._abscissa:
|
|
115
|
+
# self._abscissa[abscissa.name] = abscissa
|
|
116
|
+
self._add_waveform_common(self._abscissa, abscissa)
|
|
117
|
+
return self._abscissa[abscissa.name]
|
|
118
|
+
|
|
119
|
+
##############################################
|
|
120
|
+
|
|
121
|
+
def _add_waveform(self, group, waveform):
|
|
122
|
+
dset = self._add_waveform_common(group, waveform)
|
|
123
|
+
attrs = dset.attrs
|
|
124
|
+
if waveform.title:
|
|
125
|
+
attrs["title"] = waveform.title
|
|
126
|
+
attrs["abscissa"] = self._add_abscissa(waveform.abscissa).ref
|
|
File without changes
|