ansys / pymechanical

Pythonic interface to Ansys Mechanical ™
https://mechanical.docs.pyansys.com/
MIT License
36 stars 18 forks source link

Bug located in ...result = mechanical.run_python_script("ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis()") #207

Closed AbelR0 closed 1 year ago

AbelR0 commented 1 year ago

🔍 Before submitting the issue

🐞 Description of the bug

When I try to add a StaticStructural Analysis there is no result returned and the code breaks here: image

With no additional error message

Thanks! Best Regards, Abel

📝 Steps to reproduce

import os from ansys.mechanical.core import launch_mechanical

mechanical = launch_mechanical(batch=False)

Add static structural

result = mechanical.run_python_script("model=ExtAPI.DataModel.Project.Model") result = mechanical.run_python_script("model.AddStaticStructuralAnalysis()")

💻 Which operating system are you using?

Windows

📀 Which ANSYS version are you using?

23.1 with the service pack

🐍 Which Python version are you using?

3.8

📦 Installed packages

ansys-api-mechanical==0.1.0
ansys-api-platform-instancemanagement==1.0.0b3
ansys-mechanical-core==0.7.1
ansys-platform-instancemanagement==1.0.3
ansys-pythonnet==3.1.0rc1
appdirs==1.4.4
cffi==1.15.1
clr-loader==0.2.5
colorama==0.4.6
googleapis-common-protos==1.59.0
grpcio==1.53.0
importlib-metadata==6.3.0
protobuf==3.20.3
protoc-gen-swagger==0.1.0
pycparser==2.21
tqdm==4.65.0
zipp==3.15.0
pmaroneh commented 1 year ago

Same happens on my side: image

But if "AddStaticStructuralAnalysis()" is saved into a separate Python script, and send through mechanical.run_python_script_from_file('mech_script.py') then it works.

samigithub2022 commented 1 year ago

run_python_script or run_python_script_from_file is a generic API and it can only return a string value, and this is returned based on the last statement in your script. This is by design. It is not a defect.

Btw, Mechanical could be running on a different process in your machine or on a different machine (or in a container), you may want to try...except your code.

In your scenario, you are trying to return Ansys.ACT.Automation.Mechanical.Analysis object which is not supported by the API. You can see this information from the error details of grpc.RpcError.

You can use any of the following techniques:

  1. You can ignore this error if it is not going to return a string.

import grpc try: result = mechanical.run_python_script("ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis()") except grpc.RpcError as error: print(error.details())

  1. additional line to your script so it returns a string. result = mechanical.run_python_script("ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis()\n'success'") if result == 'success': pass

  2. send a function that does the above script = """ def add_analysis(): ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis() .. more statements return "added analysis"

add_analysis() """ result = mechanical.run_python_script(script)

  1. If you find constructing a string on the fly is not friendly, you can have the same information in a file. test.py: def add_analysis(): ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis() .. additional statements return "added analysis"

add_analysis()

main.py result = mechanical.run_python_script("/some_path/test.py")

Even though you can send/run a script line by line, it may not be efficient since you are talking to a remote process and may want to limit the number of calls.

samigithub2022 commented 1 year ago

reopening to see if we can improve anything here for the user.

pmaroneh commented 1 year ago

Hi @samigithub2022 , thanks for the clarification. If I understand correctly, this means that any Mechanical automation script has to be sent to the remote instance at once. Remote version will not offer the possibility to do something like: (note - below is pseudo code, not real code, just to illustrate what I mean):

result1 = mechanical.run_python_script("ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis()")
result2 = mechanical.run_python_script("result1.AddFixedSupport()")

This means that there is not way to build a model / script by sending commands line per line to check if they work with remote version. This will be fine for users that want to reuse scripts that they have already built in Mechanical, but it will not be a good solution for users who want to create their scripts directly from PyMechanical.

AbelR0 commented 1 year ago

Hi @samigithub2022 , @pmaroneh

As Pernelle said, the problem I see then is that there is no way to launch a "line by line" script with the run_python_script, since even though I launch it without getting a response, my code still breaks on the second line:

mechanical.run_python_script("model=ExtAPI.DataModel.Project.Model") mechanical.run_python_script("ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis()")

That would mean, as you pointed out, that for each call that is not able to return an answer, we might need to wrap it individually on a try-except? Something like this?

try: mechanical.run_python_script("model=ExtAPI.DataModel.Project.Model") mechanical.run_python_script("ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis()") except: pass

One workaround I was using was to launch "those few lines of code" in a script

mechanical.run_python_script_from_file('addStaticStructural.py')

But it's curious that I still need to add an additional ine in addStaticStructural.py or I still get the error.

model=ExtAPI.DataModel.Project.Model model.AddStaticStructuralAnalysis() geometryImportGroup = model.GeometryImportGroup

Thanks for your comments!

pmaroneh commented 1 year ago

Had a meeting with @samigithub2022 to clarify. Commands can be sent line per line as below: image but the returned string "result" will be empty for the first line. Preferable way of sending the commands: image this method returns only the last result as a string: image The reason result1 = mechanical.run_python_script("ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis()")fails is that ExtAPI.DataModel.Project.Model.AddStaticStructuralAnalysis() returns an analysis object, not a string. Possible improvement is to have some sort of string conversion to send back to the client. Suggestion: image

@AbelR0 FYI

samigithub2022 commented 1 year ago

This issue has been fixed in the PR #224.

Return empty string when the run_python_script* return value cannot be converted to a string.

It is available in the ansys-mechanical-core 0.8.0 package.