Multiple Python API issues and strange behaviors

363 views
Skip to first unread message

Stratos2 - no videos here

unread,
Jan 11, 2025, 12:51:40 AMJan 11
to OpenVSP
Hello! I've only started using the OpenVSP API today, but over the last 9 or so hours I've figured out a good few things. However, I am still running into trouble in several places:

1) If I switch my attached script from VORTEX_LATTICE to PANEL, everything seems to go just fine, however when I load the vsp3 file and look at the analysis, it fails to load with

Error: VSPAERO History file D:/.Downloads/OpenVSP-3.41.2-win64-Python3.11/OpenVSP-3.41.2-win64/python/openvsp/first-developements.py_DegenGeom.history not found
Error: VSPAERO Load file D:/.Downloads/OpenVSP-3.41.2-win64-Python3.11/OpenVSP-3.41.2-win64/python/openvsp/first-developements.py_DegenGeom.lod not found

VORTEX_LATTICE seems to work just fine, and when running the PANEL solver doesn't throw any errors, but afterwards I can't inspect the results as some key files apparently end up being missing. (if you test this be sure to delete the vlm files before you run the panel method, otherwise the aero analysis still might work, but show the old vlm results)

2) I have been looking around the API docs, but I have not been able to figure out how to split a wing or generate a wing with multiple XSections. I'd like to model an elliptical wing, and I'm not sure how to do that.

3) I've been trying to load the GUI to allow someone to ideally be presented with results automatically, however that just crashes out with a driver error, as I reported here: https://github.com/OpenVSP/OpenVSP/issues/316

4) does anyone happen to have experience integrating this into an existing project? My student group has already written an optimizer, though using pip for packages and in python 3.13. Is there any (semi-)streamlined way to integrate both of them together, maybe convince pycharm to build the correct conda env without having to run every command manually like I had to do today?

I'd also massively appreciate feedback on the general quality of my code and API usage. I'm still trying to figure out what exactly the "proper" approach to do a thing with the API is.

Thanks in Advance for having a look!
-HB
first-developements.py

Rob McDonald

unread,
Jan 11, 2025, 2:19:15 PMJan 11
to OpenVSP
When you open the OpenVSP GUI to load last results to look at things, you need to change the GUI to match VLM / Panel mode from the run you want to load.

VSP names the files sent to VSPAERO with a slightly different naming convention depending on VLM / Panel.  Consequently, when the GUI looks for the files, it won't find them if you don't select the right option.  Also, you must open a file with the same name (as the file when the analysis was performed).

Inserting XSecs is done through the XSecSurf portion of the API.  There is an example of its use on a Wing here.

I believe that Splitting a Wing was accidentally omitted from the API.  It has been mentioned on the list before, but clearly I forgot to add it.  Feel free to add a GitHub issue -- that is the best way to keep things like that from being forgotten.

I know essentially nothing about Python Packaging.  I believe getting an OpenVSP package accepted 'upstream' by big package management projects would be a substantial challenge.  The OpenVSP Python Wrapper is really all the C++ code compiled into a shared library (*.dll on Windows, *.so on Unix).  That shared library needs to 'match' the Python binary on your platform.  I.e. 32/64 bit, x86 vs Arm vs. Both, Linux/Windows/MacOS/other, appropriate Python version 3.9, 3.10, 3.11, etc.  Some of these projects have requirements that you build packages for all platforms they support -- PlayStation 5, Raspberry Pi, Android, iOS, etc.  Someone would need to work on automating the build process -- from when I push an OpenVSP release to building on a huge combinatorial matrix of platforms/versions and uploading to the packaging servers.

I can try to help if the community wants to take this on, but it is not something I am able to take on myself.

Rob

Rob McDonald

unread,
Jan 11, 2025, 2:52:33 PMJan 11
to OpenVSP
Overall, your script looks pretty reasonable.

The VSP API is different from a lot of Python API's.  This is mainly because all of the data is kept on the OpenVSP side of things.

With most Python API's (say numpy), the data is kept by the user in Python.  You have a matrix M.  You want to calculate its inverse -- so you pass M to numpy and it passes back the inverse, which you store in Minv.

Minv = np.linalg.inv(M)

Although OpenVSP is object oriented under the hood, the API is entirely function based.  Almost all functions take an ID argument -- this is a unique identifier of the thing you want to operate on -- usually a Geom or Parm, but we use them for lots of other things too.

Some time ago, there was some effort to create a more Pythonic wrapper to the OpenVSP API.  It was a set of Python classes that remembered each entity's ID and made it so you could do things like Sweep.SetVal(X) instead of SetParmVal(SweepID, X).

There is both C++ and Python based documentation for the API.  The two should pretty much be a 1:1 match -- let us know if they are not.  I generally prefer the C++ documentation because it has a better Table of Contents that makes it easier to navigate.  I'm sure that Pydoc / Sphynx has an option to build a TOC, but we haven't figured that out.

In your API usage, you do something that many (if not most) API users do -- that I did not expect when we started putting things together.

You're starting from an empty model and issuing all the commands to build your model from scratch every time.

Instead, I expected users to use the GUI to build a baseline version of their model.  This makes it easier to use attachment, parameter links, and other advanced features to build up a model.  You can see that you are getting the right result and interact with the analyses, etc.

Then, I would expect their script to load the baseline file, perturb a small number of design variables (leaving most variables alone) and then conduct some analysis.

I still think creating a baseline file via the GUI is the way to go, but lots of people build from scratch every time.

Rob


On Friday, January 10, 2025 at 9:51:40 PM UTC-8 henning....@gmail.com wrote:

Stratos2 - no videos here

unread,
Jan 11, 2025, 2:57:16 PMJan 11
to OpenVSP
Thanks for your input Rob!

I did finally figure out on my own that the UI must be set to Panel to open previous panel method analysis. 
The XSec insert commands do look like what I was looking for, I'll investigate how I can best use them.
I'll see about adding a github issue for splitting a wing.
Good to know about packaging. Having it be an official package would certainly be very convenient, but require a fully automated build process, yes. For now I just need to hack together a solution that pycharm can ideally install itself when loading the project from git. Maybe I can get this working, will report back.

I do have a couple more questions / issues I've come across in the meantime:
- I have played around with the stall models, but the "Carlson Pressure Correlation" appears to be non-functional. With or without I'm able to get a C_L of almost 7 out of a NACA 3612 at 60° AoA, which really makes no sense at all. The C_L_max limiter does appear to work, but acquiring a value to insert is proving difficult. Our RFP mandates we use n_crit of 7, which is not readily available on airfoiltools.com to get a C_L_max from xfoil without having to build and write a whole python harness for that program too. Am I doing something wrong here that is preventing the Carlson Pressure Correlation from working or have I fundamentally misunderstood something?
- is it somehow possible to set the camera to a precise location as with the "adjust view" window in the GUI? I haven't found a function in the API that allows an input that isn't a fixed preset view.
- Does the API have any support for the VSPAERO Viewer? Ideally I'd like to show the user an aero view with pressures and wakes while the solver iterates through many different combinations of airfoils, etc. I haven't found any way to control the viewer beyond launching it manually on the command line for every result, with no GUI controls after.
- I have set vsp.SetDriverGroup(wing_id, 1, vsp.SPAN_WSECT_DRIVER, vsp.ROOTC_WSECT_DRIVER, vsp.TAPER_WSECT_DRIVER), but setting the Taper parameter appears to do nothing of value. I still can only set Root Chord, Span and Tip Chord and am unable to instead set Taper.
- OpenVSP appears to possess no ability to automatically trim an aircraft. Do you know of a good method to trim out an aircraft with ideally as few solver runs as possible? I specifically need to tune wing incidence angle and alpha to find a steady state with a target C_L and a C_M of zero. Getting down computation time is really important as we'll have to evaluate tens of thousands of aircraft configurations.

Thanks again for your input!
- HB

Stratos2 - no videos here

unread,
Jan 11, 2025, 3:22:15 PMJan 11
to OpenVSP
I think the reason most people prefer to build a model from scratch in code is that it feels more predictable. Everything is in one place in a python file and one doesn't have to also commit a vsp3 file to the git repository that might not play nice with git or might accidentally be touched / contain unforeseen changes the user didn't expect. Starting from a blank slate feels like the most stable way to me too.
I did also think about building a more object oriented wrapper myself and will likely end up at least doing part of that to allow my team to work with the API in a bit less error prone of a way and use Python Enums so one doesn't have to look at the docs to trace which part of the system a constant belongs to. What might make this a little bit more difficult (I think) is that there is no process to instantiate a vsp object, it is instead created as what I'd know as a static class in c# when importing. I wouldn't know how to create a second instance of the vsp object, or be sure which one I'm handling. And as most of the API works on a global state that is not a python object, but exists in the background, I'm concerned about e.g. two simultaneous uses while threading actually writing into the same global state.

The below turned out to be a bit more of a rant than I intended. What OpenVSP provides is still an amazing tool, and having an API at all has been a godsend compared to AVL or XFLR5. I do hope the below at least provides some pointers on where a new user (me) will stumble and get stuck when trying to use the API for the first time.

My biggest issue with the Docs have not been the docs of the functions, but the lack of good and straightforward usage examples and best practices as well as awareness of the inner workings and pitfalls. It took me over two hours to finally find vsp.SetVSPAERORefWingID(wing_id) by sheer chance while CTRL+F searching through the docs. No code example I've been able to find has just worked when I ported it over, most of the time with really strange issues and no error thrown. The biggest thing haunting me by far is having missed an Update() in some key place, and suddenly the geometry solver produces complete mess of an output with no errors. The exported VSP file even looked perfectly fine when loaded in the GUI, but the solver just broke. This took hours to track down, and wasn't the only time a missing Update() haunted me.

With all functions being global to the vsp object there's also no easy way to narrow down the search to the area I'm looking for, e.g. all functions related to the VSPAERO solver. Even just finding out that VSPAEROSweep is the method I need to use to run the solver, that I need to run the compGeom method before that and that I need to tell it about panel vs vortex lattice took hours and hours of searching code snippets buried in the google group and piecing them together with lots of trial and error.

Rob McDonald

unread,
Jan 11, 2025, 3:26:37 PMJan 11
to OpenVSP
On Saturday, January 11, 2025 at 11:57:16 AM UTC-8 henning....@gmail.com wrote:
Thanks for your input Rob!

I did finally figure out on my own that the UI must be set to Panel to open previous panel method analysis. 
The XSec insert commands do look like what I was looking for, I'll investigate how I can best use them.
I'll see about adding a github issue for splitting a wing.
Good to know about packaging. Having it be an official package would certainly be very convenient, but require a fully automated build process, yes. For now I just need to hack together a solution that pycharm can ideally install itself when loading the project from git. Maybe I can get this working, will report back.

I don't know if this helps, but if you are building OpenVSP and the API from source (for example, to match to a Python version that I don't release), the CMake build system has a build target to create a virtual environment with the OpenVSP packages all loaded in it.  Build the 'VENV' target and it will create it.  Anything you run with the Python located in the VENV will automatically have access to the current / appropriate build of the API.

 
I do have a couple more questions / issues I've come across in the meantime:
- I have played around with the stall models, but the "Carlson Pressure Correlation" appears to be non-functional. With or without I'm able to get a C_L of almost 7 out of a NACA 3612 at 60° AoA, which really makes no sense at all. The C_L_max limiter does appear to work, but acquiring a value to insert is proving difficult. Our RFP mandates we use n_crit of 7, which is not readily available on airfoiltools.com to get a C_L_max from xfoil without having to build and write a whole python harness for that program too. Am I doing something wrong here that is preventing the Carlson Pressure Correlation from working or have I fundamentally misunderstood something?

The Carlson Pressure Correlation method is sensitive to the freestream Mach number (and Reynolds number).  If you leave it at M 0.01, it will get wacky results.  Even changing it to M=0.2 will make things a lot more reasonable.

- is it somehow possible to set the camera to a precise location as with the "adjust view" window in the GUI? I haven't found a function in the API that allows an input that isn't a fixed preset view.

It should be possible using commands like this....

string veh = FindContainer( "Vehicle", 0 ); // Find Vehicle container

string panx = FindParm( veh, "PanX", "AdjustView" ); // Find view Parms in Vehicle
string pany = FindParm( veh, "PanY", "AdjustView" );
string zoom = FindParm( veh, "Zoom", "AdjustView" );
string rotx = FindParm( veh, "RotationX", "AdjustView" );
string roty = FindParm( veh, "RotationY", "AdjustView" );
string rotz = FindParm( veh, "RotationZ", "AdjustView" );

But they don't seem to be working for me right now....  Another thing to dig into...
 
- Does the API have any support for the VSPAERO Viewer? Ideally I'd like to show the user an aero view with pressures and wakes while the solver iterates through many different combinations of airfoils, etc. I haven't found any way to control the viewer beyond launching it manually on the command line for every result, with no GUI controls after.

It does not.
 
- I have set vsp.SetDriverGroup(wing_id, 1, vsp.SPAN_WSECT_DRIVER, vsp.ROOTC_WSECT_DRIVER, vsp.TAPER_WSECT_DRIVER), but setting the Taper parameter appears to do nothing of value. I still can only set Root Chord, Span and Tip Chord and am unable to instead set Taper.

You probably need to call Update() (or at least UpdateGeom(GeomID) ) after changing the driver group, but before adjusting Taper.
 
- OpenVSP appears to possess no ability to automatically trim an aircraft. Do you know of a good method to trim out an aircraft with ideally as few solver runs as possible? I specifically need to tune wing incidence angle and alpha to find a steady state with a target C_L and a C_M of zero. Getting down computation time is really important as we'll have to evaluate tens of thousands of aircraft configurations.

Not at present.

The steady -stab mode will perturb alpha,beta,Mach,U,roll,pitch,yaw and all control surface groups.  So, I believe it will run 8+Ncsg cases (a baseline), finite difference them, and estimate the control derivatives.  If you are doing 6DOF trim, I suggest you use it, build a linear trim problem, and solve -- you can spot-check the solution to verify.

The -pitch mode will just perturb alpha and will calculate the aerodynamic center / static margin.  However, it does not perturb any control surfaces.

If you're just doing pitch stability, I would probably run three cases -- baseline, perturbed alpha, and perturbed elevator.  I would do my own finite differences, build a linear trim problem, and solve.


If you want to get clever, you can separate your design variables -- planform vs. camber/twist.  The pitch derivatives should only depend on planform, while the intercept terms CL0 and CM0 will depend on planform and twist/camber.  This will let you save a few VSPAERO evaluations if you can group your design variable changes appropriately.


I would encourage you to run a bunch of tests looking at the parallelization speedup of VSPAERO depending on the number of processors and your problem size.  You might also compare with naive parallelization (just running two cases at once).  If you are running a lot of geometries (and they are independent in your process), then you may just run them brutally in parallel.

All that said, until very recently, Intel processors used Hyperthreading -- where each core had two pipelines.  A 4 processor CPU would show up as 8processor -- but you would often see a slowdown on some workflows if you used them in hyperthreading mode.


A major new release of VSPAERO will come out soon (in the next 4-8 weeks hopefully).  This version includes a total rewrite of the adjoint capability and will mark the first time that the adjoint will be easily available from the OpenVSP GUI.  This will include adjoint calculation of the stability derivatives -- very efficiently.

Later in the year, we hope to incorporate a trim solver and other improvements that leverage the adjoint capability.

Rob

Rob McDonald

unread,
Jan 11, 2025, 4:00:47 PMJan 11
to OpenVSP
On Saturday, January 11, 2025 at 12:22:15 PM UTC-8 henning....@gmail.com wrote:
I think the reason most people prefer to build a model from scratch in code is that it feels more predictable. Everything is in one place in a python file and one doesn't have to also commit a vsp3 file to the git repository that might not play nice with git or might accidentally be touched / contain unforeseen changes the user didn't expect. Starting from a blank slate feels like the most stable way to me too.

I also think a primary reason is that many people are starting from a framework that already has a geometry representation.  Even if it isn't a 3D model, their code has concepts like the number of wings, their area, aspect ratio, and sweep.  From their framework, in their world, their geometry representation is the starting point -- since that can change arbitrarily, it makes sense to them to just generate an equivalent VSP representation on the fly.  That may well be the right answer -- I'm just saying that I didn't expect it, and it isn't the way I work.

In fact, OpenVSP's geometry representation is much more detailed, rich, and flexible than most representations in some aircraft design framework.  Consequently, although you drive VSP through the 20 or so variables in your framework, you leave 100's of OpenVSP variables set to their defaults.  This may be totally OK.

To me, the bigger thing is the ability to set up more advanced things -- component hierarchies, links, advanced links, subsurfaces, Sets, presets, etc.  While many / most of these are available from the API, they're much easier to work with through the GUI.
 
I did also think about building a more object oriented wrapper myself and will likely end up at least doing part of that to allow my team to work with the API in a bit less error prone of a way and use Python Enums so one doesn't have to look at the docs to trace which part of the system a constant belongs to. What might make this a little bit more difficult (I think) is that there is no process to instantiate a vsp object, it is instead created as what I'd know as a static class in c# when importing. I wouldn't know how to create a second instance of the vsp object, or be sure which one I'm handling. And as most of the API works on a global state that is not a python object, but exists in the background, I'm concerned about e.g. two simultaneous uses while threading actually writing into the same global state.

We have a solution for this problem in the works.  It is a further extension of the API Facade that we're calling the MultiFacade.

When Python loads a binary module as an API, it shares that single binary across everything in that Python process.  Since most Python API's keep all their data on the Python side, this doesn't matter.  Numpy can invert a matrix M in context A and a matrix Q in context B and everything works fine.

Since OpenVSP keeps all the data on the OpenVSP side, this means that you have a common global instance across all API callers, no matter the context...

As it turns out, computer operating systems only deliver GUI events to the primary thread of a given process.  This means that any given process can only have one GUI event loop running at any time.  We had OpenVSP API users who wanted the OpenVSP GUI to be open while their Python framework with its own GUI was also running and interactive.  This would require two event loops, each receiving GUI events, running in the same process.

This is why we created the Facade.  It spawns a second Python process for OpenVSP and then communicates via sockets.  Your primary process can have its event loop, and our secondary process can also have an event loop.

The MultiFacade extension to this allows us to load a separate Python process for each copy of OpenVSP that you want to have access to in memory.  If you want to have three OpenVSP's, we will spawn three Python processes and allow you to talk to them separately.

The MultiFacade should hopefully be released pretty soon.
 

The below turned out to be a bit more of a rant than I intended. What OpenVSP provides is still an amazing tool, and having an API at all has been a godsend compared to AVL or XFLR5. I do hope the below at least provides some pointers on where a new user (me) will stumble and get stuck when trying to use the API for the first time.

My biggest issue with the Docs have not been the docs of the functions, but the lack of good and straightforward usage examples and best practices as well as awareness of the inner workings and pitfalls. It took me over two hours to finally find vsp.SetVSPAERORefWingID(wing_id) by sheer chance while CTRL+F searching through the docs. No code example I've been able to find has just worked when I ported it over, most of the time with really strange issues and no error thrown. The biggest thing haunting me by far is having missed an Update() in some key place, and suddenly the geometry solver produces complete mess of an output with no errors. The exported VSP file even looked perfectly fine when loaded in the GUI, but the solver just broke. This took hours to track down, and wasn't the only time a missing Update() haunted me.

With all functions being global to the vsp object there's also no easy way to narrow down the search to the area I'm looking for, e.g. all functions related to the VSPAERO solver. Even just finding out that VSPAEROSweep is the method I need to use to run the solver, that I need to run the compGeom method before that and that I need to tell it about panel vs vortex lattice took hours and hours of searching code snippets buried in the google group and piecing them together with lots of trial and error.

I'm sorry you've had these struggles -- but I'm glad to hear that OpenVSP is useful to you despite them.
 
This year, we're going to have the OpenVSP Workshop online again -- I encourage you to check out the past Workshop videos and the new Workshop when we do it (late summer / fall).  The 2026 Workshop will be in-person again, if you can travel to join us, I think you'll find it is a very valuable experience.


I understand that not knowing when to Update() from the API is a real hassle.

When interacting with the GUI, we can Update() after everything the user does.  Users are very limited in that they only do one thing at a time.  Update one parameter, see the result.

However, from the API, a user might change 20 or 30 parameters before needing to do anything.  If we automatically called Update() and re-lofted the Geometry after each time, performance would be disastrous.  Our solution to this is to defer updates.  We actually do this in the GUI, but in less visible ways.  For example, when you load a *.vsp3 file, it may set 1000's or 10's of thousands of parameters.  We wait until all that is done and only call Update() at the end.  If we didn't, loading a *.vsp3 file would take minutes or hours...

It is actually much more complex than this under the hood.  Different parameters are triaged into different categories -- eg. those that change the position / orientation of a component vs. those that change the shape of a component.  When a single Parm is changed, we may be able to perform a limited Update() -- if you just translate a component, then we don't re-loft the Bezier surfaces, we just update the transformation matrices.  These optimizations have greatly sped up interactive OpenVSP, but they've been very difficult to get 100% correct and consistent since I started making these changes about five years ago...  Fortunately, the fractional Update() should be totally invisible to all users.

When you change the Wing driver group, change the active XForm Parms from Rel to Abs, Insert XSecs, or change XSecCurve type (and other similar things) -- in many ways, you're changing the structure of the model.  What Parms exist and which Parms are enabled / disabled.  These actions often require an Update() before you can access the Parms whose state was changed.  Driver groups for example.  The driver group controls what Parms are Activate()'ed vs. Deactivate()'ed.  However, that doesn't get applied until Update().  If you SetParmVal() to a Deactivate()'ed Parm, the value is thrown away and ignored.

Rob

Stratos2 - no videos here

unread,
Jan 11, 2025, 4:27:12 PMJan 11
to OpenVSP
> If you want to get clever, you can separate your design variables -- planform vs. camber/twist.  The pitch derivatives should only depend on planform, while the intercept terms CL0 and CM0 will depend on planform and twist/camber.  This will let you save a few VSPAERO evaluations if you can group your design variable changes appropriately. <


We'll investigate this, as the relationship is hopefully linear enough, we may be able to get away with four solver runs, three untrimmed and one finally trimmed. Still not optimal time wise, but there isn't much more that can be done here. We may be able to set wake count really low though as our main wing is vertically offset to where they both receive effectively free-stream air at any reasonable angle of attack.

>A major new release of VSPAERO will come out soon (in the next 4-8 weeks hopefully).  This version includes a total rewrite of the adjoint capability and will mark the first time that the adjoint will be easily available from the OpenVSP GUI.  This will include adjoint calculation of the stability derivatives -- very efficiently.

Later in the year, we hope to incorporate a trim solver and other improvements that leverage the adjoint capability.<


That sounds really promising, I'll investigate that when the time comes. Unfortunately for now I need to have our solver running by Thursday, so this won't be able to benefit our current project

> I'm sorry you've had these struggles -- but I'm glad to hear that OpenVSP is useful to you despite them.
 
This year, we're going to have the OpenVSP Workshop online again -- I encourage you to check out the past Workshop videos and the new Workshop when we do it (late summer / fall).  The 2026 Workshop will be in-person again, if you can travel to join us, I think you'll find it is a very valuable experience.<


Unfortunately in person will be tough, from Germany to the US is no easy feat. I would encourage you to try and record talks at that Workshop too, so at least those will be preserved for as long as possible. I've already checked out some of the previous year's slides and they have proven useful, though their information on how exactly to use the API has been sparse in what I looked at.

>I understand that not knowing when to Update() from the API is a real hassle.

When interacting with the GUI, we can Update() after everything the user does.  Users are very limited in that they only do one thing at a time.  Update one parameter, see the result.

However, from the API, a user might change 20 or 30 parameters before needing to do anything.  If we automatically called Update() and re-lofted the Geometry after each time, performance would be disastrous.  Our solution to this is to defer updates.  We actually do this in the GUI, but in less visible ways.  For example, when you load a *.vsp3 file, it may set 1000's or 10's of thousands of parameters.  We wait until all that is done and only call Update() at the end.  If we didn't, loading a *.vsp3 file would take minutes or hours...

It is actually much more complex than this under the hood.  Different parameters are triaged into different categories -- eg. those that change the position / orientation of a component vs. those that change the shape of a component.  When a single Parm is changed, we may be able to perform a limited Update() -- if you just translate a component, then we don't re-loft the Bezier surfaces, we just update the transformation matrices.  These optimizations have greatly sped up interactive OpenVSP, but they've been very difficult to get 100% correct and consistent since I started making these changes about five years ago...  Fortunately, the fractional Update() should be totally invisible to all users.<


Fractional update sounds like a solution to some of these annoyances. Though in my opinion manual updates are an okay solution, if then when and why is documented. At the moment functions are documented, but high level usage is not. That is what I am advocating for, a high level guide of the API, where to find what things, and what to watch out for. It would have saved me hours to have a short page telling me how I load, edit data, what the basic concepts of the API usage are and where I have to watch out for strange behavior. That along with a simple code example that does all usual steps a user might want to do from creation to reading result data would massively reduce the learning curve for the API. 

At least the docs do help a good bit on their own too. Though for the first few hours I was working without those too as I did not find the link from https://openvsp.org/pyapi_docs/latest/ to https://openvsp.org/pyapi_docs/latest/openvsp.html which is hidden in the sidebar under a table of contents so I just dismissed the bottom one as part of that.


As a bit of a side note, is there any chance it would be possible to add a perspective view mode to OpenVSP? I actually did take a few hours to watch through most of the ground school a few years back and learned OpenVSP, but when I went to create my own design I was constantly getting so confused by the isometric rendering that I entirely stopped using it despite wanting to design some RC aircraft in it. For my brain at least, isometric renders are extremely hard to parse as there is no distance information included. It would make it a lot easier for me to use OpenVSP if there was a perspective render mode, it is way easier for my brain to parse.

Stratos2 - no videos here

unread,
Jan 11, 2025, 4:44:41 PMJan 11
to OpenVSP
I'm also a little bit confused by how to actually extract result data from my aero solver. The most intuitive initially would be to parse the results CSV file manually from python. However through reading a good bit here in the group I think something called "ResultMgr" exists which is supposed to be a more stable way to access the data, though there is no mention of it or how to use it in the docs. I assume that is related to functions like vsp.GetDoubleResults(). I am trying to use that function on some VSPAEROSweep data at the moment, but PrintResults(sweep_results) outputs a huge amount of sub-tables of different things that I am not sure how I am supposed to access with GetDoubleResults() as vsp.GetAllDataNames(sweep_results) tells me there is only ('Analysis_Duration_Sec', 'ResultsVec'), and I don't yet follow how I pivot into ResultsVec. Or if this is even the intended method of accessing VSPAERO results.
I also noticed res = vsp.parasitedrag_sweep(speeds=np.linspace(10, 250, 10), alts_ft=[0, 10000, 20000, 50000], sref=sref, length_unit=vsp.LEN_FT, speed_unit=vsp.V_UNIT_MPH) (found in test_degen_geometry.py) which seems to be much more seamlessly integrated into python compared to what I am doing in the aero work. Is there some way to access aerodynamic data in such a "nice" way, or is this new here, or am I totally misunderstanding something?

-HB

Rob McDonald

unread,
Jan 12, 2025, 1:43:49 AMJan 12
to OpenVSP
On Saturday, January 11, 2025 at 1:27:12 PM UTC-8 henning....@gmail.com wrote:
> If you want to get clever, you can separate your design variables -- planform vs. camber/twist.  The pitch derivatives should only depend on planform, while the intercept terms CL0 and CM0 will depend on planform and twist/camber.  This will let you save a few VSPAERO evaluations if you can group your design variable changes appropriately. <


We'll investigate this, as the relationship is hopefully linear enough, we may be able to get away with four solver runs, three untrimmed and one finally trimmed. Still not optimal time wise, but there isn't much more that can be done here. We may be able to set wake count really low though as our main wing is vertically offset to where they both receive effectively free-stream air at any reasonable angle of attack.

It is certainly worth checking a fixed wake solution -- that will speed things up a good bit as well.

VSPAERO as shipped is not really set up for super-detailed gradient based optimization studies.  Some of VSPAERO's tolerances are set relatively coarsely -- they're fine if you're interested in engineering estimates of force and moment coefficients etc.  However, if you're using a gradient based optimizer, it will likely want to take very small steps when calculating derivatives.  The difference in solution between those cases will likely be smaller than the coarse default tolerances used by VSPAERO.  This will cause the derivative information to be unreliable and will send a gradient based optimizer in the wrong direction.

The next VSPAERO update will come with more knobs to tighten the tolerances to help this situation.  The adjoint will also allow exact derivatives of certain things (but OpenVSP does not yet provide analytical derivatives).

If you're doing more of a design space survey -- say a DOE to fit a metamodel of some sort -- you'll probably be fine.


>A major new release of VSPAERO will come out soon (in the next 4-8 weeks hopefully).  This version includes a total rewrite of the adjoint capability and will mark the first time that the adjoint will be easily available from the OpenVSP GUI.  This will include adjoint calculation of the stability derivatives -- very efficiently.

Later in the year, we hope to incorporate a trim solver and other improvements that leverage the adjoint capability.<


That sounds really promising, I'll investigate that when the time comes. Unfortunately for now I need to have our solver running by Thursday, so this won't be able to benefit our current project

Understood. 


 
> I'm sorry you've had these struggles -- but I'm glad to hear that OpenVSP is useful to you despite them.
 
This year, we're going to have the OpenVSP Workshop online again -- I encourage you to check out the past Workshop videos and the new Workshop when we do it (late summer / fall).  The 2026 Workshop will be in-person again, if you can travel to join us, I think you'll find it is a very valuable experience.<


Unfortunately in person will be tough, from Germany to the US is no easy feat. I would encourage you to try and record talks at that Workshop too, so at least those will be preserved for as long as possible. I've already checked out some of the previous year's slides and they have proven useful, though their information on how exactly to use the API has been sparse in what I looked at.

Keep it in mind, we usually have international participation at the Workshop

Unless the Workshop venue is equipped to take care of recording and streaming in a way that does not interfere with the workshop, I'm not willing to take away from the in-person experience for recording.  I understand that not everyone can travel -- and I appreciate the value of archiving the presentations to video so they can be accessed.  Our compromise is to hold a virtual workshop every few years.  Many of the Workshop presentations are repeated each year -- and the fundamentals don't change that quickly.  

 
>I understand that not knowing when to Update() from the API is a real hassle.

When interacting with the GUI, we can Update() after everything the user does.  Users are very limited in that they only do one thing at a time.  Update one parameter, see the result.

However, from the API, a user might change 20 or 30 parameters before needing to do anything.  If we automatically called Update() and re-lofted the Geometry after each time, performance would be disastrous.  Our solution to this is to defer updates.  We actually do this in the GUI, but in less visible ways.  For example, when you load a *.vsp3 file, it may set 1000's or 10's of thousands of parameters.  We wait until all that is done and only call Update() at the end.  If we didn't, loading a *.vsp3 file would take minutes or hours...

It is actually much more complex than this under the hood.  Different parameters are triaged into different categories -- eg. those that change the position / orientation of a component vs. those that change the shape of a component.  When a single Parm is changed, we may be able to perform a limited Update() -- if you just translate a component, then we don't re-loft the Bezier surfaces, we just update the transformation matrices.  These optimizations have greatly sped up interactive OpenVSP, but they've been very difficult to get 100% correct and consistent since I started making these changes about five years ago...  Fortunately, the fractional Update() should be totally invisible to all users.<


Fractional update sounds like a solution to some of these annoyances. Though in my opinion manual updates are an okay solution, if then when and why is documented. At the moment functions are documented, but high level usage is not. That is what I am advocating for, a high level guide of the API, where to find what things, and what to watch out for. It would have saved me hours to have a short page telling me how I load, edit data, what the basic concepts of the API usage are and where I have to watch out for strange behavior. That along with a simple code example that does all usual steps a user might want to do from creation to reading result data would massively reduce the learning curve for the API. 

Have you looked at the example scripts that ship with OpenVSP?  I know they are in *.vspscript instead of Python, but the API calls should match 1:1.

OpenVSP development is done by a very small team.  The largest number of concurrent contributors we've ever had could be counted on one hand.  Development work is generally sponsored, but that means that development priorities are set by the sponsor.  So far, sponsors are much more interested in new features than they are in documentation.

Most of the effort in documentation has been focused on helping beginners.  Brandon Litherland's OpenVSP Ground School is the primary result of that.

API users are generally assumed to not be beginners -- but you make a good point that everyone is a beginner at everything at some point.

I appreciate the different kinds of documentation -- our API docs have focused on providing a reference manual so far.  We have not attempted a bigger picture form of documentation.

I must admit, I really struggle with documenting OpenVSP.  It is hard for me to put myself in the shoes of a beginner and imagine what would be most helpful to them.  Some people have advocated for exhaustive documentation of every GUI, window, button, and slider.  We currently have more than 70 GUI's and thousands of parameters.  I can't imagine that telling people that "The Wing Geom's Sweep parameter controls the wing sweep." is useful documentation.  I also struggle with discoverability -- even if everything was documented somewhere, would people actually be able to find and use it when they need it?

 
At least the docs do help a good bit on their own too. Though for the first few hours I was working without those too as I did not find the link from https://openvsp.org/pyapi_docs/latest/ to https://openvsp.org/pyapi_docs/latest/openvsp.html which is hidden in the sidebar under a table of contents so I just dismissed the bottom one as part of that.

Yes, this kind of difference is exactly why I prefer the C++ documentation instead -- it is simply better formatted and organized.
 
As a bit of a side note, is there any chance it would be possible to add a perspective view mode to OpenVSP? I actually did take a few hours to watch through most of the ground school a few years back and learned OpenVSP, but when I went to create my own design I was constantly getting so confused by the isometric rendering that I entirely stopped using it despite wanting to design some RC aircraft in it. For my brain at least, isometric renders are extremely hard to parse as there is no distance information included. It would make it a lot easier for me to use OpenVSP if there was a perspective render mode, it is way easier for my brain to parse.


I am generally opposed to a perspective view in technical programs.  Unless you're placing the 3D object in a virtual world with other items for size and distance information, a perspective view provides an arbitrarily warped view of the model.

Essentially, the problem is that field of view and distance from the object can both be varied in order to 'zoom'.  You can keep the view of a model the same size (say the wingspan takes up the same number of pixels across the screen), but by varying FOV and distance, you get infinite choices of warped images.

A 3D modeling use case like OpenVSP is different from a 3D world (like a FPS video game) because of all the other stuff in the world.  In a FPS game, you generally have a fixed FOV and run around changing the viewpoint position. (occasionally looking through a gun scope with very different FOV).  With perspective, you can't have both near and far views of something without significant distortion -- and alignment of objects is only meaningful if they are at the very center of the view.

Technical drawings, blueprints, 3-views, etc. are dawn without perspective such that everything is to scale and alignment is meaningful.  When you sight along a constant chord wing, the wing should appear to be constant chord.  If you want to see that two objects are aligned in 3D space, you should be able to tell that easily -- without the distortion of perspective views.


You'll notice that OpenVSP also does not support photorealistic rendering.  Optically correct reflections, shadows, and material properties can look really cool, but they take away from what the model is conveying.  Reflections can hide where two surfaces meet.  Shadows make it difficult to see whatever object is not in direct light.

Instead, by choosing to be non-photorealistic, we can make the wing green and the fuselage pink.  We can make OML components translucent -- so you can see objects inside of the aircraft.  We draw feature lines to highlight sharp edges, contours, boundaries, etc.

Photorealistic rendering and perspective are great for glossy brochures, flight simulation, and 3D worlds -- however they are not best for a technical 3D modeling program.

As you spend a little more time with OpenVSP, I think (and hope) you'll come to appreciate these choices.

Rob

Rob McDonald

unread,
Jan 12, 2025, 2:06:25 AMJan 12
to OpenVSP
Here is a chunk of a script that works with VSPAERO results that might be helpful.

def plot_sweep_vspaero():
    vsp.VSPRenew()
    vsp.ReadVSPFile(os.path.join(sweep_dir, 'wingbody.vsp3'))

    vsp.SetAnalysisInputDefaults('VSPAEROReadPreviousAnalysis')
    vsp.PrintAnalysisInputs('VSPAEROReadPreviousAnalysis')
    rid = vsp.ExecAnalysis('VSPAEROReadPreviousAnalysis')
    # vsp.PrintResults(rid)

    resvec = vsp.GetStringResults(rid, 'ResultsVec')

    nres = len(resvec)

    ipolar = -1
    for ires in range(nres):
        if vsp.GetResultsName(resvec[ires]) == 'VSPAERO_Polar':
            ipolar = ires

    if ipolar >= 0:
        polar = resvec[ipolar]

        aldeg = np.array(vsp.GetDoubleResults(polar, 'Alpha'))
        CL = np.array(vsp.GetDoubleResults(polar, 'CL'))
        CDi = np.array(vsp.GetDoubleResults(polar, 'CDi'))
        CDt = np.array(vsp.GetDoubleResults(polar, 'CDt'))
        CMm = np.array(vsp.GetDoubleResults(polar, 'CMm'))

        fig = plt.figure(0)
        ax = fig.add_subplot(111)
        ax = fig.gca()
        ax.plot(aldeg,CL,color='b', label='VSPAERO')
        #ax.set_ylim([-3, 1])
        plt.xlabel('alpha')
        plt.ylabel('C_L')

        fig = plt.figure(1)
        ax = fig.add_subplot(111)
        ax = fig.gca()
        ax.plot(CDi,CL,color='b',label='VSPAERO')
        ax.plot(CDt,CL,color='b',linestyle='--',label='VSPAERO Trefftz')
        #ax.set_ylim([-3, 1])
        plt.xlabel('C_D')
        plt.ylabel('C_L')

        fig = plt.figure(2)
        ax = fig.add_subplot(111)
        ax = fig.gca()
        ax.plot(CL,CMm,color='b',label='VSPAERO')
        #ax.set_ylim([-3, 1])
        plt.xlabel('C_L')
        plt.ylabel('C_m')

Here I'm using VSPAEROReadPreviousAnalysis so my script can plot results from a previous run.  However, the results object should contain exactly the same information after a VSPAERO run.

You might want to check out 'TestAnalysis.vspscript'.  At the top, there is a 'PrintResultsExample' routine that duplicates what the PrintResults API call does.  The API call was added after PrintResults was found to be broadly useful, but the code in PrintResultsExample came first.  The value in PrintResultsExample for you is not that it will print out the contents of a ResultsMgr object, but it documents and illustrates the use of ResultsMgr for getting at data.

The important thing to know about working with AnalysisMgr and ResultsMgr (they use the same stuff under the hood) is that they are based on name-value-documentation triplets.  This way, everything is discoverable -- you can ask a Result what data it has, it will tell you the names, you can then query the type of each data and then request it.  The structure of this data is not hard-coded anywhere.  This allows the same code to access any Result from any Analysis -- even ones that haven't been written yet.

The PyVSP GUI example attempts to illustrate this.  You can use it to load a model, choose an Analysis, set the Inputs, execute, and then browse through the results.  None of this behavior is hard coded.  Even the list of available Analyses is the result of a query.


The call to parasitedrag_sweep is an example where we have a Pythonic wrapper around the native API.  The wrapper is found in parasite_drag.py in the openvsp package.

Under the hood, it is making the same kinds of low-level calls to the AnalysisMgr and ResultsMgr.

Unfortunately, the same sort of convenience wrapper does not exist for VSPAERO.

You might want to check out parse_results_object in utilities.py in the openvsp package.  It is a generic layer that makes working with OpenVSP ResultsMgr more Pythonic.

Rob

Stratos2 - no videos here

unread,
Jan 12, 2025, 2:48:29 AMJan 12
to OpenVSP
It is certainly worth checking a fixed wake solution -- that will speed things up a good bit as well.

VSPAERO as shipped is not really set up for super-detailed gradient based optimization studies.  Some of VSPAERO's tolerances are set relatively coarsely -- they're fine if you're interested in engineering estimates of force and moment coefficients etc.  However, if you're using a gradient based optimizer, it will likely want to take very small steps when calculating derivatives.  The difference in solution between those cases will likely be smaller than the coarse default tolerances used by VSPAERO.  This will cause the derivative information to be unreliable and will send a gradient based optimizer in the wrong direction.

The next VSPAERO update will come with more knobs to tighten the tolerances to help this situation.  The adjoint will also allow exact derivatives of certain things (but OpenVSP does not yet provide analytical derivatives).

If you're doing more of a design space survey -- say a DOE to fit a metamodel of some sort -- you'll probably be fine.

Good to know that this is an area being worked on. I unfortunately won't be able to make use of it this time, but I might next time, maybe if I make this my bachelor thesis topic. We'll see. For now my idea would be to evaluate three cases: AoA 0 Incidence 0, AoA 1 Incidence 0, AoA 0, Incidence1. I haven't figured out quite how yet and have asked my aerodynamics team to look into it, but I do believe so long as the behavior does not run into tolerances too much these three runs alone should be able to predict where the aircraft would be trimmed, where the final solver pass then runs to evaluate details.

Keep it in mind, we usually have international participation at the Workshop

Unless the Workshop venue is equipped to take care of recording and streaming in a way that does not interfere with the workshop, I'm not willing to take away from the in-person experience for recording.  I understand that not everyone can travel -- and I appreciate the value of archiving the presentations to video so they can be accessed.  Our compromise is to hold a virtual workshop every few years.  Many of the Workshop presentations are repeated each year -- and the fundamentals don't change that quickly. 
 
That's fair. I do hope they can be recorded for the future, but if it would detract from the main event that obviously wouldn't make sense.
 
Have you looked at the example scripts that ship with OpenVSP?  I know they are in *.vspscript instead of Python, but the API calls should match 1:1.

I've had a look, though I found it difficult to locate scripts that might contain the correct code. Not knowing what I am looking for and being faced with >1000LOC files did not make that easy. So I stopped at what was more of a cursory look as filenames were not indicative to where I might find a full analysis.
 
OpenVSP development is done by a very small team.  The largest number of concurrent contributors we've ever had could be counted on one hand.  Development work is generally sponsored, but that means that development priorities are set by the sponsor.  So far, sponsors are much more interested in new features than they are in documentation.

That is completely understandable. I'm do unfortunately not have the spare budget to sponsor you guys, but I also do not expect any changes to happen based on my input. Still, I hope me recounting my experiences helps in some way. I'd also like to repeat what I said before, thank you so much for your input and thoughts! The conversation has already saved me hours of trial and error.
 
Most of the effort in documentation has been focused on helping beginners.  Brandon Litherland's OpenVSP Ground School is the primary result of that.

That series is gold, I would have never picked up OpenVSP were it not for the absolutely excellent Ground School.
 
API users are generally assumed to not be beginners -- but you make a good point that everyone is a beginner at everything at some point.

One can still be a beginner at using the API while being an expert at OpenVSP itself. The API as I have experienced has some particularities that are not immediately obvious even if one is perfectly comfortable with the GUI.
 
I appreciate the different kinds of documentation -- our API docs have focused on providing a reference manual so far.  We have not attempted a bigger picture form of documentation.

I must admit, I really struggle with documenting OpenVSP.  It is hard for me to put myself in the shoes of a beginner and imagine what would be most helpful to them.  Some people have advocated for exhaustive documentation of every GUI, window, button, and slider.  We currently have more than 70 GUI's and thousands of parameters.  I can't imagine that telling people that "The Wing Geom's Sweep parameter controls the wing sweep." is useful documentation.  I also struggle with discoverability -- even if everything was documented somewhere, would people actually be able to find and use it when they need it?

I can imagine your position. As someone who deals with it daily, it can be really hard to see where someone who is new might stumble. I do hope sharing my experience helps to give you a bit better of an idea. I would definitely appreciate even just a brief higher level documentation. I don't think it's necessary to write what would in effect be self-explanatory comments on every window, that has no use. What is much more important to convey are principles of operation and important concepts. Such things as there is always one global state that you modify, that it is not like other python modules in that sense. That one might often need to use Update() if there is some strange behavior creating a model, etc etc.
I may write a bit of an absolute beginners crash course myself if I can find the time. I don't have the best idea of the inner workings, but I do believe I can write something that gets a total beginner to the level I am at now, where I can actually go from zero to having evaluated an entire model.
 
Yes, this kind of difference is exactly why I prefer the C++ documentation instead -- it is simply better formatted and organized.

I ended up going with the python one because initially it wasn't clear to me that they were nearly equal.
 
I am generally opposed to a perspective view in technical programs.  Unless you're placing the 3D object in a virtual world with other items for size and distance information, a perspective view provides an arbitrarily warped view of the model.

Essentially, the problem is that field of view and distance from the object can both be varied in order to 'zoom'.  You can keep the view of a model the same size (say the wingspan takes up the same number of pixels across the screen), but by varying FOV and distance, you get infinite choices of warped images.

A 3D modeling use case like OpenVSP is different from a 3D world (like a FPS video game) because of all the other stuff in the world.  In a FPS game, you generally have a fixed FOV and run around changing the viewpoint position. (occasionally looking through a gun scope with very different FOV).  With perspective, you can't have both near and far views of something without significant distortion -- and alignment of objects is only meaningful if they are at the very center of the view.

Technical drawings, blueprints, 3-views, etc. are dawn without perspective such that everything is to scale and alignment is meaningful.  When you sight along a constant chord wing, the wing should appear to be constant chord.  If you want to see that two objects are aligned in 3D space, you should be able to tell that easily -- without the distortion of perspective views.


You'll notice that OpenVSP also does not support photorealistic rendering.  Optically correct reflections, shadows, and material properties can look really cool, but they take away from what the model is conveying.  Reflections can hide where two surfaces meet.  Shadows make it difficult to see whatever object is not in direct light.

Instead, by choosing to be non-photorealistic, we can make the wing green and the fuselage pink.  We can make OML components translucent -- so you can see objects inside of the aircraft.  We draw feature lines to highlight sharp edges, contours, boundaries, etc.

Photorealistic rendering and perspective are great for glossy brochures, flight simulation, and 3D worlds -- however they are not best for a technical 3D modeling program.

As you spend a little more time with OpenVSP, I think (and hope) you'll come to appreciate these choices.

I can agree with you that photo realism is entirely unnecessary in an engineering program. I would however argue that OpenVSP is very much about placing different objects in relation to each other while moving the camera around. That is exactly the process one goes through modelling when using the GUI. Of course, top, side and front views should always be isometric, no question about that. Lining things up with a blueprint would be impossible without. 
But for angled views, I would massively prefer having a perspective view, as I really struggle with getting proportions of objects anywhere near correct without perspective view. I usually rely heavily on my intuition when designing the initial bits of an aircraft, along the lines of "if it looks right it will fly right". But with an isometric view that part of my brain seemingly does not function, I just can not comprehend how things are placed in relation to another, and as soon as I rotate the camera I realize what a cursed creation I just made. Have a look at the screenshot I took of my current OpenVSP testing plane. Due to the isometric projection, the viewer has no way to tell whether the HTP is shifted downwards or to the left in relation to the wing. Looking instead a the second image, a blender screenshot with the same model loaded, it is much more clear where the HTP is placed relative to the wing. At least I can clearly tell the HTP is centered behind the wing and slightly offset down. Looking at the OpenVSP screenshot, my brain tells me the HTP is at the same height as the wing and offset left (relative to flight direction), which is entirely inaccurate.
This has frustrated me to the point of looking into how I could make blender load vsp3 files and automatically reload them to use it as a 3d viewer with perspective. And eventually to giving up OpenVSP back then after I had already spent a few days watching pretty much all of Ground School.
If I needed to make sure that my wing was constant chord I would quickly switch to isometric top view with the hotkey, or just look at the precise parameters. The part of my brain that comprehends depth just entirely fails when looking at isometric images. Any other 3d modelling program I have ever used, be it Fusion360 (CAD), Blender, OpenSCAD, etc, all come with perspective and isometric view options, because both have their usecases. OpenSCAD also doesn't have any realistic rendering, but it does come with a simple perspective view, which is entirely sufficient for my usecase.
I have no way of telling whether I'm an outlier here because my head works extensively in imagining 3d objects, but it would certainly help me a good bit to have a perspective view.




6456846.PNG
484681651.PNG

Stratos2 - no videos here

unread,
Jan 12, 2025, 2:59:55 AMJan 12
to OpenVSP
That is very good to know, I'll explore the parasite_drag.py implementation when I get the time for it. Between my last post and your answer I did thankfully find out about how to get a result id for either the polar or load data specifically, which was the key piece I was missing.

I now have a full chain implemented from generating the aircraft to evaluating it to reading the data back into python, and am now working on integrating this with our already existing optimizer tooling.

I am running into a bit of a strange issue here though: If I import openvsp in the root of my directory tree for the project, it works perfectly fine after the usual setup of creating the conda env and installing the things, then telling pycharm to use said env. However, if I go a layer or two down in the directory tree, so instead of /main.py, I end up at /lib/openvsp_implementation/solver.py, I get an error when I try to do anything with OpenVSP, specifically:

Traceback (most recent call last):
  File "C:\Users\HB Stratos\PycharmProjects\airframe-evaluator-openvsp\lib\openvsp\solver.py", line 200, in <module>
    main()
  File "C:\Users\HB Stratos\PycharmProjects\airframe-evaluator-openvsp\lib\openvsp\solver.py", line 190, in main
    vsp.VSPCheckSetup()
    ^^^^^^^^^^^^^^^^^
AttributeError: module 'openvsp' has no attribute 'VSPCheckSetup'

The module imports without errors, but any attempt to use it shows it imported an empty shell of an object. Which is the same behavior I was seeing when I had forgotten the pip install step. I initially suspected it might have something to do with a relative path, but I can't even run GetVspExePath() as that one also doesn't work.
I can think of a workaround by importing it in main.py and passing a reference down the call chain. But that would be quite ugly. Do you happen to know what's going on here?

Stratos2 - no videos here

unread,
Jan 12, 2025, 4:59:13 AMJan 12
to OpenVSP
Looking closer at this issue, it looks like the file that imports vsp can live anywhere, but it only works when main.py or another file in the project root dir is run. When python is run out of another directory by running the local file, vsp fails to load correctly, even if the current working dir is set to be the project root before the vsp import.
Reply all
Reply to author
Forward
0 new messages