Salome HOME
e7313469823b1865499b06c9fb0b47561d648154
[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, 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 == 'ScriptWithOneFunction':
272                             __argumentsList.append(['OneFunction',True])
273                             __argumentsList.append(['Script',__idata.pop('SCRIPTWITHONEFUNCTION_FILE')])
274                             if len(__idata)>0:
275                                 __argumentsList.append(['Parameters',__idata])
276                         if __ifrom == 'ScriptWithFunctions':
277                             __argumentsList.append(['ThreeFunctions',True])
278                             __argumentsList.append(['Script',__idata.pop('SCRIPTWITHFUNCTIONS_FILE')])
279                             if len(__idata)>0:
280                                 __argumentsList.append(['Parameters',__idata])
281                 __arguments = ["%s = %s"%(k,repr(v)) for k,v in __argumentsList]
282                 __commands.append( "set( Concept='%s', %s )"%(__command, ", ".join(__arguments)))
283         #
284         # ----------------------------------------------------------------------
285         __commands.sort() # Pour commencer par 'AlgorithmParameters'
286         __commands.append(__UserPostAnalysis)
287         return __commands
288
289 class _SCDViewer(GenericCaseViewer):
290     """
291     Etablissement des commandes d'un cas SCD (Study Config Dictionary/Cas->SCD)
292     """
293     def __init__(self, __name="", __objname="case", __content=None, __object=None):
294         "Initialisation et enregistrement de l'entete"
295         GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
296         self._addLine("# -*- coding: utf-8 -*-")
297         self._addLine("#\n# Input for ADAO converter to YACS\n#")
298         self._addLine("from numpy import array, matrix")
299         self._addLine("#")
300         self._addLine("study_config = {}")
301         self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'")
302         self._addLine("study_config['Name'] = '%s'"%self._name)
303         self._addLine("observers = {}")
304         self._addLine("study_config['Observers'] = observers")
305         self._addLine("#")
306         self._addLine("inputvariables_config = {}")
307         self._addLine("inputvariables_config['Order'] =['adao_default']")
308         self._addLine("inputvariables_config['adao_default'] = -1")
309         self._addLine("study_config['InputVariables'] = inputvariables_config")
310         self._addLine("#")
311         self._addLine("outputvariables_config = {}")
312         self._addLine("outputvariables_config['Order'] = ['adao_default']")
313         self._addLine("outputvariables_config['adao_default'] = -1")
314         self._addLine("study_config['OutputVariables'] = outputvariables_config")
315         if __content is not None:
316             for command in __content:
317                 self._append(*command)
318     def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
319         "Transformation d'une commande individuelle en un enregistrement"
320         if __command == "set": __command = __local["Concept"]
321         else:                  __command = __command.replace("set", "", 1)
322         #
323         __text  = None
324         if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get', 'Name'):
325             return
326         elif __command in ['Debug', 'setDebug']:
327             __text  = "#\nstudy_config['Debug'] = '1'"
328         elif __command in ['NoDebug', 'setNoDebug']:
329             __text  = "#\nstudy_config['Debug'] = '0'"
330         elif __command in ['Observer', 'setObserver']:
331             __obs   = __local['Variable']
332             self._numobservers += 1
333             __text  = "#\n"
334             __text += "observers['%s'] = {}\n"%__obs
335             if __local['String'] is not None:
336                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
337                 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
338             if __local['Script'] is not None:
339                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
340                 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
341             if __local['Template'] is not None and __local['Template'] in Templates.ObserverTemplates:
342                 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
343                 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, Templates.ObserverTemplates[__local['Template']])
344             if __local['Info'] is not None:
345                 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
346             else:
347                 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
348             __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
349         elif __local is not None: # __keys is not None and
350             numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
351             __text  = "#\n"
352             __text += "%s_config = {}\n"%__command
353             __local.pop('self','')
354             __to_be_removed = []
355             for __k,__v in __local.items():
356                 if __v is None: __to_be_removed.append(__k)
357             for __k in __to_be_removed:
358                 __local.pop(__k)
359             for __k,__v in __local.items():
360                 if __k == "Concept": continue
361                 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix','OneFunction','ThreeFunctions'] and 'Script' in __local: continue
362                 if __k == 'Algorithm':
363                     __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
364                 elif __k == 'Script':
365                     __k = 'Vector'
366                     __f = 'Script'
367                     __v = "'"+repr(__v)+"'"
368                     for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
369                         if __lk in __local and __local[__lk]: __k = __lk
370                     if __command == "AlgorithmParameters": __k = "Dict"
371                     if 'OneFunction' in __local and __local['OneFunction']:
372                         __text += "%s_ScriptWithOneFunction = {}\n"%(__command,)
373                         __text += "%s_ScriptWithOneFunction['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
374                         __text += "%s_ScriptWithOneFunction['Script'] = {}\n"%(__command,)
375                         __text += "%s_ScriptWithOneFunction['Script']['Direct'] = %s\n"%(__command,__v)
376                         __text += "%s_ScriptWithOneFunction['Script']['Tangent'] = %s\n"%(__command,__v)
377                         __text += "%s_ScriptWithOneFunction['Script']['Adjoint'] = %s\n"%(__command,__v)
378                         __text += "%s_ScriptWithOneFunction['DifferentialIncrement'] = 1e-06\n"%(__command,)
379                         __text += "%s_ScriptWithOneFunction['CenteredFiniteDifference'] = 0\n"%(__command,)
380                         __k = 'Function'
381                         __f = 'ScriptWithOneFunction'
382                         __v = '%s_ScriptWithOneFunction'%(__command,)
383                     if 'ThreeFunctions' in __local and __local['ThreeFunctions']:
384                         __text += "%s_ScriptWithFunctions = {}\n"%(__command,)
385                         __text += "%s_ScriptWithFunctions['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
386                         __text += "%s_ScriptWithFunctions['Script'] = {}\n"%(__command,)
387                         __text += "%s_ScriptWithFunctions['Script']['Direct'] = %s\n"%(__command,__v)
388                         __text += "%s_ScriptWithFunctions['Script']['Tangent'] = %s\n"%(__command,__v)
389                         __text += "%s_ScriptWithFunctions['Script']['Adjoint'] = %s\n"%(__command,__v)
390                         __k = 'Function'
391                         __f = 'ScriptWithFunctions'
392                         __v = '%s_ScriptWithFunctions'%(__command,)
393                     __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
394                     __text += "%s_config['From'] = '%s'\n"%(__command,__f)
395                     __text += "%s_config['Data'] = %s\n"%(__command,__v)
396                     __text = __text.replace("''","'")
397                 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
398                     if bool(__v):
399                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
400                 elif __k in ('AvoidRC', 'noDetails'):
401                     if not bool(__v):
402                         __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
403                 else:
404                     if __k == 'Parameters': __k = "Dict"
405                     if isinstance(__v,Persistence.Persistence): __v = __v.values()
406                     if callable(__v): __text = self._missing%__v.__name__+__text
407                     if isinstance(__v,dict):
408                         for val in __v.values():
409                             if callable(val): __text = self._missing%val.__name__+__text
410                     __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
411                     __text += "%s_config['From'] = '%s'\n"%(__command,'String')
412                     __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
413             __text += "study_config['%s'] = %s_config"%(__command,__command)
414             numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
415             if __switchoff:
416                 self._switchoff = True
417         if __text is not None: self._addLine(__text)
418         if not __switchoff:
419             self._switchoff = False
420     def _finalize(self, *__args):
421         self.__loadVariablesByScript()
422         self._addLine("#")
423         self._addLine("Analysis_config = {}")
424         self._addLine("Analysis_config['From'] = 'String'")
425         self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
426         self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
427         self._addLine("print('Analysis:',xa)\"\"\"")
428         self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
429     def __loadVariablesByScript(self):
430         __ExecVariables = {} # Necessaire pour recuperer la variable
431         exec("\n".join(self._lineSerie), __ExecVariables)
432         study_config = __ExecVariables['study_config']
433         # Pour Python 3 : self.__hasAlgorithm = bool(study_config['Algorithm'])
434         if 'Algorithm' in study_config:
435             self.__hasAlgorithm = True
436         else:
437             self.__hasAlgorithm = False
438         if not self.__hasAlgorithm and \
439                 "AlgorithmParameters" in study_config and \
440                 isinstance(study_config['AlgorithmParameters'], dict) and \
441                 "From" in study_config['AlgorithmParameters'] and \
442                 "Data" in study_config['AlgorithmParameters'] and \
443                 study_config['AlgorithmParameters']['From'] == 'Script':
444             __asScript = study_config['AlgorithmParameters']['Data']
445             __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
446             __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
447             self._addLine(__text)
448         if self.__hasAlgorithm and \
449                 "AlgorithmParameters" in study_config and \
450                 isinstance(study_config['AlgorithmParameters'], dict) and \
451                 "From" not in study_config['AlgorithmParameters'] and \
452                 "Data" not in study_config['AlgorithmParameters']:
453             __text  = "#\n"
454             __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
455             __text += "AlgorithmParameters_config['From'] = 'String'\n"
456             __text += "AlgorithmParameters_config['Data'] = '{}'\n"
457             self._addLine(__text)
458         del study_config
459
460 class _YACSViewer(GenericCaseViewer):
461     """
462     Etablissement des commandes d'un cas YACS (Cas->SCD->YACS)
463     """
464     def __init__(self, __name="", __objname="case", __content=None, __object=None):
465         "Initialisation et enregistrement de l'entete"
466         GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
467         self.__internalSCD = _SCDViewer(__name, __objname, __content, __object)
468         self._append       = self.__internalSCD._append
469     def dump(self, __filename=None, __upa=None):
470         "Restitution normalisée des commandes"
471         # -----
472         if __filename is None:
473             raise ValueError("A file name has to be given for YACS XML output.")
474         else:
475             __file    = os.path.abspath(__filename)
476             if os.path.isfile(__file) or os.path.islink(__file):
477                 os.remove(__file)
478         # -----
479         if not PlatformInfo.has_salome or \
480             not PlatformInfo.has_adao:
481             raise ImportError(
482                 "Unable to get SALOME or ADAO environnement variables for YACS conversion.\n"+\
483                 "Please load the right environnement before trying to use it.")
484         else:
485             from daYacsSchemaCreator.run import create_schema_from_content
486         # -----
487         self.__internalSCD._finalize(__upa)
488         __SCDdump = self.__internalSCD.dump()
489         create_schema_from_content(__SCDdump, __file)
490         # -----
491         if not os.path.exists(__file):
492             __msg  = "An error occured during the ADAO YACS Schema build for\n"
493             __msg += "the target output file:\n"
494             __msg += "  %s\n"%__file
495             __msg += "See errors details in your launching terminal log.\n"
496             raise ValueError(__msg)
497         # -----
498         __fid = open(__file,"r")
499         __text = __fid.read()
500         __fid.close()
501         return __text
502
503 # ==============================================================================
504 class ImportFromScript(object):
505     """
506     Obtention d'une variable nommee depuis un fichier script importé
507     """
508     __slots__ = ("__basename", "__filenspace", "__filestring")
509     def __init__(self, __filename=None):
510         "Verifie l'existence et importe le script"
511         if __filename is None:
512             raise ValueError("The name of the file, containing the variable to be read, has to be specified.")
513         if not os.path.isfile(__filename):
514             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))
515         if os.path.dirname(__filename) != '':
516             sys.path.insert(0, os.path.dirname(__filename))
517             __basename = os.path.basename(__filename).rstrip(".py")
518         else:
519             __basename = __filename.rstrip(".py")
520         PlatformInfo.checkFileNameImportability( __basename+".py" )
521         self.__basename = __basename
522         self.__filenspace = __import__(__basename, globals(), locals(), [])
523         self.__filestring = open(__filename,'r').read()
524     def getvalue(self, __varname=None, __synonym=None ):
525         "Renvoie la variable demandee par son nom ou son synonyme"
526         if __varname is None:
527             raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
528         if not hasattr(self.__filenspace, __varname):
529             if __synonym is None:
530                 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))
531             elif not hasattr(self.__filenspace, __synonym):
532                 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))
533             else:
534                 return getattr(self.__filenspace, __synonym)
535         else:
536             return getattr(self.__filenspace, __varname)
537     def getstring(self):
538         "Renvoie le script complet"
539         return self.__filestring
540
541 # ==============================================================================
542 class ImportDetector(object):
543     """
544     Détection des caractéristiques de fichiers ou objets en entrée
545     """
546     __slots__ = (
547         "__url", "__usr", "__root", "__end")
548     def __enter__(self): return self
549     def __exit__(self, exc_type, exc_val, exc_tb): return False
550     #
551     def __init__(self, __url, UserMime=""):
552         if __url is None:
553             raise ValueError("The name or url of the file object has to be specified.")
554         if __url is bytes:
555             self.__url = __url.decode()
556         else:
557             self.__url = str(__url)
558         if UserMime is bytes:
559             self.__usr = UserMime.decode().lower()
560         else:
561             self.__usr = str(UserMime).lower()
562         (self.__root, self.__end) = os.path.splitext(self.__url)
563         #
564         mimetypes.add_type('application/numpy.npy', '.npy')
565         mimetypes.add_type('application/numpy.npz', '.npz')
566         mimetypes.add_type('application/dymola.sdf', '.sdf')
567         if sys.platform.startswith("win"):
568             mimetypes.add_type('text/plain', '.txt')
569             mimetypes.add_type('text/csv', '.csv')
570             mimetypes.add_type('text/tab-separated-values', '.tsv')
571     #
572     # File related tests
573     # ------------------
574     def is_local_file(self):
575         if os.path.isfile(os.path.realpath(self.__url)):
576             return True
577         else:
578             return False
579     def is_not_local_file(self):
580         if not os.path.isfile(os.path.realpath(self.__url)):
581             return True
582         else:
583             return False
584     def raise_error_if_not_local_file(self):
585         if not os.path.isfile(os.path.realpath(self.__url)):
586             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))
587         else:
588             return False
589     #
590     # Directory related tests
591     # -----------------------
592     def is_local_dir(self):
593         if os.path.isdir(self.__url):
594             return True
595         else:
596             return False
597     def is_not_local_dir(self):
598         if not os.path.isdir(self.__url):
599             return True
600         else:
601             return False
602     def raise_error_if_not_local_dir(self):
603         if not os.path.isdir(self.__url):
604             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))
605         else:
606             return False
607     #
608     # Mime related functions
609     # ------------------------
610     def get_standard_mime(self):
611         (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
612         return __mtype
613     def get_user_mime(self):
614         __fake = "fake."+self.__usr.lower()
615         (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
616         return __mtype
617     def get_comprehensive_mime(self):
618         if self.get_standard_mime() is not None:
619             return self.get_standard_mime()
620         elif self.get_user_mime() is not None:
621             return self.get_user_mime()
622         else:
623             return None
624     #
625     # Name related functions
626     # ----------------------
627     def get_user_name(self):
628         return self.__url
629     def get_absolute_name(self):
630         return os.path.abspath(os.path.realpath(self.__url))
631     def get_extension(self):
632         return self.__end
633
634 # ==============================================================================
635 class ImportFromFile(object):
636     """
637     Obtention de variables disrétisées en 1D, définies par une ou des variables
638     nommées, et sous la forme d'une série de points éventuellement indexés. La
639     lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
640     fonctions depuis :
641         - des fichiers textes en colonnes de type TXT, CSV, TSV...
642         - des fichiers de données binaires NPY, NPZ, SDF...
643     La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
644     performance tout en disposant de l'interprétation du contenu. Les fichiers
645     textes doivent présenter en première ligne (hors commentaire ou ligne vide)
646     les noms des variables de colonnes. Les commentaires commencent par un "#".
647     """
648     __slots__ = (
649         "_filename", "_colnames", "_colindex", "_varsline", "_format",
650         "_delimiter", "_skiprows", "__url", "__filestring", "__header",
651         "__allowvoid", "__binaryformats", "__supportedformats")
652     def __enter__(self): return self
653     def __exit__(self, exc_type, exc_val, exc_tb): return False
654     #
655     def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
656         """
657         Verifie l'existence et les informations de définition du fichier. Les
658         noms de colonnes ou de variables sont ignorées si le format ne permet
659         pas de les indiquer.
660         Arguments :
661             - Filename : nom du fichier
662             - ColNames : noms de la ou des colonnes/variables à lire
663             - ColIndex : nom unique de la colonne/variable servant d'index
664             - Format : format du fichier et/ou des données inclues
665             - AllowVoidNameList : permet, si la liste de noms est vide, de
666               prendre par défaut toutes les colonnes
667         """
668         self.__binaryformats =(
669             "application/numpy.npy",
670             "application/numpy.npz",
671             "application/dymola.sdf",
672             )
673         self.__url = ImportDetector( Filename, Format)
674         self.__url.raise_error_if_not_local_file()
675         self._filename = self.__url.get_absolute_name()
676         PlatformInfo.checkFileNameConformity( self._filename )
677         #
678         self._format = self.__url.get_comprehensive_mime()
679         #
680         self.__header, self._varsline, self._skiprows = self.__getentete()
681         #
682         if self._format == "text/csv" or Format.upper() == "CSV":
683             self._format = "text/csv"
684             self.__filestring = "".join(self.__header)
685             if self.__filestring.count(",") > 1:
686                 self._delimiter = ","
687             elif self.__filestring.count(";") > 1:
688                 self._delimiter = ";"
689         elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
690             self._format = "text/tab-separated-values"
691             self._delimiter = "\t"
692         else:
693             self._delimiter = None
694         #
695         if ColNames is not None: self._colnames = tuple(ColNames)
696         else:                    self._colnames = None
697         #
698         if ColIndex is not None: self._colindex = str(ColIndex)
699         else:                    self._colindex = None
700         #
701         self.__allowvoid = bool(AllowVoidNameList)
702
703     def __getentete(self, __nblines = 3):
704         "Lit l'entête du fichier pour trouver la définition des variables"
705         __header, __varsline, __skiprows = [], "", 1
706         if self._format in self.__binaryformats:
707             pass
708         else:
709             with open(self._filename,'r') as fid:
710                 __line = fid.readline().strip()
711                 while "#" in __line or len(__line) < 1:
712                     __header.append(__line)
713                     __skiprows += 1
714                     __line = fid.readline().strip()
715                 __varsline = __line # Première ligne non commentée non vide
716                 for i in range(max(0,__nblines)):
717                     __header.append(fid.readline())
718         return (__header, __varsline, __skiprows)
719
720     def __getindices(self, __colnames, __colindex, __delimiter=None ):
721         "Indices de colonnes correspondants à l'index et aux variables"
722         if __delimiter is None:
723             __varserie = self._varsline.strip('#').strip().split()
724         else:
725             __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
726         #
727         if __colnames is not None:
728             __usecols = []
729             __colnames = tuple(__colnames)
730             for v in __colnames:
731                 for i, n in enumerate(__varserie):
732                     if v == n: __usecols.append(i)
733             __usecols = tuple(__usecols)
734             if len(__usecols) == 0:
735                 if self.__allowvoid:
736                     __usecols = None
737                 else:
738                     raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
739         else:
740             __usecols = None
741         #
742         if __colindex is not None:
743             __useindex = None
744             __colindex = str(__colindex)
745             for i, n in enumerate(__varserie):
746                 if __colindex == n: __useindex = i
747         else:
748             __useindex = None
749         #
750         return (__usecols, __useindex)
751
752     def getsupported(self):
753         self.__supportedformats = {}
754         self.__supportedformats["text/plain"]                = True
755         self.__supportedformats["text/csv"]                  = True
756         self.__supportedformats["text/tab-separated-values"] = True
757         self.__supportedformats["application/numpy.npy"]     = True
758         self.__supportedformats["application/numpy.npz"]     = True
759         self.__supportedformats["application/dymola.sdf"]    = PlatformInfo.has_sdf
760         return self.__supportedformats
761
762     def getvalue(self, ColNames=None, ColIndex=None ):
763         "Renvoie la ou les variables demandees par la liste de leurs noms"
764         # Uniquement si mise à jour
765         if ColNames is not None: self._colnames = tuple(ColNames)
766         if ColIndex is not None: self._colindex = str(ColIndex)
767         #
768         __index = None
769         if self._format == "application/numpy.npy":
770             __columns = numpy.load(self._filename)
771         #
772         elif self._format == "application/numpy.npz":
773             __columns = None
774             with numpy.load(self._filename) as __allcolumns:
775                 if self._colnames is None:
776                     self._colnames = __allcolumns.files
777                 for nom in self._colnames:
778                     if nom in __allcolumns.files:
779                         if __columns is not None:
780                             # Attention : toutes les variables doivent avoir la même taille
781                             __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
782                         else:
783                             # Première colonne
784                             __columns = numpy.reshape(__allcolumns[nom], (1,-1))
785                 if self._colindex is not None and self._colindex in __allcolumns.files:
786                     __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
787         elif self._format == "text/plain":
788             __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
789             __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
790             if __useindex is not None:
791                 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
792         #
793         elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
794             import sdf
795             __content = sdf.load(self._filename)
796             __columns = None
797             if self._colnames is None:
798                 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
799             for nom in self._colnames:
800                 if nom in __content:
801                     if __columns is not None:
802                         # Attention : toutes les variables doivent avoir la même taille
803                         __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
804                     else:
805                         # Première colonne
806                         __columns = numpy.reshape(__content[nom].data, (1,-1))
807             if self._colindex is not None and self._colindex in __content:
808                 __index = __content[self._colindex].data
809         #
810         elif self._format == "text/csv":
811             __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
812             __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
813             if __useindex is not None:
814                 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
815         #
816         elif self._format == "text/tab-separated-values":
817             __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
818             __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
819             if __useindex is not None:
820                 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
821         else:
822             raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
823         if __columns is None: __columns = ()
824         #
825         def toString(value):
826             try:
827                 return value.decode()
828             except ValueError:
829                 return value
830         if __index is not None:
831             __index = tuple([toString(v) for v in __index])
832         #
833         return (self._colnames, __columns, self._colindex, __index)
834
835     def getstring(self):
836         "Renvoie le fichier texte complet"
837         if self._format in self.__binaryformats:
838             return ""
839         else:
840             with open(self._filename,'r') as fid:
841                 return fid.read()
842
843     def getformat(self):
844         return self._format
845
846 # ==============================================================================
847 class ImportScalarLinesFromFile(ImportFromFile):
848     """
849     Importation de fichier contenant des variables scalaires nommées. Le
850     fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
851     "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
852     est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
853     None si nécessaire pour une borne).
854
855     Seule la méthode "getvalue" est changée.
856     """
857     def __enter__(self): return self
858     def __exit__(self, exc_type, exc_val, exc_tb): return False
859     #
860     def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
861         ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
862         if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
863             raise ValueError("Unkown file format \"%s\""%self._format)
864     #
865     def getvalue(self, VarNames = None, HeaderNames=()):
866         "Renvoie la ou les variables demandees par la liste de leurs noms"
867         if VarNames is not None: __varnames = tuple(VarNames)
868         else:                    __varnames = None
869         #
870         if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
871             __ftype = "NamValMinMax"
872             __dtypes   = {'names'  : ('Name', 'Value', 'Minimum', 'Maximum'),
873                           'formats': ('S128', 'g', 'g', 'g')}
874             __usecols  = (0, 1, 2, 3)
875             def __replaceNoneN( s ):
876                 if s.strip() == b'None': return numpy.NINF
877                 else:                    return s
878             def __replaceNoneP( s ):
879                 if s.strip() == b'None': return numpy.PINF
880                 else:                    return s
881             __converters = {2: __replaceNoneN, 3: __replaceNoneP}
882         elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
883             __ftype = "NamVal"
884             __dtypes   = {'names'  : ('Name', 'Value'),
885                           'formats': ('S128', 'g')}
886             __converters = None
887             __usecols  = (0, 1)
888         elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
889             __ftype = "NamLotOfVals"
890             __dtypes   = {'names'  : HeaderNames,
891                           'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
892             __usecols  = tuple(range(len(HeaderNames)))
893             def __replaceNone( s ):
894                 if s.strip() == b'None': return numpy.NAN
895                 else:                    return s
896             __converters = dict()
897             for i in range(1,len(HeaderNames)):
898                 __converters[i] = __replaceNone
899         else:
900             raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n            \"%s\""%__firstline)
901         #
902         if self._format == "text/plain":
903             __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
904         elif self._format in ["text/csv", "text/tab-separated-values"]:
905             __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
906         else:
907             raise ValueError("Unkown file format \"%s\""%self._format)
908         #
909         __names, __thevalue, __bounds = [], [], []
910         for sub in __content:
911             if len(__usecols) == 4:
912                 na, va, mi, ma = sub
913                 if numpy.isneginf(mi): mi = None # Réattribue les variables None
914                 elif numpy.isnan(mi):  mi = None # Réattribue les variables None
915                 if numpy.isposinf(ma): ma = None # Réattribue les variables None
916                 elif numpy.isnan(ma):  ma = None # Réattribue les variables None
917             elif len(__usecols) == 2 and __ftype == "NamVal":
918                 na, va = sub
919                 mi, ma = None, None
920             else:
921                 nsub = list(sub)
922                 na = sub[0]
923                 for i, v in enumerate(nsub[1:]):
924                     if numpy.isnan(v): nsub[i+1] = None
925                 va = nsub[1:]
926                 mi, ma = None, None
927             na = na.decode()
928             if (__varnames is None or na in __varnames) and (na not in __names):
929                 # Ne stocke que la premiere occurence d'une variable
930                 __names.append(na)
931                 __thevalue.append(va)
932                 __bounds.append((mi,ma))
933         #
934         __names      = tuple(__names)
935         __thevalue = numpy.array(__thevalue)
936         __bounds     = tuple(__bounds)
937         #
938         return (__names, __thevalue, __bounds)
939
940 # ==============================================================================
941 if __name__ == "__main__":
942     print('\n AUTODIAGNOSTIC\n')