Optimisation

Les scripts d'optimisation servent à lancer itérativement des séries de simulation en évaluant à chaque itération si le script doit continuer. Cette évaluation se base sur le calcul d'une fonction d'objectif qui compare les résultats des simulations exportés aux observations renseignées dans la base de données.

Script d'optimisation

Un script d'optimisation est relativement similaire à un plan d'analyse, mais il comprend quelques méthodes en plus. Son but est 1) de générer séquentiellement un ensemble de simulations qui seront executées et 2) déterminer une condition à l'arrêt du script. La particularité est la possible combinaison de simulations séquentielles et parallèles et le fait que les paramètres d’une nouvelle série de simulations sont déterminés au cours du plan sur la base des résultats des simulations précédentes.

Voici l'ensemble des méthodes présentes dans le script:
  • getNecessaryResult() : retourne l'ensemble des résultats devant être calculés par l'ensemble des simulations et nécessaires à l'exécution du script d'optimisation
  • getDescription() : retourne une description du script à destination de l’utilisateur (affichée dans l'interface de lancement)
  • init(OptimizationContext) : sert à initialiser le script d’optimisation (appelée une fois, avant le lancement du script)
  • firstSimulation(OptimizationContext) : sert à générer la première génération de simulation (appelée une fois au lancement du script)
  • nextSimulation(OptimizationContext) : est appelée à chaque nouvelle génération de simulation
  • endSimulation(OptimizationContext) : est appelée à chaque fin d’exécution d'une génération de simulations
  • finish(OptimizationContext context) : appelée une fois, à la fin du script, lorsque que l'ensemble des générations de simulations sont terminées

Génération de simulations

Dans les scripts d'optimisation, on parle de "génération de simulations" pour désigner un ensemble de simulations indépendantes que le script d'optimisation crée à chaque itération à partir des résultats de la génération précédente.

Chaque génération comprend plusieurs simulations qui sont exécutées en parallèle. Mais les "générations de simulations" sont exécutées séquentiellement.

OptimisationContext

L'objet OptimizationContext est un objet qui est donné à chaque méthode du script d'optimisation. Il permet de:
  • connaitre l'état d'avancement du script
  • de produire de nouvelles simulations dans la génération courante
Liste des méthodes disponibles:
  • context.getCurrentGeneration() : permet de connaitre le numéro de la génération en cours. Par exemple, au 3ème appel de nextSimulation() le compteur sera égal à 3 (en prenant en compte que le compteur est égal à 0 dans la méthode firstSimulation())
  • context.newSimulation() : crée une nouvelle simulation dans la génération courante et la retourne sous forme de SimulationStorage (pour être modifiée par l'utilisateur avant son lancement)
  • context.getLastSimulations() : retourne l'ensemble des simulations exécutée dans la dernière génération. Les SimulationStorage retournés peuvent être lus pour en extraire des résultats

Condition d'arrêt

Un script d'optimisation s'arrête lorsqu'il n'y a plus de simulation à exécuter.

Donc, pour arrêter un script, il faut, dans la méthode nextSimulation(OptimizationContext) ne faire aucun appel à context.newSimulation().

Fonction d'objectif

Une fonction d'objectif sert à retourner une valeur à la fin de l'exécution d'une simulation. Cette fonction d'objectif n'est pas générique et dépend de l'optimisation réalisée. Par exemple pour une calibration, elle consiste en général à comparer des sorties de simulation à des observations. Elle doit être programmée par l’utilisateur.

Structure

Un script d'optimisation à des méthodes classiques aux autres scripts:
  • init() pour initialiser la fonction d'objectif
  • getNecessaryResult() pour définir les résultats à calculer pour le fonction d'objectif
  • getDescription() pour fournir une description à l'utilisateur

Il contient surtout une seule méthode spécifique : double eval(OptimizationContext context, List<MatrixND> exports, List<MatrixND> observations) qui sert au calcul de la fonction d’objectif.

Cette méthode prend en paramètres:
  • le contexte de simulation
  • les résultats des exports calculés par la simulation
  • les observations définis lors du lancement du script d'optimisation

Le but de la fonction d'objectif est de comparer les exports aux observations et à définir un indicateur double qui pourra être utile au script d'optimisation.

Le résultat de la fonction d'objectif est stocké dans le SimulationStorage et pourra être récupéré, à la fin de chaque génération, avec la méthode SimulationStorage.getObjective()

Exemple

Fonction d'objectif Objectif3Iteration.java. Cette fonction d'objectif est très simple. Elle retourne -1 lorsque que 3 générations de simulations ont été exécutées.

public class Objective3Iteration implements Objective {

  public double eval(OptimizationContext context, List<MatrixND> exports, List<MatrixND> observations) {
      double result = 0;
      if (context.getCurrentGeneration() >= 3) {
          result = -1;
      }
      return result;
  }
}

Script d'optimisation ExampleObjectif.java. Cet script d'optimisation génère des séries de 2 simulations, tant que la fonction d'objectif n'a pas retourné -1.

public class ExampleOptimization implements Optimization {

  protected boolean stopped = false;

  public void firstSimulation(OptimizationContext context) throws Exception {
      for (int i = 0; i <= 2; i++) {
          SimulationStorage storage = context.newSimulation();
          // modify simulation storage
      }
  }

  public void nextSimulation(OptimizationContext context) throws Exception {
      if (!stopped) {
          for (int i = 0; i <= 2; i++) {
              SimulationStorage storage = context.newSimulation();
              // modify simulation storage
          }
      }
  }

  public void endSimulation(OptimizationContext context) throws Exception {
      List<SimulationStorage> lastGeneration = context.getLastSimulations();
      for (SimulationStorage simulation : lastGeneration) {
          double objective = simulation.getObjective();
          if (objective <= -1) {
              stopped = true;
          }
      }
  }
}

Dans cet exemple, cette fonction d'optimisation aura lancé 8 simulations (4 séries de 2 simulations).