diff options
| author | Clément Zrounba <6691770+clement-z@users.noreply.github.com> | 2023-09-30 23:06:01 +0200 |
|---|---|---|
| committer | Clément Zrounba <6691770+clement-z@users.noreply.github.com> | 2023-09-30 23:26:46 +0200 |
| commit | ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982 (patch) | |
| tree | 21f27be782ce11c6d00b96ce100a2bff88141b2e /pyspecs/specs.py | |
| download | specs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.tar.gz specs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.zip | |
Initial release
Diffstat (limited to 'pyspecs/specs.py')
| -rw-r--r-- | pyspecs/specs.py | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/pyspecs/specs.py b/pyspecs/specs.py new file mode 100644 index 0000000..ca0d6f9 --- /dev/null +++ b/pyspecs/specs.py @@ -0,0 +1,236 @@ +import numpy as np +import matplotlib.pyplot as plt +import pandas as pd +import subprocess +import time +from .specsparse import * + +""" +Ideas: + - generate value files + - generate netlists based on graph representations + - simulate + - paralel run + - others? + +""" + +default_settings = { + "o": "traces/delete_me.vcd", + "abstol": 1e-8, + "reltol": 1e-4 +} + + + +def create_arguments_netlist(netlist_file, output_file, abstol, reltol): + """ Function called by specs.simulate(), generates + the argument string for the command-line tool. + + Returns: + arguments (list of str): + Formatted list of arguments required by SPECS + """ + + arguments_dictionary = { "f":netlist_file, + "o":output_file, + "abstol":abstol, + "reltol":reltol + } + + arguments = create_arguments_dictionary(arguments_dictionary) + + return arguments + + +def create_arguments_dictionary(arguments_dictionary:dict): + """ Function called by specs.simulate(), generates + the argument string for the command-line tool. + + Args: + arguments_dictionary (dict): + The keys of this dictionary are keywords expected + by SPECS, while their contents hold their value. + + Example: {"f":"circuit.txt", "o":"data.vcd"," + "abstol":1e-8, "reltol":1e-4 + } + + Returns: + arguments (list of str): + Formatted list of arguments required by SPECS + """ + + arguments = [] + + for keyword_string in arguments_dictionary: + value = arguments_dictionary[keyword_string] + + # Long keywords are prepended with double dash + if len(keyword_string) > 1: + keyword_string = "--" + keyword_string + else: + keyword_string = "-" + keyword_string + + arguments.append(keyword_string) + if value is not None: + arguments.append(str(value)) + + return arguments + +def run_and_time(simulator_command, arguments, verbose): + """Function that runs SPECS and times it. + + This is BLOCKING execution, so not intended for paralel + usage. For this case, use par_run(). + + Args: + simulator_command (str): + The command to call SPECS comprised of + its directory and simulator name. Ex: ./specs + arguments (str): + Command-line arguments passed to SPECS + verbose (bool): + If true, will print SPECS output to the Python shell + Returns: + time_ms: + Execution time of SPECS for that run, in miliseconds (ms) + """ + + print("Executing SPECS from python. . .") + + #spec_env = {"SC_COPYRIGHT_MESSAGE":"DISABLE"} + + process_call = simulator_command + arguments + + tic_ns = time.perf_counter_ns() + print("Command: ", ' '.join(process_call)) + #p = subprocess.Popen(process_call, env=spec_env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + p = subprocess.Popen(process_call, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + specs_stdout, specs_stderr = p.communicate() + p.wait() + toc_ns = time.perf_counter_ns() + + time_ms = (toc_ns - tic_ns)*1e-6 + + specs_return_code = p.returncode + print("Execution finished with code: ", specs_return_code) + + if (not specs_return_code == 0) or (verbose): + print("SPECS had an error. Here is the full output: ") + for line in specs_stdout.splitlines(): + print(line.decode(encoding='utf-8', errors='ignore')) + + return time_ms, (specs_return_code, specs_stdout) + +def simulate(netlist_file=None, + custom_arguments=None, + simulator_directory="", + verbose=False, + **kwargs): + """Function that call SPECS from the Python shell + + Args: + netlist_file (str): + File containing the netlist description + of the circuit to simulate. Should contain + a simulation directive within it (.tran, .dc, .op). + + The netlist is a text file that can be: + - Created using the KiCAD library of components in + its schematic editor (eeschema) + - Created and edited by hand by knowing the syntax + - Generated proceduraly using scripts. It's a basic .txt + + It can be achieved with custom arguments by defining + {"f": "path/to/file"} in the dict custom_arguments. + + Defaults to "". + + output_file (str, optional): + VCD file containing all the recorded events. + Can be read with GTKWAVE or parsed with parse_vcd() + Defaults to "traces/delete_me.vcd". + + abstol (double, optional): + Field absolute tolerance for propagating events in the simulator. + Is relevant when running circuits with feedback. + + It can be achieved with custom arguments by defining + {"abstol": 1e-8} in the dict custom_arguments. + + Defaults to 1e-8. + + reltol (double, optional): + Field relative tolerance for propagating events in the simulator. + Is relevant when running circuits with feedback. + + It can be achieved with custom arguments by defining + {"reltol": 1e-4} in the dict custom_arguments. + + Defaults to 1e-4. + + custom_arguments (dict, optional): + <<< ADVANCED USE >>> + It is possible to call SPECS with many other arguments. + You can consult them by running specs without arguments + in the command line interface. + + If custom_arguments is defined, you need to specify + the netlist as a part of the dictionary. + + There is no specific order that the arguments must follow. + + simulator_directory (str, optional): + SPECS can either be included in the PATH variable + or exist as a standalone executable. In the latter case, + it is necessary to define its location. + + Examples: + simulator_directory = "./" + Means that the executable is in the same + directory as this script." + simulator_directory = "/home/user/Documents/" + Means that the SPECS executable is in that + specific path. + + Defaults to "". + + verbose (bool, optional): + If true, will print all the outputs generated by SPECS + to the Python shell. + """ + + assert((netlist_file is not None) or (custom_arguments is not None)) + + + if 'abstol' in kwargs: + abstol = kwargs['abstol'] + else: + abstol = default_settings['abstol'] + + if 'reltol' in kwargs: + reltol = kwargs['reltol'] + else: + reltol = default_settings['reltol'] + + if 'output_file' in kwargs: + output_file = kwargs['output_file'] + else: + output_file = default_settings['o'] + + arguments = [] + if (netlist_file is not None): + arguments = create_arguments_netlist(netlist_file, output_file, abstol, reltol) + + if (custom_arguments is not None): + current_settings = default_settings.copy() + current_settings.update(custom_arguments) # overwrites defaults with the user input where needed + arguments += create_arguments_dictionary(current_settings) + + simulator_name = "specs" + simulator_command = [simulator_directory + simulator_name] + + outputs = run_and_time(simulator_command, arguments, verbose) + + return outputs |
