Skip to main content

Creating an optimization

Changed in v12.1.0

OptimiseButton, OptimisationResult and OptimisationResultElement have been renamed to OptimizationButton, OptimizationResult and OptimizationResultElement respectively.

Within VIKTOR an optimization routine can be constructed, in which different combinations of input parameters are linked to a specific result. The optimization routine should be defined in the app logic and this can either be a brute- force approach or a more sophisticated algorithm if desired.

In this guide a brute-force example is demonstrated, to optimize the cost of a sphere. The input variable is the radius of a sphere, and the to be optimized result is the cost which is a function of the volume.


Usually an optimization can be split into the following steps:

  1. Create an OptimizationButton in the parametrization
  2. Add an optimization method on the Controller
  3. Define and return the desired OptimizationResult

Create an OptimizationButton which refers to the controller method optimize_cost:

class ExampleParametrization(ViktorParametrization):

tab.optimization.btn = OptimizationButton('Optimize', 'optimize_cost', longpoll=True)

In the optimize_cost method, each possible combination of input parameters with corresponding analysis result should be processed and stored in an OptimizationResult:

from math import pifrom viktor import ViktorControllerfrom viktor.result import OptimizationResultfrom viktor.result import OptimizationResultElementclass Controller(ViktorController):    ...    def optimize_cost(self, params, **kwargs):        r_min = 5        r_max = 10        results = []        for radius in range(r_min, r_max):            # override the existing radius for each loop            params = {'tab': {'section': {'radius': radius}}}            # compute the cost            volume = 4 / 3 * pi * radius ** 3            cost = volume * params['price_per_m3']            # store input params with corresponding result dict            results.append(OptimizationResultElement(params, {'optimized_cost': cost}))        return OptimizationResult(results, output_headers={'optimized_cost': 'Cost'})

When the optimization routine has finished, a result window like this will pop up:

Each analysis of the defined loop is listed, and when the result is selected, its corresponding input(s) will be set in the parametrization. It is convenient to link these optimization entries to the input radius. This can be passed to the OptimizationResult as follows:

def optimize_cost(self, params, **kwargs):

input_columns = ['tab.section.radius']
return OptimizationResult(results, input_columns, output_headers={'optimized_cost': 'Cost'})

Also notice the "Results" button just beneath the OptimizationButton, which can be clicked to switch to a different optimization result.

It is recommended to keep the amount of results in the optimization overview limited, and provide a complete overview using an insightful plot which is explained in the next section.

Add an image

Next to the table, an image can be shown to visualize the results. This can be done by using the image argument in the OptimizationResult:

params1 = {'tab': {'section': {'field1': 'a', 'field2': 5}}}params2 = {'tab': {'section': {'field1': 'b', 'field2': 8}}}analysis1 = {'result1': 10, 'result2': 20}analysis2 = {'result1': 100, 'result2': 150}results = [    OptimizationResultElement(params1, analysis1),    OptimizationResultElement(params2, analysis2),]image = SVGResult(...)  # create image with matplotliboptimization_result = OptimizationResult(    results,    output_headers={'result1': 'Result 1'},    image=image,)

This renders as follows in the interface:

See "How to create an image view" for more information on how to create an image-result.