1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008-2019 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 == "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)
138 self._addLine(__text)
139 def _extract(self, __multilines="", __object=None):
140 "Transformation un enregistrement en une commande individuelle"
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()
148 logging.debug("TUI Extracting commands of '%s' object..."%(self._objname,))
152 if self._objname+".set" in line:
153 __commands.append( line.replace(self._objname+".","",1) )
154 logging.debug("TUI Extracted command: %s"%(__commands[-1],))
157 class _COMViewer(GenericCaseViewer):
159 Etablissement des commandes d'un cas COMM (Eficas Native Format/Cas<-COM)
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")
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(",),);", ",),)")
181 for line in __multilines.split("\n"):
182 if len(line) < 1: continue
183 __fulllines += line + "\n"
184 __multilines = __fulllines
185 self._objname = "case"
187 exec("self._objdata = "+__multilines)
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,))
194 __UserPostAnalysis = ""
195 for k,r in self._objdata.items():
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),) )
203 elif __command == "UserPostAnalysis" and type(r) is dict:
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:
210 __UserPostAnalysis = r['ValueTemplate']
212 __UserPostAnalysis = ""
213 __UserPostAnalysis = __UserPostAnalysis.replace("ADD",self._objname)
215 elif __command == "AlgorithmParameters" and type(r) is dict and 'Algorithm' in r:
216 if 'data' in r and r['Parameters'] == 'Dict':
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'])
230 __parameters = ', Parameters=%s'%(repr(__Dict),)
233 __commands.append( "set( Concept='AlgorithmParameters', Algorithm='%s'%s )"%(r['Algorithm'],__parameters) )
235 elif __command == "Observers" and type(r) is dict and 'SELECTION' in r:
236 if type(r['SELECTION']) is str:
237 __selection = (r['SELECTION'],)
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'],)
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) )
253 # Background, ObservationError, ObservationOperator...
254 elif type(r) is dict:
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']
262 if 'FROM' in __idata:
263 # String, Script, DataFile, Template, ScriptWithOneFunction, ScriptWithFunctions
264 __ifrom = __idata['FROM']
265 __idata.pop('FROM','')
266 if __ifrom == 'String' or __ifrom == 'Template':
267 __argumentsList.append([__itype,__idata['STRING']])
268 if __ifrom == 'Script':
269 __argumentsList.append([__itype,True])
270 __argumentsList.append(['Script',__idata['SCRIPT_FILE']])
271 if __ifrom == 'DataFile':
272 __argumentsList.append([__itype,True])
273 __argumentsList.append(['DataFile',__idata['DATA_FILE']])
274 if __ifrom == 'ScriptWithOneFunction':
275 __argumentsList.append(['OneFunction',True])
276 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHONEFUNCTION_FILE')])
278 __argumentsList.append(['Parameters',__idata])
279 if __ifrom == 'ScriptWithFunctions':
280 __argumentsList.append(['ThreeFunctions',True])
281 __argumentsList.append(['Script',__idata.pop('SCRIPTWITHFUNCTIONS_FILE')])
283 __argumentsList.append(['Parameters',__idata])
284 __arguments = ["%s = %s"%(k,repr(v)) for k,v in __argumentsList]
285 __commands.append( "set( Concept='%s', %s )"%(__command, ", ".join(__arguments)))
287 # ----------------------------------------------------------------------
288 __commands.sort() # Pour commencer par 'AlgorithmParameters'
289 __commands.append(__UserPostAnalysis)
292 class _SCDViewer(GenericCaseViewer):
294 Etablissement des commandes d'un cas SCD (Study Config Dictionary/Cas->SCD)
296 def __init__(self, __name="", __objname="case", __content=None, __object=None):
297 "Initialisation et enregistrement de l'entete"
298 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
299 self._addLine("# -*- coding: utf-8 -*-")
300 self._addLine("#\n# Input for ADAO converter to YACS\n#")
301 self._addLine("from numpy import array, matrix")
303 self._addLine("study_config = {}")
304 self._addLine("study_config['StudyType'] = 'ASSIMILATION_STUDY'")
305 self._addLine("study_config['Name'] = '%s'"%self._name)
306 self._addLine("observers = {}")
307 self._addLine("study_config['Observers'] = observers")
309 self._addLine("inputvariables_config = {}")
310 self._addLine("inputvariables_config['Order'] =['adao_default']")
311 self._addLine("inputvariables_config['adao_default'] = -1")
312 self._addLine("study_config['InputVariables'] = inputvariables_config")
314 self._addLine("outputvariables_config = {}")
315 self._addLine("outputvariables_config['Order'] = ['adao_default']")
316 self._addLine("outputvariables_config['adao_default'] = -1")
317 self._addLine("study_config['OutputVariables'] = outputvariables_config")
318 if __content is not None:
319 for command in __content:
320 self._append(*command)
321 def _append(self, __command=None, __keys=None, __local=None, __pre=None, __switchoff=False):
322 "Transformation d'une commande individuelle en un enregistrement"
323 if __command == "set": __command = __local["Concept"]
324 else: __command = __command.replace("set", "", 1)
327 if __command in (None, 'execute', 'executePythonScheme', 'executeYACSScheme', 'get', 'Name'):
329 elif __command in ['Debug', 'setDebug']:
330 __text = "#\nstudy_config['Debug'] = '1'"
331 elif __command in ['NoDebug', 'setNoDebug']:
332 __text = "#\nstudy_config['Debug'] = '0'"
333 elif __command in ['Observer', 'setObserver']:
334 __obs = __local['Variable']
335 self._numobservers += 1
337 __text += "observers['%s'] = {}\n"%__obs
338 if __local['String'] is not None:
339 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
340 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, __local['String'])
341 if __local['Script'] is not None:
342 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'Script')
343 __text += "observers['%s']['Script'] = \"%s\"\n"%(__obs, __local['Script'])
344 if __local['Template'] is not None and __local['Template'] in Templates.ObserverTemplates:
345 __text += "observers['%s']['nodetype'] = '%s'\n"%(__obs, 'String')
346 __text += "observers['%s']['String'] = \"\"\"%s\"\"\"\n"%(__obs, Templates.ObserverTemplates[__local['Template']])
347 if __local['Info'] is not None:
348 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __local['Info'])
350 __text += "observers['%s']['info'] = \"\"\"%s\"\"\"\n"%(__obs, __obs)
351 __text += "observers['%s']['number'] = %s"%(__obs, self._numobservers)
352 elif __local is not None: # __keys is not None and
353 numpy.set_printoptions(precision=15,threshold=1000000,linewidth=1000*15)
355 __text += "%s_config = {}\n"%__command
356 __local.pop('self','')
358 for __k,__v in __local.items():
359 if __v is None: __to_be_removed.append(__k)
360 for __k in __to_be_removed:
362 for __k,__v in __local.items():
363 if __k == "Concept": continue
364 if __k in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix','OneFunction','ThreeFunctions'] and 'Script' in __local and __local['Script'] is not None: continue
365 if __k in ['Vector','VectorSerie'] and 'DataFile' in __local and __local['DataFile'] is not None: continue
366 if __k == 'Algorithm':
367 __text += "study_config['Algorithm'] = %s\n"%(repr(__v))
368 elif __k == 'DataFile':
371 __v = "'"+repr(__v)+"'"
372 for __lk in ['Vector','VectorSerie']:
373 if __lk in __local and __local[__lk]: __k = __lk
374 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
375 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
376 __text += "%s_config['Data'] = %s\n"%(__command,__v)
377 __text = __text.replace("''","'")
378 elif __k == 'Script':
381 __v = "'"+repr(__v)+"'"
382 for __lk in ['ScalarSparseMatrix','DiagonalSparseMatrix','Matrix']:
383 if __lk in __local and __local[__lk]: __k = __lk
384 if __command == "AlgorithmParameters": __k = "Dict"
385 if 'OneFunction' in __local and __local['OneFunction']:
386 __text += "%s_ScriptWithOneFunction = {}\n"%(__command,)
387 __text += "%s_ScriptWithOneFunction['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
388 __text += "%s_ScriptWithOneFunction['Script'] = {}\n"%(__command,)
389 __text += "%s_ScriptWithOneFunction['Script']['Direct'] = %s\n"%(__command,__v)
390 __text += "%s_ScriptWithOneFunction['Script']['Tangent'] = %s\n"%(__command,__v)
391 __text += "%s_ScriptWithOneFunction['Script']['Adjoint'] = %s\n"%(__command,__v)
392 __text += "%s_ScriptWithOneFunction['DifferentialIncrement'] = 1e-06\n"%(__command,)
393 __text += "%s_ScriptWithOneFunction['CenteredFiniteDifference'] = 0\n"%(__command,)
395 __f = 'ScriptWithOneFunction'
396 __v = '%s_ScriptWithOneFunction'%(__command,)
397 if 'ThreeFunctions' in __local and __local['ThreeFunctions']:
398 __text += "%s_ScriptWithFunctions = {}\n"%(__command,)
399 __text += "%s_ScriptWithFunctions['Function'] = ['Direct', 'Tangent', 'Adjoint']\n"%(__command,)
400 __text += "%s_ScriptWithFunctions['Script'] = {}\n"%(__command,)
401 __text += "%s_ScriptWithFunctions['Script']['Direct'] = %s\n"%(__command,__v)
402 __text += "%s_ScriptWithFunctions['Script']['Tangent'] = %s\n"%(__command,__v)
403 __text += "%s_ScriptWithFunctions['Script']['Adjoint'] = %s\n"%(__command,__v)
405 __f = 'ScriptWithFunctions'
406 __v = '%s_ScriptWithFunctions'%(__command,)
407 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
408 __text += "%s_config['From'] = '%s'\n"%(__command,__f)
409 __text += "%s_config['Data'] = %s\n"%(__command,__v)
410 __text = __text.replace("''","'")
411 elif __k in ('Stored', 'Checked', 'ColMajor', 'InputFunctionAsMulti', 'nextStep'):
413 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
414 elif __k in ('AvoidRC', 'noDetails'):
416 __text += "%s_config['%s'] = '%s'\n"%(__command,__k,int(bool(__v)))
418 if __k == 'Parameters': __k = "Dict"
419 if isinstance(__v,Persistence.Persistence): __v = __v.values()
420 if callable(__v): __text = self._missing%__v.__name__+__text
421 if isinstance(__v,dict):
422 for val in __v.values():
423 if callable(val): __text = self._missing%val.__name__+__text
424 __text += "%s_config['Type'] = '%s'\n"%(__command,__k)
425 __text += "%s_config['From'] = '%s'\n"%(__command,'String')
426 __text += "%s_config['Data'] = \"\"\"%s\"\"\"\n"%(__command,repr(__v))
427 __text += "study_config['%s'] = %s_config"%(__command,__command)
428 numpy.set_printoptions(precision=8,threshold=1000,linewidth=75)
430 self._switchoff = True
431 if __text is not None: self._addLine(__text)
433 self._switchoff = False
434 def _finalize(self, *__args):
435 self.__loadVariablesByScript()
437 self._addLine("Analysis_config = {}")
438 self._addLine("Analysis_config['From'] = 'String'")
439 self._addLine("Analysis_config['Data'] = \"\"\"import numpy")
440 self._addLine("xa=numpy.ravel(ADD.get('Analysis')[-1])")
441 self._addLine("print('Analysis:',xa)\"\"\"")
442 self._addLine("study_config['UserPostAnalysis'] = Analysis_config")
443 def __loadVariablesByScript(self):
444 __ExecVariables = {} # Necessaire pour recuperer la variable
445 exec("\n".join(self._lineSerie), __ExecVariables)
446 study_config = __ExecVariables['study_config']
447 # Pour Python 3 : self.__hasAlgorithm = bool(study_config['Algorithm'])
448 if 'Algorithm' in study_config:
449 self.__hasAlgorithm = True
451 self.__hasAlgorithm = False
452 if not self.__hasAlgorithm and \
453 "AlgorithmParameters" in study_config and \
454 isinstance(study_config['AlgorithmParameters'], dict) and \
455 "From" in study_config['AlgorithmParameters'] and \
456 "Data" in study_config['AlgorithmParameters'] and \
457 study_config['AlgorithmParameters']['From'] == 'Script':
458 __asScript = study_config['AlgorithmParameters']['Data']
459 __var = ImportFromScript(__asScript).getvalue( "Algorithm" )
460 __text = "#\nstudy_config['Algorithm'] = '%s'"%(__var,)
461 self._addLine(__text)
462 if self.__hasAlgorithm and \
463 "AlgorithmParameters" in study_config and \
464 isinstance(study_config['AlgorithmParameters'], dict) and \
465 "From" not in study_config['AlgorithmParameters'] and \
466 "Data" not in study_config['AlgorithmParameters']:
468 __text += "AlgorithmParameters_config['Type'] = 'Dict'\n"
469 __text += "AlgorithmParameters_config['From'] = 'String'\n"
470 __text += "AlgorithmParameters_config['Data'] = '{}'\n"
471 self._addLine(__text)
474 class _YACSViewer(GenericCaseViewer):
476 Etablissement des commandes d'un cas YACS (Cas->SCD->YACS)
478 def __init__(self, __name="", __objname="case", __content=None, __object=None):
479 "Initialisation et enregistrement de l'entete"
480 GenericCaseViewer.__init__(self, __name, __objname, __content, __object)
481 self.__internalSCD = _SCDViewer(__name, __objname, __content, __object)
482 self._append = self.__internalSCD._append
483 def dump(self, __filename=None, __upa=None):
484 "Restitution normalisée des commandes"
486 if __filename is None:
487 raise ValueError("A file name has to be given for YACS XML output.")
489 __file = os.path.abspath(__filename)
490 if os.path.isfile(__file) or os.path.islink(__file):
493 if not PlatformInfo.has_salome or \
494 not PlatformInfo.has_adao:
496 "Unable to get SALOME or ADAO environnement variables for YACS conversion.\n"+\
497 "Please load the right environnement before trying to use it.")
499 from daYacsSchemaCreator.run import create_schema_from_content
501 self.__internalSCD._finalize(__upa)
502 __SCDdump = self.__internalSCD.dump()
503 create_schema_from_content(__SCDdump, __file)
505 if not os.path.exists(__file):
506 __msg = "An error occured during the ADAO YACS Schema build for\n"
507 __msg += "the target output file:\n"
508 __msg += " %s\n"%__file
509 __msg += "See errors details in your launching terminal log.\n"
510 raise ValueError(__msg)
512 __fid = open(__file,"r")
513 __text = __fid.read()
517 # ==============================================================================
518 class ImportFromScript(object):
520 Obtention d'une variable nommee depuis un fichier script importé
522 __slots__ = ("__basename", "__filenspace", "__filestring")
523 def __init__(self, __filename=None):
524 "Verifie l'existence et importe le script"
525 if __filename is None:
526 raise ValueError("The name of the file, containing the variable to be read, has to be specified.")
527 if not os.path.isfile(__filename):
528 raise ValueError("The file containing the variable to be imported doesn't seem to exist. Please check the file. The given file name is:\n \"%s\""%str(__filename))
529 if os.path.dirname(__filename) != '':
530 sys.path.insert(0, os.path.dirname(__filename))
531 __basename = os.path.basename(__filename).rstrip(".py")
533 __basename = __filename.rstrip(".py")
534 PlatformInfo.checkFileNameImportability( __basename+".py" )
535 self.__basename = __basename
536 self.__filenspace = __import__(__basename, globals(), locals(), [])
537 self.__filestring = open(__filename,'r').read()
538 def getvalue(self, __varname=None, __synonym=None ):
539 "Renvoie la variable demandee par son nom ou son synonyme"
540 if __varname is None:
541 raise ValueError("The name of the variable to be read has to be specified. Please check the content of the file and the syntax.")
542 if not hasattr(self.__filenspace, __varname):
543 if __synonym is None:
544 raise ValueError("The imported script file \"%s\" doesn't contain the mandatory variable \"%s\" to be read. Please check the content of the file and the syntax."%(str(self.__basename)+".py",__varname))
545 elif not hasattr(self.__filenspace, __synonym):
546 raise ValueError("The imported script file \"%s\" doesn't contain the mandatory variable \"%s\" to be read. Please check the content of the file and the syntax."%(str(self.__basename)+".py",__synonym))
548 return getattr(self.__filenspace, __synonym)
550 return getattr(self.__filenspace, __varname)
552 "Renvoie le script complet"
553 return self.__filestring
555 # ==============================================================================
556 class ImportDetector(object):
558 Détection des caractéristiques de fichiers ou objets en entrée
561 "__url", "__usr", "__root", "__end")
562 def __enter__(self): return self
563 def __exit__(self, exc_type, exc_val, exc_tb): return False
565 def __init__(self, __url, UserMime=""):
567 raise ValueError("The name or url of the file object has to be specified.")
569 self.__url = __url.decode()
571 self.__url = str(__url)
572 if UserMime is bytes:
573 self.__usr = UserMime.decode().lower()
575 self.__usr = str(UserMime).lower()
576 (self.__root, self.__end) = os.path.splitext(self.__url)
578 mimetypes.add_type('application/numpy.npy', '.npy')
579 mimetypes.add_type('application/numpy.npz', '.npz')
580 mimetypes.add_type('application/dymola.sdf', '.sdf')
581 if sys.platform.startswith("win"):
582 mimetypes.add_type('text/plain', '.txt')
583 mimetypes.add_type('text/csv', '.csv')
584 mimetypes.add_type('text/tab-separated-values', '.tsv')
588 def is_local_file(self):
589 if os.path.isfile(os.path.realpath(self.__url)):
593 def is_not_local_file(self):
594 if not os.path.isfile(os.path.realpath(self.__url)):
598 def raise_error_if_not_local_file(self):
599 if not os.path.isfile(os.path.realpath(self.__url)):
600 raise ValueError("The name or the url of the file object doesn't seem to exist. The given name is:\n \"%s\""%str(self.__url))
604 # Directory related tests
605 # -----------------------
606 def is_local_dir(self):
607 if os.path.isdir(self.__url):
611 def is_not_local_dir(self):
612 if not os.path.isdir(self.__url):
616 def raise_error_if_not_local_dir(self):
617 if not os.path.isdir(self.__url):
618 raise ValueError("The name or the url of the directory object doesn't seem to exist. The given name is:\n \"%s\""%str(self.__url))
622 # Mime related functions
623 # ------------------------
624 def get_standard_mime(self):
625 (__mtype, __encoding) = mimetypes.guess_type(self.__url, strict=False)
627 def get_user_mime(self):
628 __fake = "fake."+self.__usr.lower()
629 (__mtype, __encoding) = mimetypes.guess_type(__fake, strict=False)
631 def get_comprehensive_mime(self):
632 if self.get_standard_mime() is not None:
633 return self.get_standard_mime()
634 elif self.get_user_mime() is not None:
635 return self.get_user_mime()
639 # Name related functions
640 # ----------------------
641 def get_user_name(self):
643 def get_absolute_name(self):
644 return os.path.abspath(os.path.realpath(self.__url))
645 def get_extension(self):
648 # ==============================================================================
649 class ImportFromFile(object):
651 Obtention de variables disrétisées en 1D, définies par une ou des variables
652 nommées, et sous la forme d'une série de points éventuellement indexés. La
653 lecture d'un fichier au format spécifié (ou intuité) permet de charger ces
655 - des fichiers textes en colonnes de type TXT, CSV, TSV...
656 - des fichiers de données binaires NPY, NPZ, SDF...
657 La lecture du fichier complet ne se fait que si nécessaire, pour assurer la
658 performance tout en disposant de l'interprétation du contenu. Les fichiers
659 textes doivent présenter en première ligne (hors commentaire ou ligne vide)
660 les noms des variables de colonnes. Les commentaires commencent par un "#".
663 "_filename", "_colnames", "_colindex", "_varsline", "_format",
664 "_delimiter", "_skiprows", "__url", "__filestring", "__header",
665 "__allowvoid", "__binaryformats", "__supportedformats")
666 def __enter__(self): return self
667 def __exit__(self, exc_type, exc_val, exc_tb): return False
669 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess", AllowVoidNameList=True):
671 Verifie l'existence et les informations de définition du fichier. Les
672 noms de colonnes ou de variables sont ignorées si le format ne permet
675 - Filename : nom du fichier
676 - ColNames : noms de la ou des colonnes/variables à lire
677 - ColIndex : nom unique de la colonne/variable servant d'index
678 - Format : format du fichier et/ou des données inclues
679 - AllowVoidNameList : permet, si la liste de noms est vide, de
680 prendre par défaut toutes les colonnes
682 self.__binaryformats =(
683 "application/numpy.npy",
684 "application/numpy.npz",
685 "application/dymola.sdf",
687 self.__url = ImportDetector( Filename, Format)
688 self.__url.raise_error_if_not_local_file()
689 self._filename = self.__url.get_absolute_name()
690 PlatformInfo.checkFileNameConformity( self._filename )
692 self._format = self.__url.get_comprehensive_mime()
694 self.__header, self._varsline, self._skiprows = self.__getentete()
696 if self._format == "text/csv" or Format.upper() == "CSV":
697 self._format = "text/csv"
698 self.__filestring = "".join(self.__header)
699 if self.__filestring.count(",") > 1:
700 self._delimiter = ","
701 elif self.__filestring.count(";") > 1:
702 self._delimiter = ";"
704 self._delimiter = None
705 elif self._format == "text/tab-separated-values" or Format.upper() == "TSV":
706 self._format = "text/tab-separated-values"
707 self._delimiter = "\t"
709 self._delimiter = None
711 if ColNames is not None: self._colnames = tuple(ColNames)
712 else: self._colnames = None
714 if ColIndex is not None: self._colindex = str(ColIndex)
715 else: self._colindex = None
717 self.__allowvoid = bool(AllowVoidNameList)
719 def __getentete(self, __nblines = 3):
720 "Lit l'entête du fichier pour trouver la définition des variables"
721 # La première ligne non vide non commentée est toujours considérée
722 # porter les labels de colonne, donc pas des valeurs
723 __header, __varsline, __skiprows = [], "", 1
724 if self._format in self.__binaryformats:
727 with open(self._filename,'r') as fid:
728 __line = fid.readline().strip()
729 while "#" in __line or len(__line) < 1:
730 __header.append(__line)
732 __line = fid.readline().strip()
734 for i in range(max(0,__nblines)):
735 __header.append(fid.readline())
736 return (__header, __varsline, __skiprows)
738 def __getindices(self, __colnames, __colindex, __delimiter=None ):
739 "Indices de colonnes correspondants à l'index et aux variables"
740 if __delimiter is None:
741 __varserie = self._varsline.strip('#').strip().split()
743 __varserie = self._varsline.strip('#').strip().split(str(__delimiter))
745 if __colnames is not None:
747 __colnames = tuple(__colnames)
749 for i, n in enumerate(__varserie):
750 if v == n: __usecols.append(i)
751 __usecols = tuple(__usecols)
752 if len(__usecols) == 0:
756 raise ValueError("Can not found any column corresponding to the required names %s"%(__colnames,))
760 if __colindex is not None:
762 __colindex = str(__colindex)
763 for i, n in enumerate(__varserie):
764 if __colindex == n: __useindex = i
768 return (__usecols, __useindex)
770 def getsupported(self):
771 self.__supportedformats = {}
772 self.__supportedformats["text/plain"] = True
773 self.__supportedformats["text/csv"] = True
774 self.__supportedformats["text/tab-separated-values"] = True
775 self.__supportedformats["application/numpy.npy"] = True
776 self.__supportedformats["application/numpy.npz"] = True
777 self.__supportedformats["application/dymola.sdf"] = PlatformInfo.has_sdf
778 return self.__supportedformats
780 def getvalue(self, ColNames=None, ColIndex=None ):
781 "Renvoie la ou les variables demandees par la liste de leurs noms"
782 # Uniquement si mise à jour
783 if ColNames is not None: self._colnames = tuple(ColNames)
784 if ColIndex is not None: self._colindex = str(ColIndex)
787 if self._format == "application/numpy.npy":
788 __columns = numpy.load(self._filename)
790 elif self._format == "application/numpy.npz":
792 with numpy.load(self._filename) as __allcolumns:
793 if self._colnames is None:
794 self._colnames = __allcolumns.files
795 for nom in self._colnames: # Si une variable demandée n'existe pas
796 if nom not in __allcolumns.files:
797 self._colnames = tuple( __allcolumns.files )
798 for nom in self._colnames:
799 if nom in __allcolumns.files:
800 if __columns is not None:
801 # Attention : toutes les variables doivent avoir la même taille
802 __columns = numpy.vstack((__columns, numpy.reshape(__allcolumns[nom], (1,-1))))
805 __columns = numpy.reshape(__allcolumns[nom], (1,-1))
806 if self._colindex is not None and self._colindex in __allcolumns.files:
807 __index = numpy.array(numpy.reshape(__allcolumns[self._colindex], (1,-1)), dtype=bytes)
808 elif self._format == "text/plain":
809 __usecols, __useindex = self.__getindices(self._colnames, self._colindex)
810 __columns = numpy.loadtxt(self._filename, usecols = __usecols, skiprows=self._skiprows)
811 if __useindex is not None:
812 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), skiprows=self._skiprows)
813 if __usecols is None: # Si une variable demandée n'existe pas
814 self._colnames = None
816 elif self._format == "application/dymola.sdf" and PlatformInfo.has_sdf:
818 __content = sdf.load(self._filename)
820 if self._colnames is None:
821 self._colnames = [__content.datasets[i].name for i in range(len(__content.datasets))]
822 for nom in self._colnames:
824 if __columns is not None:
825 # Attention : toutes les variables doivent avoir la même taille
826 __columns = numpy.vstack((__columns, numpy.reshape(__content[nom].data, (1,-1))))
829 __columns = numpy.reshape(__content[nom].data, (1,-1))
830 if self._colindex is not None and self._colindex in __content:
831 __index = __content[self._colindex].data
833 elif self._format == "text/csv":
834 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
835 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
836 if __useindex is not None:
837 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
838 if __usecols is None: # Si une variable demandée n'existe pas
839 self._colnames = None
841 elif self._format == "text/tab-separated-values":
842 __usecols, __useindex = self.__getindices(self._colnames, self._colindex, self._delimiter)
843 __columns = numpy.loadtxt(self._filename, usecols = __usecols, delimiter = self._delimiter, skiprows=self._skiprows)
844 if __useindex is not None:
845 __index = numpy.loadtxt(self._filename, dtype = bytes, usecols = (__useindex,), delimiter = self._delimiter, skiprows=self._skiprows)
846 if __usecols is None: # Si une variable demandée n'existe pas
847 self._colnames = None
849 raise ValueError("Unkown file format \"%s\" or no reader available"%self._format)
850 if __columns is None: __columns = ()
854 return value.decode()
857 if __index is not None:
858 __index = tuple([toString(v) for v in __index])
860 return (self._colnames, __columns, self._colindex, __index)
863 "Renvoie le fichier texte complet"
864 if self._format in self.__binaryformats:
867 with open(self._filename,'r') as fid:
873 # ==============================================================================
874 class ImportScalarLinesFromFile(ImportFromFile):
876 Importation de fichier contenant des variables scalaires nommées. Le
877 fichier comporte soit 2, soit 4 colonnes, obligatoirement nommées "Name",
878 "Value", "Minimum", "Maximum" si les noms sont précisés. Sur chaque ligne
879 est indiqué le nom, la valeur, et éventuelement deux bornes min et max (ou
880 None si nécessaire pour une borne).
882 Seule la méthode "getvalue" est changée.
884 def __enter__(self): return self
885 def __exit__(self, exc_type, exc_val, exc_tb): return False
887 def __init__(self, Filename=None, ColNames=None, ColIndex=None, Format="Guess"):
888 ImportFromFile.__init__(self, Filename, ColNames, ColIndex, Format)
889 if self._format not in ["text/plain", "text/csv", "text/tab-separated-values"]:
890 raise ValueError("Unkown file format \"%s\""%self._format)
892 def getvalue(self, VarNames = None, HeaderNames=()):
893 "Renvoie la ou les variables demandees par la liste de leurs noms"
894 if VarNames is not None: __varnames = tuple(VarNames)
895 else: __varnames = None
897 if "Name" in self._varsline and "Value" in self._varsline and "Minimum" in self._varsline and "Maximum" in self._varsline:
898 __ftype = "NamValMinMax"
899 __dtypes = {'names' : ('Name', 'Value', 'Minimum', 'Maximum'),
900 'formats': ('S128', 'g', 'g', 'g')}
901 __usecols = (0, 1, 2, 3)
902 def __replaceNoneN( s ):
903 if s.strip() == b'None': return numpy.NINF
905 def __replaceNoneP( s ):
906 if s.strip() == b'None': return numpy.PINF
908 __converters = {2: __replaceNoneN, 3: __replaceNoneP}
909 elif "Name" in self._varsline and "Value" in self._varsline and ("Minimum" not in self._varsline or "Maximum" not in self._varsline):
911 __dtypes = {'names' : ('Name', 'Value'),
912 'formats': ('S128', 'g')}
915 elif len(HeaderNames)>0 and numpy.all([kw in self._varsline for kw in HeaderNames]):
916 __ftype = "NamLotOfVals"
917 __dtypes = {'names' : HeaderNames,
918 'formats': tuple(['S128',]+['g']*(len(HeaderNames)-1))}
919 __usecols = tuple(range(len(HeaderNames)))
920 def __replaceNone( s ):
921 if s.strip() == b'None': return numpy.NAN
923 __converters = dict()
924 for i in range(1,len(HeaderNames)):
925 __converters[i] = __replaceNone
927 raise ValueError("Can not find names of columns for initial values. Wrong first line is:\n \"%s\""%__firstline)
929 if self._format == "text/plain":
930 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters)
931 elif self._format in ["text/csv", "text/tab-separated-values"]:
932 __content = numpy.loadtxt(self._filename, dtype = __dtypes, usecols = __usecols, skiprows = self._skiprows, converters = __converters, delimiter = self._delimiter)
934 raise ValueError("Unkown file format \"%s\""%self._format)
936 __names, __thevalue, __bounds = [], [], []
937 for sub in __content:
938 if len(__usecols) == 4:
940 if numpy.isneginf(mi): mi = None # Réattribue les variables None
941 elif numpy.isnan(mi): mi = None # Réattribue les variables None
942 if numpy.isposinf(ma): ma = None # Réattribue les variables None
943 elif numpy.isnan(ma): ma = None # Réattribue les variables None
944 elif len(__usecols) == 2 and __ftype == "NamVal":
950 for i, v in enumerate(nsub[1:]):
951 if numpy.isnan(v): nsub[i+1] = None
955 if (__varnames is None or na in __varnames) and (na not in __names):
956 # Ne stocke que la premiere occurence d'une variable
958 __thevalue.append(va)
959 __bounds.append((mi,ma))
961 __names = tuple(__names)
962 __thevalue = numpy.array(__thevalue)
963 __bounds = tuple(__bounds)
965 return (__names, __thevalue, __bounds)
967 # ==============================================================================
968 if __name__ == "__main__":
969 print('\n AUTODIAGNOSTIC\n')