Optimization Plug-In for GH - UI thread + background worker


#1

Hi guys,

I am basically doing something similar as mentioned in this post, however my question is not 100% related to the discussion, so I figured I better create a new topic.

So I am writing a custom component opening a new form, which calls an optimization running in the background, similar to galapagos or goat. The optimization method manipulates the sliders and retrieves the result from the grasshopper file. It should be possible to cancel or force stop the optimization, so I though a background worker which runs the optimization on a separate thread and monitors for cancel requests on the main form might make sense. The problem is, that the optimization itself manipulates the sliders and thus the UI thread from the background worker thread. So the following happens:

  1. If I just call the methods (e.g. set slider values or ExpireSolution) I get an InvalidOperationException in debug mode, also it doesn’t really seem safe to me, as one can manipulate the gh doc while the optimization is running and probably crash it.
  2. If I invoke the functions with BeginInvoke the UI thread including the cancel button freezes again.

Any ideas how to deal with that properly? I noticed Galapagos also freezes / blurs out the gh document, so it cannot be manipulated while the galapagos form is open and running.

Thanks,
Daniel


C# Understanding ComputeData() and SolveInstance() -- what happens when?
(David Rutten) #2

Grasshopper will only solve on the main UI thread. If you start invoking it from background threads it will fail spectacularly. There’s no way to avoid this at present.


(Thomas Wortmann) #3

Hi Daniel,

I also use a backgroundworker, and pass the Grasshopper document to it.
In that way, I can manipulate the GH document from the backgroundworker, while my form stays responsive.
Btw, I’ve never had the need to limit access to the Grasshopper form, since it becomes unresponsive anyway.

The easiest might to to implement your algorithm as a solver for FrOG (there’s an interface class for that).
FrOG is open-source, so you can check out the code here:

Note that this doesn’t work in Debug mode in Visual Studio for some reason.


#4

That is also what I was trying to do (or at least thought what I was doing), basically it seems to work properly, however i can theoretically delete components or manipulate the gh doc in general while the solver runs which is not really safe. That is also,if I understood it correctly, why in debug mode Visual studio catches an InvalidOperationException because of manipulating the UI thread from a background worker, which is not allowed.

I was just noticing, that in Galapagos this is somehow solved, and I was curious how this works in principle… Basically what I want is a cancel form/main form which is responsive, a gh document which is locked and the optimization running in the background.

I will have a look into FrOG and see what I find there, thanks


(Thomas Wortmann) #5

Ah, now I understand what you’re trying to do. Let me know if you figure it out!


#6

OK, so now I reduced the setup, just the backgroundworker with the optimization (as the solver class of the optimization has a pretty clean force stop method which I can also directly call from with my cancel button, no need to have 2 background threads).
After a lot of code changes, finally this seems to work:

  • Lock the UI with a ShowDialog to make sure nobody is playing around with the GH UI while the optimization is running (I think it is pretty weird that you can actually do this in Goat).

  • Encapsulate the interaction with GH UI (where the waitHandle is an AutoResetEvent which get’s set when EndSolution is raised and mainDocument the current GH doc).

          IAsyncResult iAsyncResult = BeginInvoke((MethodInvoker)delegate
          {
              setSliders(x, sliders);   
    
              mainDocument.ScheduleSolution(1);
          });
          this.waitHandle.WaitOne();
          EndInvoke(iAsyncResult);
    

Some things remain still pretty unclear to me, if anybody has some thoughts on that, I’d appreciate it:

  • When I called mainDocument.newSolution(false) it raises at least two times the SolutionEnd event, no idea why that is, that’s why I stuck with scheduleSolution(1)
  • The backgroundworker_RunWorkerCompleted also claims a cross-thread violation when I manipulate the UI from it, which doesn’t make sense to me, as it should also be called on the UI (as the backgroundworker was also created on the UI thread).

Besided, the FroG hat some useful code snippets (e.g. the slider manipulations), so thanks for that.