]> SALOME platform Git repositories - modules/parametric.git/blob - src/PARAMETRIC/PARAMETRIC.py
Salome HOME
Increment version: 7.7.1
[modules/parametric.git] / src / PARAMETRIC / PARAMETRIC.py
1 # Copyright (C) 2012-2015 EDF
2 #
3 # This file is part of SALOME PARAMETRIC module.
4 #
5 # SALOME PARAMETRIC module is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # SALOME PARAMETRIC module 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
13 # GNU Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with SALOME PARAMETRIC module.  If not, see <http://www.gnu.org/licenses/>.
17
18 import logging
19 import threading
20 import inspect
21 import traceback
22 import copy
23 import cPickle
24 import tempfile
25 import os
26
27 import salome
28 import SALOME
29 import SALOME_ModuleCatalog
30 import PARAMETRIC_ORB__POA
31 from SALOME_ComponentPy import SALOME_ComponentPy_i
32 from SALOME_DriverPy import SALOME_DriverPy_i
33 import SALOMERuntime
34 import pilot
35
36 from salome.kernel.studyedit import getStudyEditor
37 from salome.kernel.logger import Logger
38 from salome.kernel import termcolor
39 logger = Logger("PARAMETRIC", color = termcolor.BLUE)
40 logger.setLevel(logging.DEBUG)
41
42 from salome.parametric import PARAM_STUDY_TYPE_ID, ParametricStudy, parse_entry, PARAMETRIC_ENGINE_CONTAINER
43 from salome.parametric.persistence import load_param_study_dict, save_param_study_dict
44
45 # module constants
46 MODULE_NAME = "PARAMETRIC"
47
48 COMPONENT_NAME = "Parametric"
49 COMPONENT_ICON = "PARAMETRIC_small.png"
50
51 PARAM_STUDY_ICON = "param_study.png"
52
53 start_script = """
54 from salome.kernel.parametric.pyscript_utils import \
55     create_input_dict, create_normal_parametric_output, create_error_parametric_output
56
57 try:
58   globals().update(create_input_dict({}, paramInput))
59   
60   ### Start of user code
61   
62 """
63
64 end_script = """  
65   ### End of user code
66
67   output_dict = {}
68   for output_var in paramInput["outputVarList"]:
69     if globals().has_key(output_var):
70       output_dict[output_var] = globals()[output_var]
71     else:
72       raise Exception("User Python script has not created variable %s" % output_var)
73
74   paramOutput = create_normal_parametric_output(output_dict, paramInput)
75
76 except Exception, exc:
77   paramOutput = create_error_parametric_output(str(exc))
78 """
79
80 class PARAMETRIC(PARAMETRIC_ORB__POA.PARAMETRIC_Gen, SALOME_ComponentPy_i, SALOME_DriverPy_i):
81
82   lock = threading.Lock()
83
84   def __init__(self, orb, poa, contID, containerName, instanceName, interfaceName):
85     SALOME_ComponentPy_i.__init__(self, orb, poa, contID, containerName, instanceName, interfaceName, 0)
86     SALOME_DriverPy_i.__init__(self, interfaceName)
87     self.param_comp = {}
88     self.param_study_dict = {}
89     self.salome_runtime = None
90     self.session_catalog = None
91
92   def _raiseSalomeError(self):
93     message = "Error in component %s running in container %s." % (self._instanceName, self._containerName)
94     logger.exception(message)
95     message += " " + traceback.format_exc()
96     exc = SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR, message,
97                                  inspect.stack()[1][1], inspect.stack()[1][2])
98     raise SALOME.SALOME_Exception(exc)
99
100   def _find_or_create_param_component(self, salomeStudyID):
101     """
102     Find the component "Parametric" or create it if none is found
103     :return: the SComponent found or created.
104     """
105     if salomeStudyID not in self.param_comp:
106       ed = getStudyEditor(salomeStudyID)
107       self.param_comp[salomeStudyID] = ed.findOrCreateComponent(MODULE_NAME, COMPONENT_NAME,
108                                                                 COMPONENT_ICON, PARAMETRIC_ENGINE_CONTAINER)
109     return self.param_comp[salomeStudyID]
110
111   def _set_param_study_sobj(self, parametric_study, salomeStudyID, sobj):
112     getStudyEditor(salomeStudyID).setItem(sobj,
113                                           name = parametric_study.name,
114                                           icon = PARAM_STUDY_ICON,
115                                           typeId = PARAM_STUDY_TYPE_ID)
116     if salomeStudyID not in self.param_study_dict:
117       self.param_study_dict[salomeStudyID] = {}
118     entry = sobj.GetID()
119     self.param_study_dict[salomeStudyID][entry] = parametric_study
120
121   def AddParametricStudy(self, parametricStudy, salomeStudyID):
122     try:
123       self.beginService("PARAMETRIC.AddParametricStudy")
124       param_study = cPickle.loads(parametricStudy)
125       param_comp = self._find_or_create_param_component(salomeStudyID)
126       sobj = getStudyEditor(salomeStudyID).createItem(param_comp, "__NEW_STUDY__")
127       self._set_param_study_sobj(param_study, salomeStudyID, sobj)
128       self.endService("PARAMETRIC.AddParametricStudy")
129     except:
130       self._raiseSalomeError()
131
132   def _set_parametric_study(self, param_study, salomeStudyID, entry):
133     sobj = getStudyEditor(salomeStudyID).study.FindObjectID(entry)
134     self._set_param_study_sobj(param_study, salomeStudyID, sobj)
135
136   def SetParametricStudy(self, parametricStudy, salomeStudyID, entry):
137     try:
138       self.beginService("PARAMETRIC.SetParametricStudy")
139       param_study = cPickle.loads(parametricStudy)
140       self._set_parametric_study(param_study, salomeStudyID, entry)
141       self.endService("PARAMETRIC.SetParametricStudy")
142     except:
143       self._raiseSalomeError()
144
145   def _get_parametric_study(self, salomeStudyID, entry):
146     if salomeStudyID not in self.param_study_dict or entry not in self.param_study_dict[salomeStudyID]:
147       raise Exception("No valid parametric study at entry %s" % entry)
148     param_study = self.param_study_dict[salomeStudyID][entry]
149     param_study.entry = entry
150     return param_study
151
152   def GetParametricStudy(self, salomeStudyID, entry):
153     try:
154       self.beginService("PARAMETRIC.GetParametricStudy")
155       param_study = self._get_parametric_study(salomeStudyID, entry)
156       return cPickle.dumps(param_study)
157       self.endService("PARAMETRIC.GetParametricStudy")
158     except:
159       self._raiseSalomeError()
160
161   def _get_salome_runtime(self):
162     if self.salome_runtime is None:
163       # Initialize runtime for YACS
164       SALOMERuntime.RuntimeSALOME.setRuntime()
165       self.salome_runtime = SALOMERuntime.getSALOMERuntime()
166       mc = salome.naming_service.Resolve('/Kernel/ModulCatalog')
167       if mc is None:
168         raise Exception ("Internal error: Cannot find SALOME Module Catalog")
169       ior = salome.orb.object_to_string(mc)
170       self.session_catalog = self.salome_runtime.loadCatalog("session", ior)
171       self.salome_runtime.addCatalog(self.session_catalog)
172     return self.salome_runtime
173
174   def RunStudy(self, salomeStudyID, entry, localOnly):
175     try:
176       self.beginService("PARAMETRIC.RunStudy")
177
178       PARAMETRIC.lock.acquire()
179       salome.salome_init()
180       PARAMETRIC.lock.release()
181       
182       # Get parametric study from the case in Salome study
183       param_study = self._get_parametric_study(salomeStudyID, entry)
184
185       # Generate YACS schema
186       runtime = self._get_salome_runtime()
187       proc = pilot.Proc("ParametricSchema")
188       param_input_tc = runtime.getTypeCode("SALOME_TYPES/ParametricInput")
189       if param_input_tc is None:
190         raise Exception ("Internal error: No typecode found for type 'SALOME_TYPES/ParametricInput'")
191       param_output_tc = runtime.getTypeCode("SALOME_TYPES/ParametricOutput")
192       if param_output_tc is None:
193         raise Exception ("Internal error: No typecode found for type 'SALOME_TYPES/ParametricOutput'")
194       foreach = pilot.ForEachLoop("ForEach", param_input_tc)
195       foreach.edGetNbOfBranchesPort().edInit(param_study.nb_parallel_computations)
196       proc.edAddChild(foreach)
197       
198       distrib_container = proc.createContainer("DistribContainer")
199       if localOnly:
200         distrib_container.setProperty("hostname", "localhost")
201
202       if param_study.solver_code_type == ParametricStudy.SALOME_COMPONENT:
203         solver_code = param_study.salome_component_name
204         solver_compo_inst = proc.createComponentInstance(solver_code)
205         solver_compo_def = self.session_catalog._componentMap[solver_code]
206         solver_compo_inst.setContainer(distrib_container)
207   
208         init_solver = solver_compo_def._serviceMap["Init"].clone(None)
209         init_solver.setComponent(solver_compo_inst)
210         init_solver.getInputPort("studyID").edInit(salomeStudyID)
211         solver_case_entry = parse_entry(param_study.solver_case_entry)
212         init_solver.getInputPort("detCaseEntry").edInit(solver_case_entry)
213         foreach.edSetInitNode(init_solver)
214   
215         exec_solver = solver_compo_def._serviceMap["Exec"].clone(None)
216         exec_solver.setComponent(solver_compo_inst)
217         foreach.edSetNode(exec_solver)
218   
219         finalize_solver = solver_compo_def._serviceMap["Finalize"].clone(None)
220         finalize_solver.setComponent(solver_compo_inst)
221         foreach.edSetFinalizeNode(finalize_solver)
222       else:
223         exec_solver = runtime.createScriptNode(SALOMERuntime.PythonNode.KIND, "Exec")
224         exec_solver.edAddInputPort("paramInput", param_input_tc)
225         exec_solver.edAddOutputPort("paramOutput", param_output_tc)
226         indented_user_script = ""
227         for line in param_study.python_script.splitlines():
228           indented_user_script += "  " + line + "\n"
229         exec_script = start_script + indented_user_script + end_script
230         exec_solver.setScript(exec_script)
231         exec_solver.setExecutionMode("remote")
232         exec_solver.setContainer(distrib_container)
233         foreach.edSetNode(exec_solver)
234
235       seq_param_output_tc = proc.createSequenceTc("", "seq_param_output", param_output_tc)
236       aggregator = runtime.createScriptNode(SALOMERuntime.PythonNode.KIND, "Aggregator")
237       aggregator_input_port = aggregator.edAddInputPort("results", seq_param_output_tc)
238       proc.edAddChild(aggregator)
239
240       #proc.edAddLink(init_data_output_port, foreach.edGetSeqOfSamplesPort())
241       proc.edAddLink(foreach.edGetSamplePort(), exec_solver.getInputPort("paramInput"))
242       proc.edAddCFLink(foreach, aggregator)
243       proc.edAddLink(exec_solver.getOutputPort("paramOutput"), aggregator_input_port)
244
245       # Set input data
246       if param_study.data is None:
247         param_study.generate_data()
248       
249       seqsamples = []
250       refsample = {"inputVarList": param_study.input_vars,
251                    "outputVarList": param_study.output_vars,
252                    "inputValues": [[[]]],
253                    "specificParameters": [],
254                   }
255
256       for i in range(param_study.datasize):
257         sample = copy.deepcopy(refsample)
258         for var in param_study.input_vars:
259           sample["inputValues"][0][0].append([param_study.data[var][i]])
260         seqsamples.append(sample)
261       foreach.edGetSeqOfSamplesPort().edInitPy(seqsamples)
262
263       logger.debug("Checking validity...")
264       if not proc.isValid():
265         raise Exception("The schema is not valid and can not be executed.")
266       
267       logger.debug("Checking consistency...")
268       info = pilot.LinkInfo(pilot.LinkInfo.ALL_DONT_STOP)
269       proc.checkConsistency(info)
270       if info.areWarningsOrErrors():
271         logger.error(info.getGlobalRepr())
272         raise Exception("The schema is not consistent and can not be executed.")
273       logger.debug("Schema validated")
274   
275       # Launch computation
276       executor = pilot.ExecutorSwig()
277       executor.RunPy(proc)
278       if proc.getEffectiveState() != pilot.DONE:
279         msg = proc.getErrorReport()
280         if msg != "":
281           raise Exception("YACS schema execution ended with errors:\n%s" % msg)
282         else:
283           raise Exception("YACS schema execution failed. No error report available.")
284
285       # Get output values
286       seqresults = aggregator.getInputPort("results").getPyObj()
287       for varname in param_study.output_vars:
288         param_study.data[varname] = []
289       param_study.data["__ERROR_MESSAGE__"] = []
290
291       for result in seqresults:
292         if result["returnCode"] == 0:
293           valuelist = result["outputValues"][0][0]
294           if len(valuelist) != len(param_study.output_vars):
295             raise Exception("Incoherent number of result variables")
296           for i in range(len(valuelist)):
297             param_study.data[param_study.output_vars[i]].append(valuelist[i][0])
298           param_study.data["__ERROR_MESSAGE__"].append(None)
299         else:
300           for varname in param_study.output_vars:
301             param_study.data[varname].append(None)
302           param_study.data["__ERROR_MESSAGE__"].append(result["errorMessage"])
303
304       # Save results in Salome study
305       self._set_parametric_study(param_study, salomeStudyID, entry)
306
307       self.endService("PARAMETRIC.RunStudy")
308     except:
309       self._raiseSalomeError()
310
311   def ExportToCSV(self, salomeStudyID, entry, filePath):
312     try:
313       self.beginService("PARAMETRIC.ExportToCSV")
314
315       PARAMETRIC.lock.acquire()
316       salome.salome_init()
317       PARAMETRIC.lock.release()
318
319       # Get parametric study from the case in Salome study
320       param_study = self._get_parametric_study(salomeStudyID, entry)
321       
322       # Export parametric study to CSV file
323       param_study.export_data_to_csv_file(filePath)
324
325       self.endService("PARAMETRIC.ExportToCSV")
326     except:
327       self._raiseSalomeError()
328
329   def Save(self, theComponent, theURL, isMultiFile):
330     try:
331       # Select parametric studies to save
332       salomeStudyID = theComponent.GetStudy()._get_StudyId()
333       componentEntry = theComponent.GetID()
334       dict_to_save = {}
335       if salomeStudyID in self.param_study_dict:
336         for (entry, param_study) in self.param_study_dict[salomeStudyID].iteritems():
337           if entry.startswith(componentEntry):
338             dict_to_save[entry] = param_study
339       
340       if len(dict_to_save) > 0:
341         # Save parametric studies in temporary file
342         (fd, filename) = tempfile.mkstemp(prefix = "PARAMETRIC_", suffix = ".hdf")
343         os.close(fd)
344         save_param_study_dict(dict_to_save, filename)
345         
346         # Return the content of the temporary file as a byte sequence
347         with open(filename) as f:
348           buf = f.read()
349         
350         # Delete the temporary file
351         os.remove(filename)
352         
353         return buf
354       else:
355         return ""
356     except:
357       logger.exception("Error while trying to save study")
358       return ""
359
360   def Load(self, theComponent, theStream, theURL, isMultiFile):
361     try:
362       if len(theStream) == 0:
363         return 1
364       
365       # Save the stream in a temporary file
366       (fd, filename) = tempfile.mkstemp(prefix = "PARAMETRIC_", suffix = ".hdf")
367       os.close(fd)
368       with open(filename, "w") as f:
369         f.write(theStream)
370
371       # Load param studies dictionary
372       loaded_dict = load_param_study_dict(filename)
373       
374       # Delete the temporary file
375       os.remove(filename)
376       
377       # Update param study dictionary with loaded dict
378       salomeStudyID = theComponent.GetStudy()._get_StudyId()
379       componentEntry = theComponent.GetID()
380       if salomeStudyID not in self.param_study_dict:
381         self.param_study_dict[salomeStudyID] = {}
382         for (entry, param_study) in loaded_dict.iteritems():
383           if entry.startswith(componentEntry):
384             self.param_study_dict[salomeStudyID][entry] = param_study
385       return 1
386     except:
387       logger.exception("Error while trying to load study")
388       return 0