Skip to main content

Hi community, I am using Python API to perform local optimisation and wanted to display the number of cycles taken for optimising a design. I tried the following code and print the value for LocalOpt.Cycles, but the output was zero:

Code:

# Local optimisation till completion
    print('... Running Local Optimization ...')
    LocalOpt = TheSystem.Tools.OpenLocalOptimization()
    LocalOpt.Algorithm = ZOSAPI.Tools.Optimization.OptimizationAlgorithm.DampedLeastSquares
    LocalOpt.Cycles = ZOSAPI.Tools.Optimization.OptimizationCycles.Automatic
    LocalOpt.NumberOfCores = 8
    print('Initial Merit Function:', LocalOpt.InitialMeritFunction)
    t = time.time()
    LocalOpt.RunAndWaitForCompletion()
    print('Final Merit Function:', LocalOpt.CurrentMeritFunction)
    print('Cycles:', LocalOpt.Cycles)
    # Get the elapsed time.
    elapsed = time.time() - t
    print('Time elapsed: ' + str(round(elapsed,3)) + 's')

 

Output

... Running Local Optimization ...
Initial Merit Function: 3.6106045608778228
Final Merit Function: 3.5055479574965736
Cycles: 0
Time elapsed: 0.521s

 

Does anyone know how can this be done or if it is possible to do it?

Hi @Ai Ping.Yow!

LocalOpt.Cycles is not the number of cycles taken for optimization, it is the setting for the number of cycles. You can see this in line 5 of your example code:

LocalOpt.Cycles = ZOSAPI.Tools.Optimization.OptimizationCycles.Automatic

I suspect you are using Python 3.8 or older, together with Python.NET 2.5.2; in that case it makes sense that your code prints a 0.   ZOSAPI.Tools.Optimization.OptimizationCycles.Automatic  is the first element of the  ZOSAPI.Tools.Optimization.OptimizationCycles enum, so it has index 0; printing an enum value while using Python.NET 2.5.2 will print its index.

Looking at the documentation, I unfortunately don't see a way to get the number of cycles used for optimization.


Thank you chaasjes! Yep, I am using Python 3.7.9.

I also looked through the documentation and wasn’t able to find a way. In that case, I would just use the elapsed time instead for my work.


There is no way to query the current or total cycles for an optimization, but you can come close with modifying your logic.

Rather than calling the blocking (sync) method of RunAndWaitForCompletion, you can call Run and then put the LocalOpt.IsRunning field as the condition of a while loop.  Before the optimization, query & store the local merit function value.  Then inside the while loop, constantly check if the MF has changed...if the value has changed, a new cycle has occurred.

If your system optimizes extremely fast, then you’re likely to miss a few cycles, but if you only have a few hundred cycles per second, you should be able to capture the number of cycles.

A proxy example of how to do this is in PythonStandalone_02_NSC_ray_trace.py around line 167.


Thank you @MichaelH ! It works based on your suggestion 👍🏻 

MFvalue = F]
print('Initial Merit Function:', LocalOpt.InitialMeritFunction)
initMF = LocalOpt.InitialMeritFunction
MFvalue.append(initMF)
t = time.time()
LocalOpt.Run()
while LocalOpt.IsRunning:
currentValue = LocalOpt.CurrentMeritFunction
if MFvaluef-1] != currentValue:
print(f'Changed MF: {currentValue}')
MFvalue.append(currentValue)
LocalOpt.WaitForCompletion()
print('Final Merit Function:', LocalOpt.CurrentMeritFunction)
finalMF = LocalOpt.InitialMeritFunction
LocalOpt.Close()
elapsed = time.time() - t # Get the elapsed time
print('Time elapsed: ' + str(round(elapsed,3)) + 's')
print(f'Cycles: {len(MFvalue)}')

 


Reply