]> SALOME platform Git repositories - tools/ydefx.git/commitdiff
Salome HOME
Add example explained in french.
authorOvidiu Mircescu <ovidiu.mircescu@edf.fr>
Fri, 6 Jan 2023 14:37:30 +0000 (15:37 +0100)
committerOvidiu Mircescu <ovidiu.mircescu@edf.fr>
Fri, 6 Jan 2023 14:37:30 +0000 (15:37 +0100)
README [deleted file]
README.md [new file with mode: 0644]
src/pydefx/sample.py
src/pyexample/exemple_fr.py [new file with mode: 0644]
src/pyexample/reconnect.py [new file with mode: 0644]

diff --git a/README b/README
deleted file mode 100644 (file)
index 758a5f1..0000000
--- a/README
+++ /dev/null
@@ -1,5 +0,0 @@
-The goal of the ydefx library is a tool to make parametric computations on
-distributed resources. It can launch the computations on a remote cluster using
-a batch manager.
-
-This library uses the Salome modules KERNEL and YACS.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..758a5f1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+The goal of the ydefx library is a tool to make parametric computations on
+distributed resources. It can launch the computations on a remote cluster using
+a batch manager.
+
+This library uses the Salome modules KERNEL and YACS.
index 4ec01633c88f689b2e1f1f0abcfd699573ef883b..9b7f6f1cf51cdd56a1bc94b83215d5362b328557 100644 (file)
@@ -34,8 +34,8 @@ class PointState(Enum):
 class Sample:
   def __init__(self, input_names, output_names):
     """
-    input_names  : gives the names and the order of input variables
-    output_names : gives the names and the order of output variables
+    input_names  : the names and the order of input variables
+    output_names : the names and the order of output variables
     """
     if len(input_names) < 1 :
       SampleException("A sample should have at least one input variable.")
@@ -49,15 +49,27 @@ class Sample:
                       # "any string"= error message for that index.
 
   def __iter__(self):
+    """
+    Iterator over input points.
+    """
     return Dico_iter(self._input)
 
   def inputIterator(self):
     """
-    Iterate over input values.
+    Iterate over input points.
     """
     return Dico_iter(self._input)
 
   def setInputValues(self, inputDict):
+    """
+    Set the points to be evaluated.
+    inputDict is a dictionary with:
+      key : name of an input parameter
+      value : list of values for the key.
+    The lists of values should have the same size for all the keys.
+    Exemple :
+      mySample.setInputValues({ "x":[1,2,3], "y":[10,20,30]})
+    """
     if len(inputDict) != len(self._input_names):
       raise SampleException("Incorrect number of keys!")
     size = None
@@ -76,7 +88,17 @@ class Sample:
 
   def addResult(self, index, out_values, message):
     """
-    Add results for index.
+    Set the resut for a point.
+    Parameters :
+      index : index of the point to be set
+      out_values : dictionary with :
+           key : output parameter name
+           value : value to be set for this index
+      message : error message. An empty string means no error. Any other string
+           contains the error message.
+      If the message is not an empty string, out_values is ignored and all the
+      results for this point are set to None as the point is considered to be in
+      error.
     """
     if message is None:
       message = ""
@@ -91,6 +113,16 @@ class Sample:
     self._messages[index] = message
 
   def getPointState(self, index):
+    """
+    Computation state of the point number index.
+    Possible states returned :
+      PointState.NO : The results are not available yet for this point.
+                      The point has not been evaluated yet.
+      PointState.ERROR : The point evaluation is finished but it failed.
+                      There are no values for the output parameters, but there
+                      is a message containing the error.
+      PointState.YES : The results are available for this point.
+    """
     message = self._messages[index]
     if message is None:
       return PointState.NO
@@ -149,12 +181,21 @@ class Sample:
                                                   inputToCheck[name]))
 
   def getInputNames(self):
+    """
+    Return the list of input parameter names.
+    """
     return self._input_names
 
   def getOutputNames(self):
+    """
+    Return the list of output parameter names.
+    """
     return self._output_names
 
   def progressRate(self):
+    """
+    Return 1.0 - unevaluatedPoints / numberOfPoints
+    """
     numberOfPoints = len(self._messages)
     unevaluatedPoints = self._messages.count(None)
     result = 0.0
@@ -162,6 +203,27 @@ class Sample:
       result = 1.0 - unevaluatedPoints / numberOfPoints
     return result
 
+  def getInput(self, name):
+    """
+    Get the list of values for an input parameter.
+    """
+    return self._input[name]
+
+  def getOutput(self, name):
+    """
+    Get the list of values for an output parameter.
+    """
+    return self._output[name]
+
+  def getMessages(self):
+    """
+    Get the list of messages where for any point we can have :
+      None - the point has not been evaluated yet.
+      "" (empty string) - evaluation ok, no error.
+      "any string" - error message.
+    """
+    return self._messages
+
   def __str__(self):
     result = ""
     for name in self._input_names:
diff --git a/src/pyexample/exemple_fr.py b/src/pyexample/exemple_fr.py
new file mode 100644 (file)
index 0000000..0319129
--- /dev/null
@@ -0,0 +1,148 @@
+import os
+
+import pydefx
+
+# Définition des paramètres de lancement
+#########################################
+
+# Charger les paramètres par défaut pour 'gaia' avec le nombre de coeurs qu'on
+# veut utiliser en deuxième paramètre.
+# Ceci permet une configuration rapide où le nombre de coeurs
+# demandés est égal au nombre de branches parallèles d'avaluation.
+#myParams = pydefx.Parameters("gaia", 4)
+myParams = pydefx.Parameters("localhost", 4)
+
+# myParams.salome_parameters contient les paramètres de soumission d'un job
+# qu'il est possible de modifier.
+# Voir la structure JobParameters dans idl/SALOME_Launcher.idl du module KERNEL
+# pour la liste complète des paramètres.
+
+# salome_parameters.work_directory a été rempli à la construction avec le
+# répertoire de travail par défaut de la resource "gaia", défini dans le
+# catalogue des resources de Salome (fichier CatalogResources.xml du dossier
+# d'installation).
+
+# Définir un répertoire de travail personnalisé sur gaia
+myParams.salome_parameters.work_directory = os.path.join(
+                                      myParams.salome_parameters.work_directory,
+                                      "moncas")
+
+# Définir un répertoire local de gestion des fichiers de travail
+# Il est aussi possible de définir directement
+# salome_parameters.result_directory avec un chemin de répertoire déjà créé.
+myParams.createResultDirectory("/tmp")
+
+# On peut indiquer une liste de chemins de fichiers nécessaires au calcul.
+# Ils seront copiés dans le répertoire de travail à distance.
+# Ce paramètre est vide par défaut.
+myParams.salome_parameters.in_files = []
+
+print("ressource de calcul:", myParams.salome_parameters.resource_required.name)
+print("nombre d'évaluations parallèles:", myParams.nb_branches)
+print("nombre de coeurs demandés:",
+      myParams.salome_parameters.resource_required.nb_proc)
+print("nombre de noeuds demandés:",
+      myParams.salome_parameters.resource_required.nb_node)
+print("répertoire de travail:", myParams.salome_parameters.work_directory)
+print("répertoire local de gestion:",
+      myParams.salome_parameters.result_directory)
+
+# Définition de la fonction d'étude
+####################################
+
+# Le script à évaluer doit contenir une fonction "_exec" qui est la fonction
+# d'étude.
+myScript = pydefx.PyScript()
+myScript.loadString("""
+def _exec(x, y):
+  d = x / y
+  t = "{} / {} = {}".format(x, y, d)
+  return d, t
+""")
+
+print("entrées:", myScript.getInputNames())
+print("sorties:", myScript.getOutputNames())
+
+# Définition du plan d'expérience
+##################################
+
+# Création d'un plan d'expériences vide pour le script à étudier
+mySample = myScript.CreateEmptySample()
+# les noms des paramètres en entrée sont identifiés
+print("entrées:", mySample.getInputNames())
+# les noms des paramètres en sortie sont identifiés
+print("sorties:", mySample.getOutputNames())
+
+# 
+mySample.setInputValues({ "x":[ x // 10 for x in range(0,100)],
+                          "y":[ x % 10 for x in range(0,100)]})
+
+# Création de l'étude et lancement du job
+##########################################
+
+myStudy = pydefx.PyStudy()
+myStudy.createNewJob(myScript, mySample, myParams)
+myStudy.launch() # soumission du job
+
+# Sauvegarder l'étude pour s'y connecter dans une autre session.
+# Cette opération marche pour les jobs lancés sur un cluster avec slurm.
+# Ca ne marche pas correctement pour des calculs lancés sur localhost.
+with open("mystudy.txt", "w") as f:
+  f.write(myStudy.dump())
+
+# Il est possible de s'arrêter ici et traiter le résultat dans le script de
+# reprise reconnect.py.
+# Sinon, voici le code pour attendre la fin du calcul et récupérer le résultat
+
+# voir l'avancement
+print("Avancement:", myStudy.getProgress())
+print("Etat:", myStudy.getJobState())
+
+# Attendre la fin des calculs
+myStudy.wait()
+
+print("Avancement:", myStudy.getProgress())
+print("Etat:", myStudy.getJobState())
+
+# Récupérer les résultats - nécessaire pour remplir les listes de résultats.
+# L'objet res contient des informations sur l'exécution globale du job.
+res = myStudy.getResult()
+
+# Y-a-t-il eu une erreur globale ?
+# Les erreurs d'évaluation des points ne sont pas prises en compte ici.
+# On ne considère que les erreurs globales, comme les erreurs dans la soumission
+# du job ou des plantages du job.
+print(res.hasErrors())
+
+# Code de retour de l'exécution du job dans son ensemble.
+# = code d'erreur du processus d'évaluation du schéma YACS (commande driver)
+print(res.getExitCode())
+
+# Message d'erreur de l'exécution du job (erreur de soumission par exemple)
+print(res.getErrors())
+
+# Résultat global utilisé pour des calculs insitu, quand on cherche une valeur
+# globale cumulée pour l'ensemble des évaluations, sans garder les résultats de
+# chaque point.
+# Ce résultat est None s'il n'y a pas de calcul insitu.
+print(res.getResult())
+
+# Affichage de l'objet 'sample'
+print(myStudy.sample)
+
+# Afficher la représentation interne des paramètres d'entrée
+print(myStudy.sample._input)
+
+# Liste des valeurs pour un paramètre d'entrée
+print(myStudy.sample.getInput("x"))
+print(myStudy.sample.getInput("y"))
+
+# Afficher la représentation interne des paramètres de sortie
+print(myStudy.sample._output)
+
+# Liste des résultats pour un paramètre de sortie
+print(myStudy.sample.getOutput("d"))
+print(myStudy.sample.getOutput("t"))
+
+# Liste des messages d'erreur dans l'évaluation de chaque point
+print(myStudy.sample.getMessages())
diff --git a/src/pyexample/reconnect.py b/src/pyexample/reconnect.py
new file mode 100644 (file)
index 0000000..7cf97a9
--- /dev/null
@@ -0,0 +1,16 @@
+import pydefx
+
+with open("mystudy.txt", "r") as f:
+  job_description = f.read()
+
+myStudy = pydefx.PyStudy()
+myStudy.loadFromString(job_description)
+
+print("Avancement:", myStudy.getProgress())
+print("Etat:", myStudy.getJobState())
+myStudy.wait()
+myStudy.getResult()
+print(myStudy.sample)
+print(myStudy.sample._input)
+print(myStudy.sample._output)
+print(myStudy.sample._messages)