Salome HOME
Extending data file input capacity for vectors series
[modules/adao.git] / src / daComposant / daCore / Interfaces.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2008-2019 EDF R&D
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 # Author: Jean-Philippe Argaud, jean-philippe.argaud@edf.fr, EDF R&D
22
23 """
24     Définit les outils d'interfaces normalisées de cas.
25 """
26 __author__ = "Jean-Philippe ARGAUD"
27 __all__ = []
28
29 import os
30 import sys
31 import numpy
32 import mimetypes
33 import logging
34 import copy
35 from daCore import Persistence
36 from daCore import PlatformInfo
37 from daCore import Templates
38
39 # ==============================================================================
40 class GenericCaseViewer(object):
41     """
42     Gestion des commandes de creation d'une vue de cas
43     """
44     def __init__(self, __name="", __objname="case", __content=None, __object=None):
45         "Initialisation et enregistrement de l'entete"
46         self._name         = str(__name)
47         self._objname      = str(__objname)
48         self._lineSerie    = []
49         self._switchoff    = False
50         self._numobservers = 2
51         self._content      = __content
52         self._object       = __object
53         self._missing = """raise ValueError("This case requires beforehand to import or define the variable named <%s>. When corrected, remove this command, correct and uncomment the following one.")\n# """
54     def _append(self, *args):
55         "Transformation de commande individuelle en enregistrement"
56         raise NotImplementedError()
57     def _extract(self, *args):
58         "Transformation d'enregistrement en commande individuelle"
59         raise NotImplementedError()
60     def _finalize(self, __upa=None):
61         "Enregistrement du final"
62         if __upa is not None and len(__upa)>0:
63             self._lineSerie.append("%s.execute()"%(self._objname,))
64             self._lineSerie.append(__upa)
65     def _addLine(self, line=""):
66         "Ajoute un enregistrement individuel"
67         self._lineSerie.append(line)
68     def _get_objname(self):
69         return self._objname
70     def dump(self, __filename=None, __upa=None):
71         "Restitution normalisée des commandes"
72         self._finalize(__upa)
73         __text = "\n".join(self._lineSerie)
74         __text +="\n"
75         if __filename is not None:
76             __file = os.path.abspath(__filename)
77             __fid = open(__file,"w")
78             __fid.write(__text)
79             __fid.close()
80         return __text
81     def load(self, __filename=None, __content=None, __object=None):
82         "Chargement normalisé des commandes"
83         if __filename is not None and os.path.exists(__filename):
84             self._content = open(__filename, 'r').read()
85         elif __content is not None and type(__content) is str:
86             self._content = __content
87         elif __object is not None and type(__object) is dict:
88             self._object = copy.deepcopy(__object)
89         else:
90             pass # use "self._content" from initialization
91         __commands = self._extract(self._content, self._object)
92         return __commands
93
94 class _TUIViewer(GenericCaseViewer):
95     """
96     Etablissement des commandes d'un cas ADAO TUI (Cas<->TUI)
97     """
98     def __init__(self, __name="", __objname="case", __content=None, __object=None):
99         "Initialisation et enregistrement de l'entete"
100         GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
101         self._addLine("# -*- coding: utf-8 -*-")
102         self._addLine("#\n# Python script using ADAO TUI\n#")
103         self._addLine("from numpy import array, matrix")
104         self._addLine("from adao import adaoBuilder")
105         self._addLine("%s = adaoBuilder.New('%s')"%(self._objname, self._name))
106         if self._content is not None:
107             for command in self._content:
108                 self._append(*command)
109     def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
110         "Transformation d'une commande individuelle en un enregistrement"
111         if __command is not None and __keys is not None and __local is not None:
112             __text  = ""
113             if __pre is not None:
114                 __text += "%s = "%__pre
115             __text += "%s.%s( "%(self._objname,str(__command))
116             if "self" in __keys: __keys.remove("self")
117             if __command not in ("set","get") and "Concept" in __keys: __keys.remove("Concept")
118             for k in __keys:
119                 __v = __local[k]
120                 if __v is None: continue
121                 if   k == "Checked"              and not __v: continue
122                 if   k == "Stored"               and not __v: continue
123                 if   k == "ColMajor"             and not __v: continue
124                 if   k == "InputFunctionAsMulti" and not __v: continue
125                 if   k == "nextStep"             and not __v: continue
126                 if   k == "AvoidRC"              and     __v: continue
127                 if   k == "noDetails":                        continue
128                 if isinstance(__v,Persistence.Persistence): __v = __v.values()
129                 if callable(__v): __text = self._missing%__v.__name__+__text
130                 if isinstance(__v,dict):
131                     for val in __v.values():
132                         if callable(val): __text = self._missing%val.__name__+__text
133                 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
134                 __text += "%s=%s, "%(k,repr(__v))
135                 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
136             __text.rstrip(", ")
137             __text += ")"
138             self._addLine(__text)
139     def _extract(self, __multilines="", __object=None):
140         "Transformation un enregistrement en une commande individuelle"
141         __is_case = False
142         __commands = []
143         __multilines = __multilines.replace("\r\n","\n")
144         for line in __multilines.split("\n"):
145             if "adaoBuilder.New" in line and "=" in line:
146                 self._objname = line.split("=")[0].strip()
147                 __is_case = True
148                 logging.debug("TUI Extracting commands of '%s' object..."%(self._objname,))
149             if not __is_case:
150                 continue
151             else:
152                 if self._objname+".set" in line:
153                     __commands.append( line.replace(self._objname+".","",1) )
154                     logging.debug("TUI Extracted command: %s"%(__commands[-1],))
155         return __commands
156
157 class _COMViewer(GenericCaseViewer):
158     """
159     Etablissement des commandes d'un cas COMM (Eficas Native Format/Cas<-COM)
160     """
161     def __init__(self, __name="", __objname="case", __content=None, __object=None):
162         "Initialisation et enregistrement de l'entete"
163         GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
164         self._observerIndex = 0
165         self._addLine("# -*- coding: utf-8 -*-")
166         self._addLine("#\n# Python script using ADAO COMM\n#")
167         self._addLine("from numpy import array, matrix")
168         self._addLine("#")
169         self._addLine("%s = {}"%__objname)
170         if self._content is not None:
171             for command in self._content:
172                 self._append(*command)
173     def _extract(self, __multilines=None, __object=None):
174         "Transformation un enregistrement en une commande individuelle"
175         if __multilines is not None:
176             __multilines = __multilines.replace("ASSIMILATION_STUDY","dict")
177             __multilines = __multilines.replace("CHECKING_STUDY",    "dict")
178             __multilines = __multilines.replace("_F(",               "dict(")
179             __multilines = __multilines.replace(",),);",             ",),)")
180         __fulllines = ""
181         for line in __multilines.split("\n"):
182             if len(line) < 1: continue
183             __fulllines += line + "\n"
184         __multilines = __fulllines
185         self._objname = "case"
186         self._objdata = None
187         exec("self._objdata = "+__multilines)
188         #
189         if self._objdata is None or not(type(self._objdata) is dict) or not('AlgorithmParameters' in self._objdata):
190             raise ValueError("Impossible to load given content as an ADAO COMM one (no dictionnary or no 'AlgorithmParameters' key found).")
191         # ----------------------------------------------------------------------
192         logging.debug("COMM Extracting commands of '%s' object..."%(self._objname,))
193         __commands = []
194         __UserPostAnalysis = ""
195         for k,r in self._objdata.items():
196             __command = k
197             logging.debug("COMM Extracted command: %s:%s"%(k, r))
198             if   __command == "StudyName" and len(str(r))>0:
199                 __commands.append( "set( Concept='Name', String='%s')"%(str(r),) )
200             elif   __command == "StudyRepertory":
201                 __commands.append( "set( Concept='Directory', String='%s')"%(str(r),) )
202             #
203             elif __command == "UserPostAnalysis" and type(r) is dict:
204                 if 'STRING' in r:
205                     __UserPostAnalysis = r['STRING']
206                 elif 'SCRIPT_FILE' in r and os.path.exists(r['SCRIPT_FILE']):
207                     __UserPostAnalysis = open(r['SCRIPT_FILE'],'r').read()
208                 elif 'Template' in r and 'ValueTemplate' in r:
209                     # AnalysisPrinter...
210                     __UserPostAnalysis = r['ValueTemplate']
211                 else:
212                     __UserPostAnalysis = ""
213                 __UserPostAnalysis = __UserPostAnalysis.replace("ADD",self._objname)
214             #
215             elif __command == "AlgorithmParameters" and type(r) is dict and 'Algorithm' in r:
216                 if 'data' in r and r['Parameters'] == 'Dict':
217                     __from = r['data']
218                     if 'STRING' in __from:
219                         __parameters = ", Parameters=%s"%(repr(eval(__from['STRING'])),)
220                     elif 'SCRIPT_FILE' in __from and os.path.exists(__from['SCRIPT_FILE']):
221                         __parameters = ", Script='%s'"%(__from['SCRIPT_FILE'],)
222                 else: # if 'Parameters' in r and r['Parameters'] == 'Defaults':
223                     __Dict = copy.deepcopy(r)
224                     __Dict.pop('Algorithm','')
225                     __Dict.pop('Parameters','')
226                     if 'SetSeed' in __Dict:__Dict['SetSeed'] = int(__Dict['SetSeed'])
227                     if 'BoxBounds' in __Dict and type(__Dict['BoxBounds']) is str:
228                         __Dict['BoxBounds'] = eval(__Dict['BoxBounds'])
229                     if len(__Dict) > 0:
230                         __parameters = ', Parameters=%s'%(repr(__Dict),)
231                     else:
232                         __parameters = ""
233                 __commands.append( "set( Concept='AlgorithmParameters', Algorithm='%s'%s )"%(r['Algorithm'],__parameters) )
234             #
235             elif __command == "Observers" and type(r) is dict and 'SELECTION' in r:
236                 if type(r['SELECTION']) is str:
237                     __selection = (r['SELECTION'],)
238                 else:
239                     __selection = tuple(r['SELECTION'])
240                 for sk in __selection:
241                     __idata = r['%s_data'%sk]
242                     if __idata['NodeType'] == 'Template' and 'Template' in __idata:
243                         __template = __idata['Template']
244                         if 'Info' in __idata:
245                             __info = ", Info='%s'"%(__idata['Info'],)
246                         else:
247                             __info = ""
248                         __commands.append( "set( Concept='Observer', Variable='%s', Template='%s'%s )"%(sk,__template,__info) )
249                     if __idata['NodeType'] == 'String' and 'Value' in __idata:
250                         __value =__idata['Value']
251                         __commands.append( "set( Concept='Observer', Variable='%s', String='%s' )"%(sk,__value) )
252             #
253             # Background, ObservationError, ObservationOperator...
254             elif type(r) is dict:
255                 __argumentsList = []
256                 if 'Stored' in r and bool(r['Stored']):
257                     __argumentsList.append(['Stored',True])
258                 if 'INPUT_TYPE' in r and 'data' in r:
259                     # Vector, Matrix, ScalarSparseMatrix, DiagonalSparseMatrix, Function
260                     __itype = r['INPUT_TYPE']
261                     __idata = r['data']
262                     if 'FROM' in __idata:
263                         # String, Script, DataFile, Template, ScriptWithOneFunction, ScriptWithFunctions
264                         __ifrom = __idata['FROM']
265                         __idata.pop('FROM','')
266                         if __ifrom == 'String' or __ifrom == 'Template':
267                             __argumentsList.append([__itype,__idata['STRING']])
268                         if __ifrom == 'Script':
269                             __argumentsList.append([__itype,True])
270                             __argumentsList.append(['Script',__idata['SCRIPT_FILE']])
271                         if __ifrom == 'DataFile':
272                             __argumentsList.append([__itype,True])
273                             __argumentsList.append(['DataFile',__idata['DATA_FILE']])
274                         if __ifrom == 'ScriptWithOneFunction':
275                             __argumentsList.append(['OneFunction',True])
276                             __argumentsList.append(['Script',__idata.pop('SCRIPTWITHONEFUNCTION_FILE')])
277                             if len(__idata)>0:
278                                 __argumentsList.append(['Parameters',__idata])
279                         if __ifrom == 'ScriptWithFunctions':
280                             __argumentsList.append(['ThreeFunctions',True])
281                             __argumentsList.append(['Script',__idata.pop('SCRIPTWITHFUNCTIONS_FILE')])
282                             if len(__idata)>0:
283                                 __argumentsList.append(['Parameters',__idata])
284                 __arguments = ["%s = %s"%(k,repr(v)) for k,v in __argumentsList]
285                 __commands.append( "set( Concept='%s', %s )"%(__command, ", ".join(__arguments)))
286         #
287         # ----------------------------------------------------------------------
288         __commands.sort() # Pour commencer par 'AlgorithmParameters'
289         __commands.append(__UserPostAnalysis)
290         return __commands
291
292 class _SCDViewer(GenericCaseViewer):
293     """
294     Etablissement des commandes d'un cas SCD (Study Config Dictionary/Cas->SCD)
295     """
296     def __init__(self, __name="", __objname="case", __content=None, __object=None):
297         "Initialisation et enregistrement de l'entete"
298         GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
299         self._addLine("# -*- coding: utf-8 -*-")
300         self._addLine("#\n# Input for ADAO converter to YACS\n#")
301         self._addLine("from numpy import array, matrix")
302         self._addLine("#")
303         self._addLine("study_config = {}")
304         self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'")
305         self._addLine("study_config['Name'] = '%s'"%self._name)
306         self._addLine("observers = {}")
307         self._addLine("study_config['Observers'] = observers")
308         self._addLine("#")
309         self._addLine("inputvariables_config = {}")
310         self._addLine("inputvariables_config['Order'] =['adao_default']")
311         self._addLine("inputvariables_config['adao_default'] = -1")
312         self._addLine("study_config['InputVariables'] = inputvariables_config")
313         self._addLine("#")
314         self._addLine("outputvariables_config = {}")
315         self._addLine("outputvariables_config['Order'] = ['adao_default']")
316         self._addLine("outputvariables_config['adao_default'] = -1")
317         self._addLine("study_config['OutputVariables'] = outputvariables_config")
318         if __content is not None:
319             for command in __content:
320                 self._append(*command)
321     def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
322         "Transformation d'une commande individuelle en un enregistrement"
323         if __command == "set": __command = __local["Concept"]
324         else:                  __command = __command.replace("set", "", 1)
325         #
326         __text  = None
327         if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get', 'Name'):
328             return
329         elif __command in ['Debug', 'setDebug']:
330             __text  = "#\nstudy_config['Debug'] = '1'"
331         elif __command in ['NoDebug', 'setNoDebug']:
332             __text  = "#\nstudy_config['Debug'] = '0'"
333         elif __command in ['Observer', 'setObserver']:
334             __obs   = __local['Variable']
335             self._numobservers += 1
336             __text  = "#\n"
337             __text += "observers['%s'] = {}\n"%__obs
338             if __local['String'] is not None:
339                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
340                 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
341             if __local['Script'] is not None:
342                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
343                 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
344             if __local['Template'] is not None and __local['Template'] in Templates.ObserverTemplates:
345                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
346                 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, Templates.ObserverTemplates[__local['Template']])
347             if __local['Info'] is not None:
348                 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
349             else:
350                 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
351             __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
352         elif __local is not None: # __keys is not None and
353             numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
354             __text  = "#\n"
355             __text += "%s_config = {}\n"%__command
356             __local.pop('self','')
357             __to_be_removed = []
358             for __k,__v in __local.items():
359                 if __v is None: __to_be_removed.append(__k)
360             for __k in __to_be_removed:
361                 __local.pop(__k)
362             for __k,__v in __local.items():
363                 if __k == "Concept": continue
364                 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix','OneFunction','ThreeFunctions'] and 'Script' in __local and __local['Script'] is not None: continue
365                 if __k in ['Vector','VectorSerie'] and 'DataFile' in __local and __local['DataFile'] is not None: continue
366                 if __k == 'Algorithm':
367                     __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
368                 elif __k == 'DataFile':
369                     __k = 'Vector'
370                     __f = 'DataFile'
371                     __v = "'"+repr(__v)+"'"
372                     for __lk in ['Vector','VectorSerie']:
373                         if __lk in __local and __local[__lk]: __k = __lk
374                     __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
375                     __text += "%s_config['From'] = '%s'\n"%(__command,__f)
376                     __text += "%s_config['Data'] = %s\n"%(__command,__v)
377                     __text = __text.replace("''","'")
378                 elif __k == 'Script':
379                     __k = 'Vector'
380                     __f = 'Script'
381                     __v = "'"+repr(__v)+"'"
382                     for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
383                         if __lk in __local and __local[__lk]: __k = __lk
384                     if __command == "AlgorithmParameters": __k = "Dict"
385                     if 'OneFunction' in __local and __local['OneFunction']:
386                         __text += "%s_ScriptWithOneFunction = {}\n"%(__command,)
387                         __text += "%s_ScriptWithOneFunction['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
388                         __text += "%s_ScriptWithOneFunction['Script'] = {}\n"%(__command,)
389                         __text += "%s_ScriptWithOneFunction['Script']['Direct'] = %s\n"%(__command,__v)
390                         __text += "%s_ScriptWithOneFunction['Script']['Tangent'] = %s\n"%(__command,__v)
391                         __text += "%s_ScriptWithOneFunction['Script']['Adjoint'] = %s\n"%(__command,__v)
392                         __text += "%s_ScriptWithOneFunction['DifferentialIncrement'] = 1e-06\n"%(__command,)
393                         __text += "%s_ScriptWithOneFunction['CenteredFiniteDifference'] = 0\n"%(__command,)
394                         __k = 'Function'
395                         __f = 'ScriptWithOneFunction'
396                         __v = '%s_ScriptWithOneFunction'%(__command,)
397                     if 'ThreeFunctions' in __local and __local['ThreeFunctions']:
398                         __text += "%s_ScriptWithFunctions = {}\n"%(__command,)
399                         __text += "%s_ScriptWithFunctions['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
400                         __text += "%s_ScriptWithFunctions['Script'] = {}\n"%(__command,)
401                         __text += "%s_ScriptWithFunctions['Script']['Direct'] = %s\n"%(__command,__v)
402                         __text += "%s_ScriptWithFunctions['Script']['Tangent'] = %s\n"%(__command,__v)
403                         __text += "%s_ScriptWithFunctions['Script']['Adjoint'] = %s\n"%(__command,__v)
404                         __k = 'Function'
405                         __f = 'ScriptWithFunctions'
406                         __v = '%s_ScriptWithFunctions'%(__command,)
407                     __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
408                     __text += "%s_config['From'] = '%s'\n"%(__command,__f)
409                     __text += "%s_config['Data'] = %s\n"%(__command,__v)
410                     __text = __text.replace("''","'")
411                 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
412                     if bool(__v):
413                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
414                 elif __k in ('AvoidRC', 'noDetails'):
415                     if not bool(__v):
416                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
417                 else:
418                     if __k == 'Parameters': __k = "Dict"
419                     if isinstance(__v,Persistence.Persistence): __v = __v.values()
420                     if callable(__v): __text = self._missing%__v.__name__+__text
421                     if isinstance(__v,dict):
422                         for val in __v.values():
423                             if callable(val): __text = self._missing%val.__name__+__text
424                     __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
425                     __text += "%s_config['From'] = '%s'\n"%(__command,'String')
426                     __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
427             __text += "study_config['%s'] = %s_config"%(__command,__command)
428             numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
429             if __switchoff:
430                 self._switchoff = True
431         if __text is not None: self._addLine(__text)
432         if not __switchoff:
433             self._switchoff = False
434     def _finalize(self, *__args):
435         self.__loadVariablesByScript()
436         self._addLine("#")
437         self._addLine("Analysis_config = {}")
438         self._addLine("Analysis_config['From'] = 'String'")
439         self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
440         self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
441         self._addLine("print('Analysis:',xa)\"\"\"")
442         self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
443     def __loadVariablesByScript(self):
444         __ExecVariables = {} # Necessaire pour recuperer la variable
445         exec("\n".join(self._lineSerie), __ExecVariables)
446         study_config = __ExecVariables['study_config']
447         # Pour Python 3 : self.__hasAlgorithm = bool(study_config['Algorithm'])
448         if 'Algorithm' in study_config:
449             self.__hasAlgorithm = True
450         else:
451             self.__hasAlgorithm = False
452         if not self.__hasAlgorithm and \
453                 "AlgorithmParameters" in study_config and \
454                 isinstance(study_config['AlgorithmParameters'], dict) and \
455                 "From" in study_config['AlgorithmParameters'] and \
456                 "Data" in study_config['AlgorithmParameters'] and \
457                 study_config['AlgorithmParameters']['From'] == 'Script':
458             __asScript = study_config['AlgorithmParameters']['Data']
459             __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
460             __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
461             self._addLine(__text)
462         if self.__hasAlgorithm and \
463                 "AlgorithmParameters" in study_config and \
464                 isinstance(study_config['AlgorithmParameters'], dict) and \
465                 "From" not in study_config['AlgorithmParameters'] and \
466                 "Data" not in study_config['AlgorithmParameters']:
467             __text  = "#\n"
468             __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
469             __text += "AlgorithmParameters_config['From'] = 'String'\n"
470             __text += "AlgorithmParameters_config['Data'] = '{}'\n"
471             self._addLine(__text)
472         del study_config
473
474 class _YACSViewer(GenericCaseViewer):
475     """
476     Etablissement des commandes d'un cas YACS (Cas->SCD->YACS)
477     """
478     def __init__(self, __name="", __objname="case", __content=None, __object=None):
479         "Initialisation et enregistrement de l'entete"
480         GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
481         self.__internalSCD = _SCDViewer(__name, __objname, __content, __object)
482         self._append       = self.__internalSCD._append
483     def dump(self, __filename=None, __upa=None):
484         "Restitution normalisée des commandes"
485         # -----
486         if __filename is None:
487             raise ValueError("A file name has to be given for YACS XML output.")
488         else:
489             __file    = os.path.abspath(__filename)
490             if os.path.isfile(__file) or os.path.islink(__file):
491                 os.remove(__file)
492         # -----
493         if not PlatformInfo.has_salome or \
494             not PlatformInfo.has_adao:
495             raise ImportError(
496                 "Unable to get SALOME or ADAO environnement variables for YACS conversion.\n"+\
497                 "Please load the right environnement before trying to use it.")
498         else:
499             from daYacsSchemaCreator.run import create_schema_from_content
500         # -----
501         self.__internalSCD._finalize(__upa)
502         __SCDdump = self.__internalSCD.dump()
503         create_schema_from_content(__SCDdump, __file)
504         # -----
505         if not os.path.exists(__file):
506             __msg  = "An error occured during the ADAO YACS Schema build for\n"
507             __msg += "the target output file:\n"
508             __msg += "  %s\n"%__file
509             __msg += "See errors details in your launching terminal log.\n"
510             raise ValueError(__msg)
511         # -----
512         __fid = open(__file,"r")
513         __text = __fid.read()
514         __fid.close()
515         return __text
516
517 # ==============================================================================
518 class ImportFromScript(object):
519     """
520     Obtention d'une variable nommee depuis un fichier script importé
521     """
522     __slots__ = ("__basename", "__filenspace", "__filestring")
523     def __init__(self, __filename=None):
524         "Verifie l'existence et importe le script"
525         if __filename is None:
526             raise ValueError("The name of the file, containing the variable to be read, has to be specified.")
527         if not os.path.isfile(__filename):
528             raise ValueError("The file containing the variable to be imported doesn't seem to exist. Please check the file. The given file name is:\n  \"%s\""%str(__filename))
529         if os.path.dirname(__filename) != '':
530             sys.path.insert(0, os.path.dirname(__filename))
531             __basename = os.path.basename(__filename).rstrip(".py")
532         else:
533             __basename = __filename.rstrip(".py")
534         PlatformInfo.checkFileNameImportability( __basename+".py" )
535         self.__basename = __basename
536         self.__filenspace = __import__(__basename, globals(), locals(), [])
537         self.__filestring = open(__filename,'r').read()
538     def getvalue(self, __varname=None, __synonym=None ):
539         "Renvoie la variable demandee par son nom ou son synonyme"
540         if __varname is None:
541             raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
542         if not hasattr(self.__filenspace, __varname):
543             if __synonym is None:
544                 raise ValueError("The imported script file \"%s\" doesn't contain the mandatory variable \"%s\" to be read. Please check the content of the file and the syntax."%(str(self.__basename)+".py",__varname))
545             elif not hasattr(self.__filenspace, __synonym):
546                 raise ValueError("The imported script file \"%s\" doesn't contain the mandatory variable \"%s\" to be read. Please check the content of the file and the syntax."%(str(self.__basename)+".py",__synonym))
547             else:
548                 return getattr(self.__filenspace, __synonym)
549         else:
550             return getattr(self.__filenspace, __varname)
551     def getstring(self):
552         "Renvoie le script complet"
553         return self.__filestring
554
555 # ==============================================================================
556 class ImportDetector(object):
557     """
558     Détection des caractéristiques de fichiers ou objets en entrée
559     """
560     __slots__ = (
561         "__url", "__usr", "__root", "__end")
562     def __enter__(self): return self
563     def __exit__(self, exc_type, exc_val, exc_tb): return False
564     #
565     def __init__(self, __url, UserMime=""):
566         if __url is None:
567             raise ValueError("The name or url of the file object has to be specified.")
568         if __url is bytes:
569             self.__url = __url.decode()
570         else:
571             self.__url = str(__url)
572         if UserMime is bytes:
573             self.__usr = UserMime.decode().lower()
574         else:
575             self.__usr = str(UserMime).lower()
576         (self.__root, self.__end) = os.path.splitext(self.__url)
577         #
578         mimetypes.add_type('application/numpy.npy', '.npy')
579         mimetypes.add_type('application/numpy.npz', '.npz')
580         mimetypes.add_type('application/dymola.sdf', '.sdf')
581         if sys.platform.startswith("win"):
582             mimetypes.add_type('text/plain', '.txt')
583             mimetypes.add_type('text/csv', '.csv')
584             mimetypes.add_type('text/tab-separated-values', '.tsv')
585     #
586     # File related tests
587     # ------------------
588     def is_local_file(self):
589         if os.path.isfile(os.path.realpath(self.__url)):
590             return True
591         else:
592             return False
593     def is_not_local_file(self):
594         if not os.path.isfile(os.path.realpath(self.__url)):
595             return True
596         else:
597             return False
598     def raise_error_if_not_local_file(self):
599         if not os.path.isfile(os.path.realpath(self.__url)):
600             raise ValueError("The name or the url of the file object doesn't seem to exist. The given name is:\n  \"%s\""%str(self.__url))
601         else:
602             return False
603     #
604     # Directory related tests
605     # -----------------------
606     def is_local_dir(self):
607         if os.path.isdir(self.__url):
608             return True
609         else:
610             return False
611     def is_not_local_dir(self):
612         if not os.path.isdir(self.__url):
613             return True
614         else:
615             return False
616     def raise_error_if_not_local_dir(self):
617         if not os.path.isdir(self.__url):
618             raise ValueError("The name or the url of the directory object doesn't seem to exist. The given name is:\n  \"%s\""%str(self.__url))
619         else:
620             return False
621     #
622     # Mime related functions
623     # ------------------------
624     def get_standard_mime(self):
625         (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
626         return __mtype
627     def get_user_mime(self):
628         __fake = "fake."+self.__usr.lower()
629         (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
630         return __mtype
631     def get_comprehensive_mime(self):
632         if self.get_standard_mime() is not None:
633             return self.get_standard_mime()
634         elif self.get_user_mime() is not None:
635             return self.get_user_mime()
636         else:
637             return None
638     #
639     # Name related functions
640     # ----------------------
641     def get_user_name(self):
642         return self.__url
643     def get_absolute_name(self):
644         return os.path.abspath(os.path.realpath(self.__url))
645     def get_extension(self):
646         return self.__end
647
648 # ==============================================================================
649 class ImportFromFile(object):
650     """
651     Obtention de variables disrétisées en 1D, définies par une ou des variables
652     nommées, et sous la forme d'une série de points éventuellement indexés. La
653     lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
654     fonctions depuis :
655         - des fichiers textes en colonnes de type TXT, CSV, TSV...
656         - des fichiers de données binaires NPY, NPZ, SDF...
657     La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
658     performance tout en disposant de l'interprétation du contenu. Les fichiers
659     textes doivent présenter en première ligne (hors commentaire ou ligne vide)
660     les noms des variables de colonnes. Les commentaires commencent par un "#".
661     """
662     __slots__ = (
663         "_filename", "_colnames", "_colindex", "_varsline", "_format",
664         "_delimiter", "_skiprows", "__url", "__filestring", "__header",
665         "__allowvoid", "__binaryformats", "__supportedformats")
666     def __enter__(self): return self
667     def __exit__(self, exc_type, exc_val, exc_tb): return False
668     #
669     def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
670         """
671         Verifie l'existence et les informations de définition du fichier. Les
672         noms de colonnes ou de variables sont ignorées si le format ne permet
673         pas de les indiquer.
674         Arguments :
675             - Filename : nom du fichier
676             - ColNames : noms de la ou des colonnes/variables à lire
677             - ColIndex : nom unique de la colonne/variable servant d'index
678             - Format : format du fichier et/ou des données inclues
679             - AllowVoidNameList : permet, si la liste de noms est vide, de
680               prendre par défaut toutes les colonnes
681         """
682         self.__binaryformats =(
683             "application/numpy.npy",
684             "application/numpy.npz",
685             "application/dymola.sdf",
686             )
687         self.__url = ImportDetector( Filename, Format)
688         self.__url.raise_error_if_not_local_file()
689         self._filename = self.__url.get_absolute_name()
690         PlatformInfo.checkFileNameConformity( self._filename )
691         #
692         self._format = self.__url.get_comprehensive_mime()
693         #
694         self.__header, self._varsline, self._skiprows = self.__getentete()
695         #
696         if self._format == "text/csv" or Format.upper() == "CSV":
697             self._format = "text/csv"
698             self.__filestring = "".join(self.__header)
699             if self.__filestring.count(",") > 1:
700                 self._delimiter = ","
701             elif self.__filestring.count(";") > 1:
702                 self._delimiter = ";"
703             else:
704                 self._delimiter = None
705         elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
706             self._format = "text/tab-separated-values"
707             self._delimiter = "\t"
708         else:
709             self._delimiter = None
710         #
711         if ColNames is not None: self._colnames = tuple(ColNames)
712         else:                    self._colnames = None
713         #
714         if ColIndex is not None: self._colindex = str(ColIndex)
715         else:                    self._colindex = None
716         #
717         self.__allowvoid = bool(AllowVoidNameList)
718
719     def __getentete(self, __nblines = 3):
720         "Lit l'entête du fichier pour trouver la définition des variables"
721         # La première ligne non vide non commentée est toujours considérée
722         # porter les labels de colonne, donc pas des valeurs
723         __header, __varsline, __skiprows = [], "", 1
724         if self._format in self.__binaryformats:
725             pass
726         else:
727             with open(self._filename,'r') as fid:
728                 __line = fid.readline().strip()
729                 while "#" in __line or len(__line) < 1:
730                     __header.append(__line)
731                     __skiprows += 1
732                     __line = fid.readline().strip()
733                 __varsline = __line
734                 for i in range(max(0,__nblines)):
735                     __header.append(fid.readline())
736         return (__header, __varsline, __skiprows)
737
738     def __getindices(self, __colnames, __colindex, __delimiter=None ):
739         "Indices de colonnes correspondants à l'index et aux variables"
740         if __delimiter is None:
741             __varserie = self._varsline.strip('#').strip().split()
742         else:
743             __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
744         #
745         if __colnames is not None:
746             __usecols = []
747             __colnames = tuple(__colnames)
748             for v in __colnames:
749                 for i, n in enumerate(__varserie):
750                     if v == n: __usecols.append(i)
751             __usecols = tuple(__usecols)
752             if len(__usecols) == 0:
753                 if self.__allowvoid:
754                     __usecols = None
755                 else:
756                     raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
757         else:
758             __usecols = None
759         #
760         if __colindex is not None:
761             __useindex = None
762             __colindex = str(__colindex)
763             for i, n in enumerate(__varserie):
764                 if __colindex == n: __useindex = i
765         else:
766             __useindex = None
767         #
768         return (__usecols, __useindex)
769
770     def getsupported(self):
771         self.__supportedformats = {}
772         self.__supportedformats["text/plain"]                = True
773         self.__supportedformats["text/csv"]                  = True
774         self.__supportedformats["text/tab-separated-values"] = True
775         self.__supportedformats["application/numpy.npy"]     = True
776         self.__supportedformats["application/numpy.npz"]     = True
777         self.__supportedformats["application/dymola.sdf"]    = PlatformInfo.has_sdf
778         return self.__supportedformats
779
780     def getvalue(self, ColNames=None, ColIndex=None ):
781         "Renvoie la ou les variables demandees par la liste de leurs noms"
782         # Uniquement si mise à jour
783         if ColNames is not None: self._colnames = tuple(ColNames)
784         if ColIndex is not None: self._colindex = str(ColIndex)
785         #
786         __index = None
787         if self._format == "application/numpy.npy":
788             __columns = numpy.load(self._filename)
789         #
790         elif self._format == "application/numpy.npz":
791             __columns = None
792             with numpy.load(self._filename) as __allcolumns:
793                 if self._colnames is None:
794                     self._colnames = __allcolumns.files
795                 for nom in self._colnames: # Si une variable demandée n'existe pas
796                     if nom not in __allcolumns.files:
797                         self._colnames = tuple( __allcolumns.files )
798                 for nom in self._colnames:
799                     if nom in __allcolumns.files:
800                         if __columns is not None:
801                             # Attention : toutes les variables doivent avoir la même taille
802                             __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
803                         else:
804                             # Première colonne
805                             __columns = numpy.reshape(__allcolumns[nom], (1,-1))
806                 if self._colindex is not None and self._colindex in __allcolumns.files:
807                     __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
808         elif self._format == "text/plain":
809             __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
810             __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
811             if __useindex is not None:
812                 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
813             if __usecols is None: # Si une variable demandée n'existe pas
814                 self._colnames = None
815         #
816         elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
817             import sdf
818             __content = sdf.load(self._filename)
819             __columns = None
820             if self._colnames is None:
821                 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
822             for nom in self._colnames:
823                 if nom in __content:
824                     if __columns is not None:
825                         # Attention : toutes les variables doivent avoir la même taille
826                         __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
827                     else:
828                         # Première colonne
829                         __columns = numpy.reshape(__content[nom].data, (1,-1))
830             if self._colindex is not None and self._colindex in __content:
831                 __index = __content[self._colindex].data
832         #
833         elif self._format == "text/csv":
834             __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
835             __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
836             if __useindex is not None:
837                 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
838             if __usecols is None: # Si une variable demandée n'existe pas
839                 self._colnames = None
840         #
841         elif self._format == "text/tab-separated-values":
842             __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
843             __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
844             if __useindex is not None:
845                 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
846             if __usecols is None: # Si une variable demandée n'existe pas
847                 self._colnames = None
848         else:
849             raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
850         if __columns is None: __columns = ()
851         #
852         def toString(value):
853             try:
854                 return value.decode()
855             except ValueError:
856                 return value
857         if __index is not None:
858             __index = tuple([toString(v) for v in __index])
859         #
860         return (self._colnames, __columns, self._colindex, __index)
861
862     def getstring(self):
863         "Renvoie le fichier texte complet"
864         if self._format in self.__binaryformats:
865             return ""
866         else:
867             with open(self._filename,'r') as fid:
868                 return fid.read()
869
870     def getformat(self):
871         return self._format
872
873 # ==============================================================================
874 class ImportScalarLinesFromFile(ImportFromFile):
875     """
876     Importation de fichier contenant des variables scalaires nommées. Le
877     fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
878     "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
879     est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
880     None si nécessaire pour une borne).
881
882     Seule la méthode "getvalue" est changée.
883     """
884     def __enter__(self): return self
885     def __exit__(self, exc_type, exc_val, exc_tb): return False
886     #
887     def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
888         ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
889         if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
890             raise ValueError("Unkown file format \"%s\""%self._format)
891     #
892     def getvalue(self, VarNames = None, HeaderNames=()):
893         "Renvoie la ou les variables demandees par la liste de leurs noms"
894         if VarNames is not None: __varnames = tuple(VarNames)
895         else:                    __varnames = None
896         #
897         if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
898             __ftype = "NamValMinMax"
899             __dtypes   = {'names'  : ('Name', 'Value', 'Minimum', 'Maximum'),
900                           'formats': ('S128', 'g', 'g', 'g')}
901             __usecols  = (0, 1, 2, 3)
902             def __replaceNoneN( s ):
903                 if s.strip() == b'None': return numpy.NINF
904                 else:                    return s
905             def __replaceNoneP( s ):
906                 if s.strip() == b'None': return numpy.PINF
907                 else:                    return s
908             __converters = {2: __replaceNoneN, 3: __replaceNoneP}
909         elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
910             __ftype = "NamVal"
911             __dtypes   = {'names'  : ('Name', 'Value'),
912                           'formats': ('S128', 'g')}
913             __converters = None
914             __usecols  = (0, 1)
915         elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
916             __ftype = "NamLotOfVals"
917             __dtypes   = {'names'  : HeaderNames,
918                           'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
919             __usecols  = tuple(range(len(HeaderNames)))
920             def __replaceNone( s ):
921                 if s.strip() == b'None': return numpy.NAN
922                 else:                    return s
923             __converters = dict()
924             for i in range(1,len(HeaderNames)):
925                 __converters[i] = __replaceNone
926         else:
927             raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n            \"%s\""%__firstline)
928         #
929         if self._format == "text/plain":
930             __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
931         elif self._format in ["text/csv", "text/tab-separated-values"]:
932             __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
933         else:
934             raise ValueError("Unkown file format \"%s\""%self._format)
935         #
936         __names, __thevalue, __bounds = [], [], []
937         for sub in __content:
938             if len(__usecols) == 4:
939                 na, va, mi, ma = sub
940                 if numpy.isneginf(mi): mi = None # Réattribue les variables None
941                 elif numpy.isnan(mi):  mi = None # Réattribue les variables None
942                 if numpy.isposinf(ma): ma = None # Réattribue les variables None
943                 elif numpy.isnan(ma):  ma = None # Réattribue les variables None
944             elif len(__usecols) == 2 and __ftype == "NamVal":
945                 na, va = sub
946                 mi, ma = None, None
947             else:
948                 nsub = list(sub)
949                 na = sub[0]
950                 for i, v in enumerate(nsub[1:]):
951                     if numpy.isnan(v): nsub[i+1] = None
952                 va = nsub[1:]
953                 mi, ma = None, None
954             na = na.decode()
955             if (__varnames is None or na in __varnames) and (na not in __names):
956                 # Ne stocke que la premiere occurence d'une variable
957                 __names.append(na)
958                 __thevalue.append(va)
959                 __bounds.append((mi,ma))
960         #
961         __names      = tuple(__names)
962         __thevalue = numpy.array(__thevalue)
963         __bounds     = tuple(__bounds)
964         #
965         return (__names, __thevalue, __bounds)
966
967 # ==============================================================================
968 if __name__ == "__main__":
969     print('\n AUTODIAGNOSTIC\n')