Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValueError: Cannot have more than one active ZOS instance #19

Closed
Omnistic opened this issue Jun 29, 2023 · 12 comments
Closed

ValueError: Cannot have more than one active ZOS instance #19

Omnistic opened this issue Jun 29, 2023 · 12 comments

Comments

@Omnistic
Copy link
Contributor

I'm using OS 2023 R1.03 Premium with Python 3.10.9, Pythonnet 3.0.1

After installing ZOSPy, when I try to use:

import zospy as zp

zos = zp.ZOS()
zos.wakeup()
zos.connect_as_extension()
oss = zos.get_primary_system()

I get a

ValueError: Cannot have more than one active ZOS instance

This happens even after a fresh restart of my computer. My OS is setup with Programming..Interactive Extension (the OS boilerplate interactive extension code works for me). Is there anything I should do to clear any pre-existing connection? Thanks for your help.

@crnh
Copy link
Collaborator

crnh commented Jun 29, 2023

Hi @Omnistic, thanks for notifying us about this problem. This exception is raised from zpcore.py#L289, when creating an instance of the ZOS class. It should therefore occur only if a second instance of the ZOS class is instantiated.

Can you debug this code to confirm that the exception is raised as soon as you run this line?

zos = zp.ZOS()

This problem is quite weird and probably not related to the connection with OpticStudio, as this exception should already be raised before creating the connection. It might be related to other parts of your setup. Which development environment do you use?

@Omnistic
Copy link
Contributor Author

I turned-off my computer to go to lunch, and tried the following when I returned to work

import zospy as zp

zos = zp.ZOS()

This time it worked once. But subsequent call to that snippet would produce the error. Even if I close OpticStudio entirely. I will try to restart my computer again to see if it makes a difference.

@Omnistic
Copy link
Contributor Author

I'm having difficulty understanding what's happening. It seems that when I do restart my computer I can get it to work once, but then get the

ValueError: Cannot have more than one active ZOS instance

Even though with the OS template I can still connect. Could it have to do with how Ansys manage OS licence as oppose to Zemax previously? Its kind of hard to debug cause I need to restart my computer everytime.

@crnh
Copy link
Collaborator

crnh commented Jun 29, 2023

It is actually correct that the second call to that snippet produces the error. Only one instance of the ZOS class can exist at the same time; if you try to create a second instance, it will check if there is already an existing instance and raise that error. The reason for this limit is that the ZOS-API doesn't support multiple connections from the same process. Since a ZOS object represents a connection to the ZOS-API (at least after calling ZOS.wakeup), we decided to allow only a single instance of this class.

You can check if there is already an existing instance of the ZOS class in various ways. e.g. running

zp.ZOS._instances

If this returns an empty set, there are no instances; if it returns a set with a single element, there is already an instance and any subsequent calls to zp.ZOS() will raise an error.

Another way to check for instances:

import gc

[o for o in gc.get_objects() if isinstance(o, zp.ZOS)]

By the way, which development environment are you using? If you are using Spyder, Jupyter or anything else running an ipython kernel, a ZOS instance will live as long as you don't manually delete it and don't stop the kernel. Restarting the kernel or deleting the zos object should be enough to clear it, and rebooting shouldn't be necessary then.

@Omnistic
Copy link
Contributor Author

I'm using JupyterLab 3.3.2 and restarting the Kernel works! Sorry I didn't think about that, with the boilerplate code from OpticStudio this is not necessary. Is there any other way other than restarting the Kernel? I tried

del zos

without success. Thanks for your help!

@jwmbeenakker
Copy link
Contributor

Nice that has been sorted out.
@crnh Would it be an idea to add a frequently asked questions document with common problems and solutions? Could probably help others.

@crnh
Copy link
Collaborator

crnh commented Jun 29, 2023

I tried
del zos
without success. Thanks for your help!

Okay, but this should work as well. It might be that the _instances attribute is not reset when deleting the zos object. I'll have a look into that.

Meanwhile, it may be useful to know that you can safely reuse an existing ZOS instance. If you want to reconnect with OpticStudio (and the previous connection has been closed), you can just call connect_as_extension or create_new_application on the existing zos object.

@andibarg

This comment was marked as off-topic.

@crnh
Copy link
Collaborator

crnh commented Jun 29, 2023

This is a good question, but not related to this issue, so it's better to create a new discussion for this. Thanks!

@crnh
Copy link
Collaborator

crnh commented Jun 30, 2023

Hi @Omnistic, I looked into the problem with deleting the zos object and I'm unable to reproduce it. Can you run this in the REPL (so not in a jupyter notebook):

import zospy as zp
print(zp.ZOS._instances)
zos = zp.ZOS()
print(zp.ZOS._instances)
del zos
print(zp.ZOS._instances)

The first and last print statement should return an empty set, the second a set with a single element.
Deleting objects in Python actually only removes the reference to the object; the object itself will live on happily until the garbage collector removes it. This often happens immediately, but this seems not to be the case in your setup. Cleaning up the _instances attribute of the ZOS class is also triggered by the garbage collector. It is to the best of my knowledge not possible to do this immediately on running del zos; this is a technical limitation within Python.

@Omnistic
Copy link
Contributor Author

Omnistic commented Jun 30, 2023

Hi @crnh,

Using your message I managed to understand my mistake. The problem was that upon calling

del zos

The Interactive Extension remains connected in OpticStudio (the Status window displays: Connected). If, after calling

del zos

I manually Terminate the interactive extension window in OpticStudio and open a new one. Then it seems to be fine. Sorry for the trouble, I guess I expected again a behaviour like the boilerplate code that OpticStudio generates. Do you think there could be a way to avoid having to manually Terminate the interactive extension in OpticStudio? Thanks for your help.

@crnh
Copy link
Collaborator

crnh commented Jun 30, 2023

Ah, that makes sense, thanks for checking this! As far as I know, it is possible to close the extension / standalone OpticStudio instance by calling zos.Application.CloseApplication(). We are considering to add this to the finalizer, so that this will be done automatically when calling del, but we first need to test if this works as expected.

Regarding the OpticStudio boilerplate code: it completely ignores that you can't create a second connection, and if you try to do so, it will happily return a new reference to the existing connection without telling you it's not a new connection. If you treat this connection as a new connection, you may run into problems, and that's why @LucVV decided to implement the ZOS class in this way. We are going to update the error message to explain this more clearly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants