From f1d1815340a1ef85c7b248d28f45f82a88137273 Mon Sep 17 00:00:00 2001 From: Ovidiu Mircescu Date: Fri, 6 Jan 2023 15:37:30 +0100 Subject: [PATCH] Add example explained in french. --- README => README.md | 0 src/pydefx/sample.py | 70 ++++++++++++++++- src/pyexample/exemple_fr.py | 148 ++++++++++++++++++++++++++++++++++++ src/pyexample/reconnect.py | 16 ++++ 4 files changed, 230 insertions(+), 4 deletions(-) rename README => README.md (100%) create mode 100644 src/pyexample/exemple_fr.py create mode 100644 src/pyexample/reconnect.py diff --git a/README b/README.md similarity index 100% rename from README rename to README.md diff --git a/src/pydefx/sample.py b/src/pydefx/sample.py index 4ec0163..9b7f6f1 100644 --- a/src/pydefx/sample.py +++ b/src/pydefx/sample.py @@ -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 index 0000000..0319129 --- /dev/null +++ b/src/pyexample/exemple_fr.py @@ -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 index 0000000..7cf97a9 --- /dev/null +++ b/src/pyexample/reconnect.py @@ -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) -- 2.39.2