Salome HOME
Improvement and extension of EnKF algorithm (loc)
[modules/adao.git] / bin / AdaoCatalogGenerator.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2020 EDF R&D
4 #
5 # This file is part of SALOME ADAO module
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20 #
21 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 #
23 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
24
25 import logging
26 import traceback
27 import sys
28 import io
29 import os
30
31 import module_version
32
33 logging.basicConfig(level=logging.WARNING)
34
35 if sys.version_info.major > 2:
36     def unicode(text, encoding='utf-8'): return text
37
38 print("-- Starting AdaoCalatogGenerator.py --")
39
40 try:
41   import adao
42   import daEficas
43   import daYacsSchemaCreator
44   import daCore.AssimilationStudy
45   import daYacsSchemaCreator.infos_daComposant as infos
46 except:
47   logging.fatal("Import of ADAO python modules failed !" +
48                 "\n add ADAO python installation directory in your PYTHONPATH")
49   traceback.print_exc()
50   sys.exit(1)
51
52 #----------- Templates Part ---------------#
53 begin_catalog_file = """# -*- coding: utf-8 -*-
54 #
55 # Copyright (C) 2008-2020 EDF R&D
56 #
57 # This file is part of SALOME ADAO module
58 #
59 # This library is free software; you can redistribute it and/or
60 # modify it under the terms of the GNU Lesser General Public
61 # License as published by the Free Software Foundation; either
62 # version 2.1 of the License.
63 #
64 # This library is distributed in the hope that it will be useful,
65 # but WITHOUT ANY WARRANTY; without even the implied warranty of
66 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
67 # Lesser General Public License for more details.
68 #
69 # You should have received a copy of the GNU Lesser General Public
70 # License along with this library; if not, write to the Free Software
71 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
72 #
73 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
74 #
75 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
76
77 # --------------------------------------------------------
78 # Generated by AdaoCatalogGenerator on {date}
79 # --------------------------------------------------------
80
81 import os, re
82 import Accas
83 from Accas import *
84
85 JdC = JDC_CATA (
86     code = '%s',
87     execmodul = None,
88     regles = ( AU_MOINS_UN ('ASSIMILATION_STUDY','CHECKING_STUDY'), AU_PLUS_UN ('ASSIMILATION_STUDY','CHECKING_STUDY')),
89     )
90 VERSION_CATALOGUE='%s'
91
92 def NoCheckInNS(filename):
93     return 1
94 NoCheckInNS.info = u""
95 def DirectOperatorInNS(filename):
96     if os.path.exists(filename):
97         fc = open(filename, 'r').readlines()
98         cr = re.compile("^def[\s]*DirectOperator[\s]*\(")
99         for ln in fc:
100             if cr.match(ln): return 1
101         cr = re.compile("^DirectOperator[\s]*=")
102         for ln in fc:
103             if cr.match(ln): return 1
104     return 0
105 DirectOperatorInNS.info = u"The Python file has to contain explicitly a \\"DirectOperator\\" function definition with only one vector as argument."
106 def TangentOperatorInNS(filename):
107     if os.path.exists(filename):
108         fc = open(filename, 'r').readlines()
109         cr = re.compile("^def[\s]*TangentOperator[\s]*\(")
110         for ln in fc:
111             if cr.match(ln): return 1
112         cr = re.compile("^TangentOperator[\s]*=")
113         for ln in fc:
114             if cr.match(ln): return 1
115     return 0
116 TangentOperatorInNS.info = u"The Python file has to contain explicitly a \\"TangentOperator\\" function definition with only one pair of vectors as argument."
117 def AdjointOperatorInNS(filename):
118     if os.path.exists(filename):
119         fc = open(filename, 'r').readlines()
120         cr = re.compile("^def[\s]*AdjointOperator[\s]*\(")
121         for ln in fc:
122             if cr.match(ln): return 1
123         cr = re.compile("^AdjointOperator[\s]*=")
124         for ln in fc:
125             if cr.match(ln): return 1
126     return 0
127 AdjointOperatorInNS.info = u"The Python file has to contain explicitly an \\"AdjointOperator\\" function definition with only one pair of vectors as argument."
128 def ColDataFileExtVal(filename):
129     __readable = (".csv", ".tsv", ".txt", ".npy", ".npz")
130     if os.path.exists(filename) and os.path.splitext(filename)[1] in __readable:
131         return 1
132     return 0
133 ColDataFileExtVal.info = u"The data file has to contain explicitly one or more number columns with separator, or one variable, that can fit in a unique continuous vector."
134 """%(module_version.name,module_version.cata)
135
136 # Important : validators=[...] pour que les conditions soient traitees simultanement, en "ET", et pas en "OU" (choisi dans le cas du tuple a la place de la liste)
137 # validators=[OnlyStr(), FileExtVal('py'), FunctionVal(fv)]
138 data_method = """
139 def F_{data_name}(statut, fv=NoCheckInNS) : return FACT(
140     statut = statut,
141     FROM = SIMP(statut = "o", typ = "TXM", into=({data_into}), defaut={data_default}),
142     SCRIPT_DATA = BLOC ( condition = " FROM in ( 'Script', ) ",
143         SCRIPT_FILE = SIMP(statut = "o", typ = ("FichierNoAbs",'Python Files (*.py)',), validators=[OnlyStr(), FileExtVal('py'), FunctionVal(fv)], fr="En attente d'un nom de fichier script, avec ou sans le chemin complet pour le trouver, contenant si nécessaire la définition d'une variable interne de même nom que le concept parent", ang="Waiting for a script file name, with or without the full path to find it, containing if necessary the definition of an internal variable of the same name as the parent concept"),
144         ),
145     DATA_DATA = BLOC ( condition = " FROM in ( 'DataFile', ) ",
146         DATA_FILE = SIMP(statut = "o", typ = ("FichierNoAbs",'CSV Text Files (*.csv);;TSV Text Files (*.tsv);;TXT Text Files (*.txt);;NPY Binary Numpy Files (*.npy);;NPZ Binary Numpy Files (*.npz);;All Files (*)", ',), validators=[OnlyStr(), FunctionVal(ColDataFileExtVal)], fr="En attente d'un nom de fichier de données, avec ou sans le chemin complet pour le trouver, contenant ou plusieurs colonnes pour définir un unique vecteur continu", ang="Waiting for a data file name, with or without the full path to find it, containing one or more columns to define a unique continuous vector"),
147         ColMajor = SIMP(statut="f", typ = "I", into=(0, 1), defaut=0, fr="Variables en colonnes acquises ligne par ligne (0) ou colonne par colonne (1)", ang="Variables in columns acquired line by line (0) or column by column (1)"),
148         ),
149     STRING_DATA = BLOC ( condition = " FROM in ( 'String', ) ",
150         STRING = SIMP(statut = "o", typ = "TXM",{ms_default} fr="En attente d'une chaine de caractères entre guillements. Pour construire un vecteur ou une matrice, ce doit être une suite de nombres, utilisant un espace ou une virgule pour séparer deux éléments et un point-virgule pour séparer deux lignes", ang="Waiting for a string in quotes. To build a vector or a matrix, it has to be a float serie, using a space or comma to separate two elements in a line, a semi-colon to separate rows"),
151         ),
152     SCRIPTWITHFUNCTIONS_DATA = BLOC ( condition = " FROM in ( 'ScriptWithFunctions', ) ",
153         SCRIPTWITHFUNCTIONS_FILE = SIMP(statut = "o", typ = "FichierNoAbs", validators=[OnlyStr(), FileExtVal('py'), FunctionVal(DirectOperatorInNS), FunctionVal(TangentOperatorInNS), FunctionVal(AdjointOperatorInNS)], fr="En attente d'un nom de fichier script, avec ou sans le chemin complet pour le trouver, contenant en variables internes trois fonctions de calcul nommées DirectOperator, TangentOperator et AdjointOperator", ang="Waiting for a script file name, with or without the full path to find it, containing as internal variables three computation functions named DirectOperator, TangentOperator and AdjointOperator"),
154         ),
155     SCRIPTWITHONEFUNCTION_DATA = BLOC ( condition = " FROM in ( 'ScriptWithOneFunction', ) ",
156         SCRIPTWITHONEFUNCTION_FILE = SIMP(statut = "o", typ = "FichierNoAbs", validators=[OnlyStr(), FileExtVal('py'), FunctionVal(DirectOperatorInNS)], fr="En attente d'un nom de fichier script, avec ou sans le chemin complet pour le trouver, contenant en variable interne une seule fonction de calcul nommée DirectOperator", ang="Waiting for a script file name, with or without the full path to find it, containing as internal variable only one function named DirectOperator"),
157         DifferentialIncrement = SIMP(statut="o", typ = "R", val_min=0, val_max=1, defaut=0.01, fr="Incrément de la perturbation dX pour calculer la dérivée, construite en multipliant X par l'incrément en évitant les valeurs nulles", ang="Increment of dX perturbation to calculate the derivative, build multiplying X by the increment avoiding null values"),
158         CenteredFiniteDifference = SIMP(statut="o", typ = "I", into=(0, 1), defaut=0, fr="Formulation centrée (1) ou décentrée (0) pour la méthode des différences finies", ang="Centered (1) or uncentered (0) formulation for the finite differences method"),
159         EnableMultiProcessing = SIMP(statut="f", typ = "I", into=(0, 1), defaut=0, fr="Calculs élémentaires effectués en séquentiel (0) ou en parallèle (1) dans la méthode des différences finies", ang="Elementary calculations done sequentially (0) or in parallel (1) in the finite differences method"),
160         NumberOfProcesses = SIMP(statut="f", typ = "I", val_min=0, defaut=0, fr="Nombre de processus parallèles, 0 pour un contrôle automatique", ang="Number of parallel processes, 0 for automatic control"),
161         ),
162     SCRIPTWITHSWITCH_DATA = BLOC ( condition = " FROM in ( 'ScriptWithSwitch', ) ",
163         SCRIPTWITHSWITCH_FILE = SIMP(statut = "o", typ = "FichierNoAbs", validators=[OnlyStr(), FileExtVal('py')], fr="En attente d'un nom de fichier script, avec ou sans le chemin complet pour le trouver, contenant un switch pour les calculs direct, tangent et adjoint", ang="Waiting for a script file name, with or without the full path to find it, containing a switch for direct, tangent and adjoint computations"),
164         ),
165     TEMPLATE_DATA =  BLOC (condition = " FROM in ( 'Template', ) ",
166         Template = SIMP(statut = "o", typ = "TXM", min=1, max=1, defaut = "AnalysisPrinter", into=("AnalysisPrinter", "AnalysisSaver", "AnalysisPrinterAndSaver")),
167         AnalysisPrinter = BLOC (condition = " Template == 'AnalysisPrinter' ",
168             ValueTemplate = SIMP(statut = "o", typ = "TXM", min=1, max=1, defaut = "import numpy\\nxa=numpy.ravel(ADD.get('Analysis')[-1])\\nprint('Analysis:',xa)" ),
169             ),
170         AnalysisSaver = BLOC (condition = " Template == 'AnalysisSaver' ",
171             ValueTemplate = SIMP(statut = "o", typ = "TXM", min=1, max=1, defaut = "import numpy\\nxa=numpy.ravel(ADD.get('Analysis')[-1])\\nf='/tmp/analysis.txt'\\nprint('Analysis saved in \\"%s\\"'%f)\\nnumpy.savetxt(f,xa)" ),
172             ),
173         AnalysisPrinterAndSaver = BLOC (condition = " Template == 'AnalysisPrinterAndSaver' ",
174             ValueTemplate = SIMP(statut = "o", typ = "TXM", min=1, max=1, defaut = "import numpy\\nxa=numpy.ravel(ADD.get('Analysis')[-1])\\nprint 'Analysis:',xa\\nf='/tmp/analysis.txt'\\nprint('Analysis saved in \\"%s\\"'%f)\\nnumpy.savetxt(f,xa)" ),
175             ),
176         ),
177     )
178 """
179
180 init_method = """
181 def F_InitChoice() : return  ("Background",
182                               "BackgroundError",
183                               "Observation",
184                               "ObservationError",
185                               "ObservationOperator",
186                               "EvolutionModel",
187                               "EvolutionError",
188                               "AlgorithmParameters",
189                               "UserPostAnalysis",
190                              )
191
192 def F_Init(statut) : return FACT(statut = statut,
193     INIT_FILE = SIMP(statut = "o", typ = "FichierNoAbs", validators=[OnlyStr(), FileExtVal('py')]),
194     TARGET_LIST = SIMP(statut = "o", typ = "TXM", min=1, max="**", into=F_InitChoice(),  validators=(VerifExiste(2))),
195     )
196 """
197
198 assim_data_method = """
199 def {assim_name}InNS(filename):
200     if os.path.exists(filename):
201         fc = open(filename, 'r').readlines()
202         cr = re.compile("^{assim_name}[\s]*=")
203         for ln in fc:
204             if cr.match(ln): return 1
205     return 0
206 {assim_name}InNS.info = u"The Python file has to contain explicitly a \\"{assim_name}\\" variable."
207 def F_{assim_name}(statut, fv=NoCheckInNS) : return FACT(
208     statut=statut,
209 {storage}
210     INPUT_TYPE = SIMP(statut="o", typ = "TXM", into=({choices}), defaut={default_choice}),{decl_choices}
211     )
212 """
213
214 assim_data_choice = """
215     {choice_name} = BLOC ( condition = " INPUT_TYPE in ( '{choice_name}', ) ",
216         data = F_{choice_name}("o", fv),
217         ),"""
218
219 observers_choice = """
220     {var_name} = BLOC (condition=" '{var_name}' in set(SELECTION) ",
221         {var_name}_data = FACT(statut = "o",
222             Scheduler    = SIMP(statut = "f", typ = "TXM"),
223             Info         = SIMP(statut = "o", typ = "TXM", defaut = "{var_name}"),
224             NodeType     = SIMP(statut = "o", typ = "TXM", min=1, max=1, defaut = "Template", into=("String", "Script", "Template")),
225             PythonScript = BLOC (condition = " NodeType == 'String' ",
226                 Value = SIMP(statut = "o", typ = "TXM")
227                 ),
228             UserFile = BLOC (condition = " NodeType == 'Script' ",
229                 Value = SIMP(statut = "o", typ = "FichierNoAbs", validators=[OnlyStr(), FileExtVal('py')])
230                 ),
231             ObserverTemplate = F_ObserverTemplate(),
232             ),
233         ),"""
234
235 from daCore.Templates import ObserverTemplates
236 observers_list = ObserverTemplates.keys_in_presentation_order()
237 observers_list = '"%s"'%str('", "'.join(observers_list))
238 observers_cont = ""
239 for k in ObserverTemplates.keys_in_presentation_order():
240     observers_cont += """                %s = BLOC (condition = " Template == '%s' ",\n"""%(k,k)
241     observers_cont += """                    ValueTemplate = SIMP(statut = "o", typ = "TXM", min=1, max=1, defaut = "%s", fr="%s", ang="%s" ),\n"""%(
242         ObserverTemplates[k].replace("\n","\\n").replace('"','\\"'),
243         ObserverTemplates.getdoc(k, "fr_FR"),
244         ObserverTemplates.getdoc(k, "en_EN"),
245         )
246     observers_cont += """                    ),\n"""
247 observers_method = """
248 def F_ObserverTemplate() : return BLOC(condition = " NodeType == 'Template' ",
249                 Template = SIMP(statut = "o", typ = "TXM", min=1, max=1, defaut = "ValuePrinter", into=(%s)),
250 %s                )
251
252 def F_Observers(statut) : return FACT(
253     statut=statut,
254     SELECTION = SIMP(statut="o", defaut=[], typ="TXM", min=0, max="**", homo="SansOrdreNiDoublon", validators=NoRepeat(), into=({choices})),{decl_choices}
255     )
256 """%(observers_list,observers_cont)
257
258 algo_choices = """
259 def AlgorithmParametersInNS(filename):
260     if os.path.exists(filename):
261         fc = open(filename, 'r').readlines()
262         cr = re.compile("^AlgorithmParameters[\s]*=")
263         for ln in fc:
264             if cr.match(ln): return 1
265     return 0
266 AlgorithmParametersInNS.info = u"The Python file has to contain explicitly an \\"AlgorithmParameters\\" variable."
267 def F_AlgorithmParameters(statut, algos_names, fv=NoCheckInNS) : return FACT(
268     statut = statut,
269     Algorithm = SIMP(statut="o", typ = "TXM", into = algos_names ),
270     Parameters = SIMP(statut="f", typ = "TXM", into=("Defaults", "Dict"), defaut="Defaults"),
271     Dict = BLOC ( condition = " Parameters == 'Dict' ",
272         statut="f",
273         data = F_Dict("o", fv),
274         ),{all_algo_defaults}
275     )
276 """
277 one_algo_choices = """
278     Parameters{algo_name} = BLOC (condition = " (Parameters == 'Defaults') and (Algorithm == '{algo_name}') ",
279         statut="f",
280 {algo_parameters}        ),"""
281
282 assim_study = """
283 def F_variables(statut) : return FACT(
284     statut=statut,
285     regles = ( MEME_NOMBRE ('NAMES', 'SIZES')),
286     NAMES = SIMP(statut="o", typ="TXM", max="**", validators=NoRepeat()),
287     SIZES = SIMP(statut="o", typ="I", val_min=1, max="**")
288     )
289 def ChDir(dirname):
290     os.chdir(os.path.abspath(dirname))
291     return 1
292 ChDir.info = u"This has to be a regular directory path."
293
294 ASSIMILATION_STUDY = PROC(nom="ASSIMILATION_STUDY",
295     op=None,
296     repetable           = "n",
297     StudyName           = SIMP(statut="o", typ = "TXM", defaut="ADAO Calculation Case"),
298     StudyRepertory      = SIMP(statut="f", typ = "Repertoire", validators=FunctionVal(ChDir), min=1, max=1),
299     Debug               = SIMP(statut="f", typ = "I", into=(0, 1), defaut=0),
300     ExecuteInContainer  = SIMP(statut="f", typ = "TXM", min=1, max=1, defaut = "No", into=("No", "Mono", "Multi")),
301     AlgorithmParameters = F_AlgorithmParameters("o",({algos_names}), AlgorithmParametersInNS),
302     Background          = F_Background("o", BackgroundInNS),
303     BackgroundError     = F_BackgroundError("o", BackgroundErrorInNS),
304     Observation         = F_Observation("o", ObservationInNS),
305     ObservationError    = F_ObservationError("o", ObservationErrorInNS),
306     ObservationOperator = F_ObservationOperator("o"),
307     EvolutionModel      = F_EvolutionModel("f"),
308     EvolutionError      = F_EvolutionError("f", EvolutionErrorInNS),
309     ControlInput        = F_ControlInput("f"),
310     UserDataInit        = F_Init("f"),
311     UserPostAnalysis    = F_UserPostAnalysis("o"),
312     InputVariables      = F_variables("f"),
313     OutputVariables     = F_variables("f"),
314     Observers           = F_Observers("f")
315     )
316
317 CHECKING_STUDY = PROC(nom="CHECKING_STUDY",
318     op=None,
319     repetable           = "n",
320     StudyName           = SIMP(statut="o", typ = "TXM", defaut="ADAO Checking Case"),
321     StudyRepertory      = SIMP(statut="f", typ = "Repertoire", validators=FunctionVal(ChDir), min=1, max=1),
322     Debug               = SIMP(statut="f", typ = "I", into=(0, 1), defaut=0),
323     ExecuteInContainer  = SIMP(statut="f", typ = "TXM", min=1, max=1, defaut = "No", into=("No", "Mono", "Multi")),
324     AlgorithmParameters = F_AlgorithmParameters("o", ({check_names}), AlgorithmParametersInNS),
325     CheckingPoint       = F_CheckingPoint("o", CheckingPointInNS),
326     Background          = F_Background("f", BackgroundInNS),
327     BackgroundError     = F_BackgroundError("f", BackgroundErrorInNS),
328     Observation         = F_Observation("f", ObservationInNS),
329     ObservationError    = F_ObservationError("f", ObservationErrorInNS),
330     ObservationOperator = F_ObservationOperator("o"),
331     UserDataInit        = F_Init("f"),
332     Observers           = F_Observers("f")
333     )
334 """
335
336 #----------- End of Templates Part ---------------#
337
338
339
340 #----------- Begin generation script -----------#
341
342 # Parse arguments
343 from argparse import ArgumentParser
344 usage = "usage: %(prog)s [options] catalog_path catalog_name"
345 version="%(prog)s 0.1"
346 my_parser = ArgumentParser(usage=usage)
347 my_parser.add_argument('-v', '--version', action='version', version=version)
348 my_parser.add_argument('catalog_path')
349 my_parser.add_argument('catalog_name')
350 args = my_parser.parse_args()
351
352 # Generates into a string
353 mem_file = io.StringIO()
354
355 # Start file
356 from time import strftime
357 mem_file.write(unicode(begin_catalog_file, 'utf-8').format(**{'date':strftime("%Y-%m-%d %H:%M:%S")}))
358
359 # Step initial: on obtient la liste des algos
360 algos_names = ""
361 check_names = ""
362 decl_algos  = ""
363 assim_study_object = daCore.AssimilationStudy.AssimilationStudy()
364 algos_list = assim_study_object.get_available_algorithms()
365 del assim_study_object
366 for algo_name in algos_list:
367   if algo_name in infos.AssimAlgos:
368     logging.debug("An assimilation algorithm is found: " + algo_name)
369     algos_names += "\"" + algo_name + "\", "
370   elif algo_name in infos.CheckAlgos:
371     logging.debug("A checking algorithm is found: " + algo_name)
372     check_names += "\"" + algo_name + "\", "
373   else:
374     logging.debug("This algorithm is not considered: " + algo_name)
375
376 # Step 1: A partir des infos, on cree les fonctions qui vont permettre
377 # d'entrer les donnees utilisateur
378 for data_input_name in infos.DataTypeDict:
379   logging.debug('A data input Type is found: ' + data_input_name)
380   data_name = data_input_name
381   data_into = ""
382   data_default = ""
383   ms_default = ""
384
385   # On recupere les differentes facon d'entrer les donnees
386   for basic_type in infos.DataTypeDict[data_input_name]:
387     data_into += "\"" + basic_type + "\", "
388
389   # On choisit le default
390   data_default = "\"" + infos.DataTypeDefaultDict[data_input_name] + "\""
391   if data_input_name in infos.DataSValueDefaultDict:
392     ms_default = " defaut=\"" + infos.DataSValueDefaultDict[data_input_name] + "\","
393
394   mem_file.write(unicode(data_method, 'utf-8').format(**{
395     'data_name'    : data_name,
396     'data_into'    : data_into,
397     'data_default' : data_default,
398     'ms_default'   : ms_default,
399     'algos_names'  : algos_names+check_names,
400     }))
401
402 # Step 2: On cree les fonctions qui permettent de rentrer les donnees des algorithmes
403 for assim_data_input_name in infos.AssimDataDict:
404   logging.debug("An input function data input is found: " + assim_data_input_name)
405   # assim_name = assim_data_input_name
406   storage = ""
407   choices = ""
408   default_choice = ""
409   decl_choices = ""
410   decl_opts = ""
411   if infos.AssimDataDefaultDict[assim_data_input_name] in infos.StoredAssimData:
412     storage = "    Stored = SIMP(statut=\"f\", typ = \"I\", into=(0, 1), defaut=0, fr=\"Choix de stockage interne ou non du concept parent\", ang=\"Choice of the storage or not of the parent concept\"),"
413   for choice in infos.AssimDataDict[assim_data_input_name]:
414     choices += "\"" + choice + "\", "
415     decl_choices += assim_data_choice.format(**{'choice_name' : choice})
416     if choice in infos.StoredAssimData:
417       storage = "    Stored = SIMP(statut=\"f\", typ = \"I\", into=(0, 1), defaut=0, fr=\"Choix de stockage interne ou non du concept parent\", ang=\"Choice of the storage or not of the parent concept\"),"
418   default_choice = "\"" + infos.AssimDataDefaultDict[assim_data_input_name] + "\""
419
420   mem_file.write(unicode(assim_data_method, 'utf-8').format(**{
421     'assim_name'     : assim_data_input_name,
422     'storage'        : storage,
423     'choices'        : choices,
424     'decl_choices'   : decl_choices,
425     'default_choice' : default_choice,
426     }))
427
428 # Step 3: On ajoute les fonctions representant les options possibles
429 for opt_name in infos.OptDict:
430   logging.debug("An optional node is found: " + opt_name)
431   data_name = opt_name
432   data_into = ""
433   data_default = ""
434   ms_default = ""
435
436   for choice in infos.OptDict[opt_name]:
437     data_into += "\"" + choice + "\", "
438
439   # On choisit le default
440   data_default = "\"" + infos.OptDefaultDict[opt_name] + "\""
441   if opt_name in infos.DataSValueDefaultDict:
442     ms_default = " defaut=\"" + infos.DataSValueDefaultDict[opt_name] + "\","
443
444   mem_file.write(unicode(data_method, 'utf-8').format(**{
445     'data_name'    : data_name,
446     'data_into'    : data_into,
447     'data_default' : data_default,
448     'ms_default'   : ms_default,
449     'algos_names'  : algos_names+check_names,
450     }))
451
452 # Step 4: On ajoute la methode optionnelle init
453 # TODO uniformiser avec le step 3
454 mem_file.write(unicode(init_method, 'utf-8'))
455
456 # Step 5: Add observers
457 decl_choices = ""
458 for obs_var in infos.ObserversList:
459   decl_choices += observers_choice.format(**{'var_name':obs_var})
460 mem_file.write(unicode(observers_method, 'utf-8').format(**{
461   'choices' : infos.ObserversList,
462   'decl_choices' : decl_choices,
463   }))
464
465 # Step 5: Add algorithmic choices
466
467 all_names = eval((algos_names+check_names))
468 all_algo_defaults = ""
469 for algo in all_names:
470     assim_study_object = daCore.AssimilationStudy.AssimilationStudy()
471     assim_study_object.setAlgorithmParameters(Algorithm=algo)
472     par_dict = assim_study_object.get("AlgorithmRequiredParameters",False)
473     par_keys = sorted(par_dict.keys())
474     algo_parameters = ""
475     for pn in par_keys:
476         if pn in ("StoreInternalVariables", "PlotAndSave", "ResultFile", "ResultTitle", "ResultLabel"): continue # Cles a supprimer
477         pt = par_dict[pn]["typecast"] # Pointeur de type
478         pd = par_dict[pn]["default"]
479         pm = par_dict[pn]["message"]
480         if "minval" in par_dict[pn] and par_dict[pn]["minval"] is not None:
481             vi = ", val_min=%s"%par_dict[pn]["minval"]
482         else:
483             vi = ""
484         if "minval" in par_dict[pn] and par_dict[pn]["maxval"] is not None:
485             vs = ", val_max=%s"%par_dict[pn]["maxval"]
486         else:
487             vs = ""
488         if   pt is int:
489             algo_parameters += """        %s = SIMP(statut="f", typ="I"%s%s, min=1, max=1, defaut=%s, fr="%s"),\n"""%(pn,vi,vs,int(pd),pm)
490         elif pt is float:
491             algo_parameters += """        %s = SIMP(statut="f", typ="R"%s%s, min=1, max=1, defaut=%s, fr="%s"),\n"""%(pn,vi,vs,float(pd),pm)
492         elif pt is bool:
493             algo_parameters += """        %s = SIMP(statut="f", typ="I", min=1, max=1, defaut=%s, fr="%s"),\n"""%(pn,int(pd),pm)
494         elif pt is str and "listval" in par_dict[pn]:
495             algo_parameters += """        %s = SIMP(statut="f", typ="TXM", min=1, max=1, defaut="%s", into=%s, fr="%s"),\n"""%(pn,pd,par_dict[pn]["listval"],pm)
496         elif pt is tuple and "listval" in par_dict[pn]:
497             algo_parameters += """        %s = SIMP(statut="f", typ="TXM", max="**", into=%s, fr="%s"),\n"""%(pn,par_dict[pn]["listval"],pm)
498         else:
499             algo_parameters += """        %s = SIMP(statut="f", typ="TXM", fr="%s"),\n"""%(pn,pm)
500     del assim_study_object
501     if algo_parameters != "":
502         all_algo_defaults += one_algo_choices.format(**{
503             'algo_name':algo,
504             'algo_parameters':algo_parameters,
505             })
506 mem_file.write(unicode(algo_choices, 'utf-8').format(**{'all_algo_defaults':unicode(all_algo_defaults, 'utf-8')}))
507
508 # Final step: Add algorithm and assim_study
509 mem_file.write(unicode(assim_study, 'utf-8').format(**{
510   'algos_names':algos_names,
511   'check_names':check_names,
512   'decl_algos':decl_algos,
513   }))
514
515 # Write file
516 if sys.version_info.major > 2:
517     with open(os.path.join(args.catalog_path, args.catalog_name), "w", encoding='utf8') as final_file:
518         final_file.write(mem_file.getvalue())
519 else:
520     with open(os.path.join(args.catalog_path, args.catalog_name), "wr") as final_file:
521         final_file.write(mem_file.getvalue().encode('utf-8'))
522 mem_file.close()