OK, so I really need to write my own simple solver.
But how do I connect to and read from a downstream component value (like from a Num) so I can respond to it in a for-loop, for example.
Say I have the following for-loop;
// Main Simple solver
var current_fitness = GetDownstreamNumValue(); //* How to?
if (current_fitness >= GoodEnough)
return; // dunwithit
// Cause some changes downstreams
OutputA = m_laststeppervalue * SomeSpookyFormula;
// ScheduleSolution with callback etc...
private double m_laststeppervalue;
private double GetDownstreamNumValue()
// Read downstreams Num component value. Um... How?
I understand that I cannot connect the “DownstreamNumValue” to an inport since that would be an illegal circular reference. So there must be another, probaly simple, way to read the downstream component. Access it via a registered guid?
That would be safest. Guid lookup is pretty fast and there are updating issues with using instance references.
You can only get the value inside the parameter after the solution completes, but presumably your code is running inside a solution so that’s fine.
You have to find the object with the correct ID, cast it to a Param_Number and access its VolatileData. This gives you access to the GH_Structure<GH_Number> which stores all calculated values from the most recent solution.
I could call a callback method which saves the value in an instance variable (“m_last_downstream_fitnessvalue”), and ExpireSolution inside the callback, and so check this stored value in the next round in the main method?
Incidentally if you’re using GUIDs to remember specific objects, you’ll want to implement the IGH_InstanceGuidDependent interface. Sometimes all the object ids in a document are mutated (most often when two documents are merged, such as during paste), and you’ll need to know the new id of your target parameter.
By implementing IGH_InstanceGuidDependent you will be informed of these guid changes and you can look up the new guid of an object if you know the old guid.
That can be any components downstreams, represented by the placeholder named “Whatever Downstream Logic” in my example (pictured below).
As the solver’s output values (A and B) changes, then the “Whatever Downstream Logic's” output chnages as well ( = “Fitness A”). And so the solver can terminate if the (input value) Threshold is reached (or some other goal i come up with).
I just need to know what results this stepper’s output causes downstream so it can terminate when a value is “good enough” ( >= Threshold)
Ah, now I see better what you mean. You are onto Galapagos philosophy. But in my case the target number (Threshold) doesn’t change.
So, this is only about reaching a predefined target goal (which is calculated and reached only by downstreams components though). So this is meant to be a “stepper solver” which terminates at that predefined goal.
The term “fitness” associates to finding an optimum by messing with the input, but that is not really the case here, instead the optimum is known beforehand ( = the Threshold).
The solver/stepper outputs whatever data (dummy stepper numbers in this case), causing downstreams components to reevaluate (expire), and so at each step I want to check the result value (“Fitness A”) of the downsstream components and then act on that value in the “RILSolver” stepper (terminate the loop, for example).
The idea is that I can then use the final increment (I) of the Solver/Stepper, knowing that I reached some predefined goal (Fitness = reached the Threshold) at just that increment.
Or, if the predefined Threshold wasn’t reached (quitting at MaxIterations) it means that the downstream logic never reached the predefined goal with any of the data emitted from the Solver/Stepper. Which in some cases also can be a meaningful result.
Still a bit confused, but maybe the attached has sufficient tips to get you going. It’s a script which starts at zero and keeps incrementing an output value until the number inside some parameter exceeds a provided limit.
The basic two tricks are:
Handle the SolutionEnd event because that’s when you know whether the current iteration yielded a good enough number.
The “private double GetResult()” bit was the bit I just couldn’t figure out. I had “debug printed” almost every property of the component (I picked the “Result” num component by name just like you did), but couldn’t get any value out of it. Perhaps it was because I tried to read it in the main method?
this code has been extremely helpful for a little project I am working on - thank you!
one question - I have noticed that closing rhino while the script is running (i.e. while it’s auto scheduling new solutions) leads to a breakpoint pop-up: “an unhandled document exception was trapped”.
I believe this is the result of closing rhino while some internal timer is still running, so, what would you recommend as the best way to cancel any scheduled solutions if the user closes rhino?
There’s a static event called RhinoApp.Closing which may be handled by code which then shuts down the timer. Or maybe handle events on the GH_Document when it goes inactive. I’m not sure what would be soon enough.