[Help] Goal seek macro

Need help, or want to share a macro? Post here!
kisolre
Veteran
Posts: 4059
Joined: Wed Nov 21, 2018 1:13 pm

[Help] Goal seek macro

Post by kisolre »

Could somebody help creating a "goal seek" macro?
The idea is that you have a design and in it a parameter that needs to be adjusted (for example the internal volume of a glass cup) to a certain value (250ml) by adjusting some parameters. I expect that the rough (initial) design will require adjusting multiple parameters, but to get an exact result only one parameter should be tweaked at the end. My idea so far it to use two (probably selectable) DynamicData objects with three properties with predefined names - Parameter, Result , Goal. One uses Parameter in the design (Body.Pad.Height), sets Result to desired resulting parameter (Body.Shape.Volume) inputs the desired value in the Goal and runs the macro. The macro should change the value of the Parameter and recompute until Result reaches Goal within a threshold. Probably some other parameters might be required (Threshold, MaxSteps, MaxStep, StarChangeDirection, ...)
What I need is just a framework to access the data and I should be able to work it out from there.
Attachments
GoalSeekTest001.FCStd
(9.39 KiB) Downloaded 33 times
openBrain
Veteran
Posts: 7988
Joined: Fri Nov 09, 2018 5:38 pm

Re: [Help] Goal seek macro

Post by openBrain »

The main problem for such an algorithm is the number of ways a model can trigger an error when trying to compute it with 'random' values.
May we consider that we will only use positive values as parameter ?
kisolre
Veteran
Posts: 4059
Joined: Wed Nov 21, 2018 1:13 pm

Re: [Help] Goal seek macro

Post by kisolre »

openBrain wrote: Sat Jan 23, 2021 12:19 am May we consider that we will only use positive values as parameter ?
Probably at least that it will not change sign. So using it in an expression can be made negative if required. Like for example vertical dimension to a point below X axis.
User avatar
Chris_G
Veteran
Posts: 2127
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: [Help] Goal seek macro

Post by Chris_G »

I discovered scipy python package recently.
There is an optimization tool that can do that, even with multiple variables.
My math knowledge is a bit low to fully understand this tool, but I used it successfully to compute minimal curvature for CurvesWB BlendCurve.
User avatar
Chris_G
Veteran
Posts: 2127
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: [Help] Goal seek macro

Post by Chris_G »

If you can install python.scipy, this little script seems to work :

Code: Select all

import FreeCAD
from scipy.optimize import minimize

doc1 = FreeCAD.getDocument('GoalSeekTest001')
o1 = doc1.getObject('dd')
o2 = doc1.getObject('dd001')


def compute(value):
    o1.ddParameter = value[0]
    doc1.recompute()
    return abs(o2.ddGoal.Value - o2.ddResult.Value)

res = minimize(compute, 1, method='Nelder-Mead', options={"maxiter": 2000, "disp": True})

print("For Height = {}, Volume = {}".format(o1.ddParameter, o2.ddResult))
davidosterberg
Posts: 529
Joined: Fri Sep 18, 2020 5:40 pm

Re: [Help] Goal seek macro

Post by davidosterberg »

Chris_G wrote: Sat Jan 23, 2021 9:30 am from scipy.optimize import minimize
Scipy is awesome, definitely the right way. You can even tell it to respect bounds on the parameters (i.e max and min value)
by changing method to e.g "L-BFGS-B" and setting the bounds parameter to a list of (min, max) tuples.
kisolre
Veteran
Posts: 4059
Joined: Wed Nov 21, 2018 1:13 pm

Re: [Help] Goal seek macro

Post by kisolre »

Chris_G wrote: Sat Jan 23, 2021 9:30 am If you can install python.scipy,
Looks like it comes with the latest Windows LibPack (12.4.2) so the macro runs here and is Awesome :)\
Here is a little revised script and I need it to brake when the recompute fails. But clearly this is not the way :)

Code: Select all

import FreeCAD
from scipy.optimize import minimize

sel = Gui.Selection.getSelectionEx()
if len(sel)!=2:
    raise Exception("Select 2 DD objects - Parameter and Goal")
o1=sel[0].Object
o2=sel[1].Object
def compute(value):
    o1.ddParameter = value[0] 
    print(o1.ddParameter)
    if not(App.ActiveDocument.recompute()):
        brake
    return abs(o2.ddGoal.Value - o2.ddResult.Value)

res = minimize(compute, o1.ddParameter, method='Nelder-Mead', options={"maxiter": 100, "disp": True})

print("For Height = {}, Volume = {}".format(o1.ddParameter, o2.ddResult))
And also a MinDelta value because usually dimensions more accurate that 0.0001mm are not practical. Probably some automatic value derived from "Edit/Preferences/General/Units/Number of decimals" property will be Ok.
Attachments
GoalSeekTest002.FCStd
(581.28 KiB) Downloaded 64 times
kisolre
Veteran
Posts: 4059
Joined: Wed Nov 21, 2018 1:13 pm

Re: [Help] Goal seek macro

Post by kisolre »

Here is another example calculating the internal volume of a cup, 3d printed in Vase mode with wall thickness 0.8mm.
.
GoalSeekTest003.JPG
GoalSeekTest003.JPG (135.8 KiB) Viewed 1164 times
Attachments
GoalSeekTest003.FCStd
(690.64 KiB) Downloaded 44 times
edwilliams16
Veteran
Posts: 1349
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: [Help] Goal seek macro

Post by edwilliams16 »

def compute(value):
o1.ddParameter = value[0]
doc1.recompute()
return abs(o2.ddGoal.Value - o2.ddResult.Value)
The minimization may work better using

Code: Select all

return (o2.ddGoal.Value - o2.ddResult.Value)**2
because the latter function is smooth at the minimum, and gradient descent methods will automatically take smaller steps as the minimum is approached.
kisolre
Veteran
Posts: 4059
Joined: Wed Nov 21, 2018 1:13 pm

Re: [Help] Goal seek macro

Post by kisolre »

edwilliams16 wrote: Sat Jan 23, 2021 10:49 pm The minimization may work better using
Yes, it definitely takes less iterations.
Post Reply