Masssearching macro challenge
J. R. Mar 11, 2018 7:32 AMHello,
As a part of a large simulation suite that I'm writing, I've come across an apparently simple, yet quite complicated issue.
There is a solid body in Solidworks model, and a plane offset from Top Plane that intersects that model. The model is then cut in half with Surface Cut with that plane. The offset of the plane has to be adjusted so that the resulting mass of the body is within desired values. In other words, the macro has to solve the model for desired mass value, in as few rebuilds as possible. Here's a screenshot to help visualize it:
If it were any primitive shape (box, sphere, etc.) the solution could be found parametrically, but that won't work with complex or unknown shapes. Therefore, the macro has to compare the desired mass input by the user to the actual mass resulting after the cut is made at a certain height, and work it's magic until the numbers are close enough.
So, to sum it up:
Goal: adjust the height of the cut plane so that the mass of the body after the cut is within 1% of the target mass in as few rebuild cycles as possible.
Setup:
1. The model can be of any shape or size;
2. The bottom of the model is always at zero in Y axis, and it's upper limit is known (provided by user or another function that is outside the scope this challenge);
3. The maximum possible mass (prior to cut) is also known (provided by user or another function);
Requirements:
1. The cut plane height must never go out of bounds (below 0 or above the upper limit);
2. The macro has to reach the desired mass value from any possible current height of the cut plane.
2. The macro cannot do any preanalyses of the model that involves any additional rebuilds, rollbacks, or extra sketches/features to the model.
Here is the prepared code that only requires a search algorithm:
Option Explicit Dim swApp As Object Dim swModel As SldWorks.ModelDoc2 Dim swDimension As SldWorks.Dimension Sub main() Const HeightLimit As Double = 1 Const IterationLimit As Double = 30 Const Margin As Double = 0.01 Dim Mass, TargetMass, MaxMass As Double Dim newHeight As Double Dim IterationCount As Double Set swApp = Application.SldWorks Set swModel = swApp.ActiveDoc MaxMass = 135 'for this specific model TargetMass = 50 'can be anything between 0 and MaxMass IterationCount = 0 While Abs(TargetMass  Mass) > TargetMass * Margin And IterationCount < IterationLimit Mass = GetMass '***algorithm goes here*** 'set new height, rebuild, advance iteration count SetCutPlaneHeight (newHeight) swModel.EditRebuild3 IterationCount = IterationCount + 1 'messages Debug.Print "Iteration count = " & IterationCount & ", Mass = " & Mass If IterationCount = IterationLimit Then Debug.Print "Iteration limit Reached" If Abs(TargetMass  Mass) < TargetMass * Margin Then Debug.Print "Solution found" Wend End Sub Function GetCutPlaneHeight() Set swDimension = swModel.Parameter("D1@Cut plane") GetCutPlaneHeight = swDimension.SystemValue End Function Sub SetCutPlaneHeight(Height As Double) Set swDimension = swModel.Parameter("D1@Cut plane") swDimension.SystemValue = Height End Sub Function GetMass() As Double Dim nStatus As Long Dim vMassProp As Variant Dim Mass As Double vMassProp = swModel.Extension.GetMassProperties2(1, nStatus, True) GetMass = vMassProp(5) End Function
As you can see, it involves simple procedures to get and set the height of the cut plane, and measure the mass of the model after the rebuild. The while cycle has an iteration count that ensures the cycle won't get stuck in an infinite loop. The debug.print system informs of each iteration results, as well as if the solution was found or the iteration count was exceeded.
Now, I've been working on this problem for a few weeks now, and tried several approaches. The best approach that worked for me was:
1. Measuring the difference between target mass and actual mass, and dividing it by the maximum mass;
2. Using this value to set the increment (step size) of the cut plane height;
3. Setting the correct direction to move the increment (+ or );
4. Advancing the cut plane height by the increment;
5. If the actual mass value "jumps over" the target, the increment direction is reversed, and it's value is divided by 2.
6. The cycle repeats until the actually mass reaches the limit.
7. (There are some additional functions that "buffs" the increment if they see that applying it will make the cut plane height to go out of bounds)
It works sort of okay, always finds a solution but since the algorithm is "blind", so to speak, it takes 712 rebuilds on average to find a solution, and sometimes more for very complex and unpredictable shapes.
Another approach that I worked on, but never made work, was this:
1. Measuring the difference between target mass and actual mass, and dividing it by the maximum mass;
2. Using this value to set the increment (step size) of the cut plane height at every iteration.
This algorithm is less "blind", because the increment size is driven by the size of the mass difference, but often it gets stuck because this can make the increment to be too large, and it skips the Goldilocks zone, or it makes the increment too small, and it takes forever to reach the target. This algorithm is great for simple, predictable (gradually changing) models, but is a catastrophe with complex ones.
I also tried combining both methods, but it never worked out well either.
So, I invite you to try your hand with this challenge (attaching the model and the macro below), and see if you can come up with an algorithm that will find an accurate solution within 34 rebuilds, even with very complex and unpredictable models. Try different target masses, try different models (just don't forget to update the constants in the macro), and see if your algorithm can find the solution from any initial position of the cut plane.
Looking forward to it! Hopefully, this can be solved without writing a full AI suite

!Mass search.rar 130.4 KB