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