PySpice icon indicating copy to clipboard operation
PySpice copied to clipboard

Fix NgSpice shared FFI duplication

Open akrasuski1 opened this issue 7 years ago • 19 comments

When creating more than one NgSpiceShared instances, like in https://pyspice.fabrice-salvaire.fr/examples/ngspice-shared/external-source.html, for example to do two simulations in a row, there was an exception thrown from PySpice:

  File "/usr/local/lib/python3.6/dist-packages/PySpice/Spice/NgSpice/Shared.py", line 356, in __init__
    self._load_library()
  File "/usr/local/lib/python3.6/dist-packages/PySpice/Spice/NgSpice/Shared.py", line 374, in _load_library
    ffi.cdef(f.read())
  File "/usr/local/lib/python3.6/dist-packages/cffi/api.py", line 107, in cdef
    self._cdef(csource, override=override, packed=packed)
  File "/usr/local/lib/python3.6/dist-packages/cffi/api.py", line 121, in _cdef
    self._parser.parse(csource, override=override, **options)
  File "/usr/local/lib/python3.6/dist-packages/cffi/cparser.py", line 315, in parse
    self._internal_parse(csource)
  File "/usr/local/lib/python3.6/dist-packages/cffi/cparser.py", line 355, in _internal_parse
    decl.type, name=decl.name, partial_length_ok=True)
  File "/usr/local/lib/python3.6/dist-packages/cffi/cparser.py", line 587, in _get_type_and_quals
    tp = self._get_struct_union_enum_type('struct', type, name)
  File "/usr/local/lib/python3.6/dist-packages/cffi/cparser.py", line 734, in _get_struct_union_enum_type
    raise CDefError("duplicate declaration of struct %s" % name)
cffi.error.CDefError: <cdef source string>:7: duplicate declaration of struct ngcomplex

Tracing the source of the error showed that global ffi variable in PySpice was filled twice with API structures, which caused it to fail with duplicate declaration error. The simple fix in pull request is to just remember that API data was already read and not do it again.

akrasuski1 avatar Dec 29 '17 18:12 akrasuski1

Also, for anyone having this issue - a temporary workaround, without having to modify PySpice sources, is to reset the FFI before constructing the object:

class Shared(NgSpiceShared):
    def __init__(self, inputs, dt):
        PySpice.Spice.NgSpice.Shared.ffi = FFI()
        super().__init__()

akrasuski1 avatar Dec 29 '17 18:12 akrasuski1

Thanks for reporting this issue.

Could you explain a bit more what you are doing ? Do you mean simulate in parallel a circuit ? As far I know it requires several ngspice libraries clones (cf. user manual).

FabriceSalvaire avatar Jan 08 '18 13:01 FabriceSalvaire

Not necessairly in parallel, but in the same Python script. Right now, even the code I linked to, when pasted twice, will fail with the error I described.

akrasuski1 avatar Jan 08 '18 13:01 akrasuski1

I believe the wrapper must be a singleton due to ngspice design.

Could you provide a basic example ? To be sure on the use case.

FabriceSalvaire avatar Jan 08 '18 13:01 FabriceSalvaire

A dumb example: https://gist.github.com/akrasuski1/d4a0e5c524202b0c3aa2511159101d91

There, I create two experiments, one with voltage divider driven by a sine source, the other with cosine (yeah, I know they are the same, but imagine cosine was square or something). I would expect to be able to analyze the same circuit using both voltage sources (one at a time), but instead, the code crashes.

akrasuski1 avatar Jan 08 '18 13:01 akrasuski1

Thanks it is now clear.

FabriceSalvaire avatar Jan 08 '18 14:01 FabriceSalvaire

Use case is

class Imp1(NgSpiceShared):
    def get_vsrc_data(self, voltage, time, node, ngspice_id):
        ...
    
class Imp2(NgSpiceShared):
    def get_vsrc_data(self, voltage, time, node, ngspice_id):
        ...

But NgSpiceShared is a singleton that must be created by new_instance and not __init__

It is a limitation of NgSpice since we cannot instantiate more than one simulator.

A solution is to implement a switch in the callback :

class MyNgSpiceShared(NgSpiceShared):
    mode = 1
    def get_vsrc_data(self, voltage, time, node, ngspice_id):
        if mode == 1:
            return self.get_vsrc_data1(voltage, time, node, ngspice_id)

FabriceSalvaire avatar Feb 07 '18 21:02 FabriceSalvaire

I am getting the exact same error originally described (CDefError: duplicate declaration of struct ngcomplex), except I am am getting it when I run the external source example https://pyspice.fabrice-salvaire.fr/examples/ngspice-shared/external-source.html as written, without trying to create multiple instances.

aetb avatar Feb 15 '18 21:02 aetb

How do you run this example ?

FabriceSalvaire avatar Feb 16 '18 11:02 FabriceSalvaire

I was running it out of a ipython notebook, but I think I found the issue. It was with the kernel, not the example. Now, however, I'm getting the following errors:

2018-02-15 16:55:18,889 - PySpice.Spice.NgSpice.Shared.NgSpiceShared - Shared.ERROR - Note: can't find init file.

2018-02-15 16:55:18,904 - PySpice.Spice.NgSpice.Shared.NgSpiceShared - Shared.DEBUG - Execute command: set nomoremode

aetb avatar Feb 16 '18 19:02 aetb

only first is an error, you have to check your ngspice installation, on Linux /usr/share/ngspice/scripts/spinit

FabriceSalvaire avatar Feb 16 '18 19:02 FabriceSalvaire

I'm on windows 10, the init file looks good; it's in Program FIles\Spice64\share\ngspice\scripts. Where does the module expect to find it?

aetb avatar Feb 16 '18 20:02 aetb

It is not related to PySpice, but Ngspice. I don't know why your setup is wrong.

FabriceSalvaire avatar Feb 16 '18 21:02 FabriceSalvaire

I have the same problem on my win10 64bit setup. The spinit file is residing in C:\Program Files\Spice64\share\ngspice\scripts and the dll is found (also by pyspice) in C:\Program Files\Spice64\bin_dll. ngspice or pyspice is not able to locate the spinit file. Where does pyspice/ngspice look for it? I tried copying it to the current working directory, which works but then the paths within spinit must be updated to absolute paths.

Setting SPICE_LIB_DIR or SPICE_PATH doesn't seem to alter anything.

akapelrud avatar Oct 18 '18 09:10 akapelrud

I was running it out of a ipython notebook, but I think I found the issue. It was with the kernel, not the example. Now, however, I'm getting the following errors:

2018-02-15 16:55:18,889 - PySpice.Spice.NgSpice.Shared.NgSpiceShared - Shared.ERROR - Note: can't find init file.

2018-02-15 16:55:18,904 - PySpice.Spice.NgSpice.Shared.NgSpiceShared - Shared.DEBUG - Execute command: set nomoremode

What was the issue? how did you resolve it? I'm facing the same problem.

Iteesha27 avatar Sep 28 '19 17:09 Iteesha27

I have the same problem, can't find the init file, on Windows 10 x64. Is there any solution yet?

peter-ch avatar Feb 26 '20 18:02 peter-ch

@peter-ch, read the ngspice manual:

(...) The path may be overridden by setting the environmental variable SPICE_SCRIPTS to a path where spinit is located.

So, on OSX:

export SPICE_SCRIPTS=/usr/local/Cellar/ngspice/31/share/ngspice/scripts/

brainstorm avatar Apr 06 '20 11:04 brainstorm

Changing that environment variable had no effect on the error. I changed it from both Python (os.environ) and Windows GUI, same thing.

2020-04-06 21:52:52,869 - PySpice.Spice.NgSpice.Shared.NgSpiceShared - Shared.INFO - New instance for id 0 2020-04-06 21:52:52,907 - PySpice.Spice.NgSpice.Shared.NgSpiceShared - Shared.ERROR - Note: can't find init file.

peter-ch avatar Apr 06 '20 18:04 peter-ch

So is the problem fixed or no? Any updates? Thanks.

ChrisZonghaoLi avatar Nov 08 '22 02:11 ChrisZonghaoLi