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