1 # Copyright (C) 2012-2015 EDF
3 # This file is part of SALOME PARAMETRIC module.
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.
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.
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/>.
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
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)
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
46 MODULE_NAME = "PARAMETRIC"
48 COMPONENT_NAME = "Parametric"
49 COMPONENT_ICON = "PARAMETRIC_small.png"
51 PARAM_STUDY_ICON = "param_study.png"
54 from salome.kernel.parametric.pyscript_utils import \
55 create_input_dict, create_normal_parametric_output, create_error_parametric_output
58 globals().update(create_input_dict({}, paramInput))
60 ### Start of user code
68 for output_var in paramInput["outputVarList"]:
69 if globals().has_key(output_var):
70 output_dict[output_var] = globals()[output_var]
72 raise Exception("User Python script has not created variable %s" % output_var)
74 paramOutput = create_normal_parametric_output(output_dict, paramInput)
76 except Exception, exc:
77 paramOutput = create_error_parametric_output(str(exc))
80 class PARAMETRIC(PARAMETRIC_ORB__POA.PARAMETRIC_Gen, SALOME_ComponentPy_i, SALOME_DriverPy_i):
82 lock = threading.Lock()
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)
88 self.param_study_dict = {}
89 self.salome_runtime = None
90 self.session_catalog = None
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)
100 def _find_or_create_param_component(self, salomeStudyID):
102 Find the component "Parametric" or create it if none is found
103 :return: the SComponent found or created.
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]
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] = {}
119 self.param_study_dict[salomeStudyID][entry] = parametric_study
121 def AddParametricStudy(self, parametricStudy, salomeStudyID):
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")
130 self._raiseSalomeError()
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)
136 def SetParametricStudy(self, parametricStudy, salomeStudyID, entry):
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")
143 self._raiseSalomeError()
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
152 def GetParametricStudy(self, salomeStudyID, entry):
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")
159 self._raiseSalomeError()
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')
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
174 def RunStudy(self, salomeStudyID, entry, localOnly):
176 self.beginService("PARAMETRIC.RunStudy")
178 PARAMETRIC.lock.acquire()
180 PARAMETRIC.lock.release()
182 # Get parametric study from the case in Salome study
183 param_study = self._get_parametric_study(salomeStudyID, entry)
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)
198 distrib_container = proc.createContainer("DistribContainer")
200 distrib_container.setProperty("hostname", "localhost")
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)
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)
215 exec_solver = solver_compo_def._serviceMap["Exec"].clone(None)
216 exec_solver.setComponent(solver_compo_inst)
217 foreach.edSetNode(exec_solver)
219 finalize_solver = solver_compo_def._serviceMap["Finalize"].clone(None)
220 finalize_solver.setComponent(solver_compo_inst)
221 foreach.edSetFinalizeNode(finalize_solver)
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)
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)
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)
246 if param_study.data is None:
247 param_study.generate_data()
250 refsample = {"inputVarList": param_study.input_vars,
251 "outputVarList": param_study.output_vars,
252 "inputValues": [[[]]],
253 "specificParameters": [],
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)
263 logger.debug("Checking validity...")
264 if not proc.isValid():
265 raise Exception("The schema is not valid and can not be executed.")
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")
276 executor = pilot.ExecutorSwig()
278 if proc.getEffectiveState() != pilot.DONE:
279 msg = proc.getErrorReport()
281 raise Exception("YACS schema execution ended with errors:\n%s" % msg)
283 raise Exception("YACS schema execution failed. No error report available.")
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__"] = []
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)
300 for varname in param_study.output_vars:
301 param_study.data[varname].append(None)
302 param_study.data["__ERROR_MESSAGE__"].append(result["errorMessage"])
304 # Save results in Salome study
305 self._set_parametric_study(param_study, salomeStudyID, entry)
307 self.endService("PARAMETRIC.RunStudy")
309 self._raiseSalomeError()
311 def ExportToCSV(self, salomeStudyID, entry, filePath):
313 self.beginService("PARAMETRIC.ExportToCSV")
315 PARAMETRIC.lock.acquire()
317 PARAMETRIC.lock.release()
319 # Get parametric study from the case in Salome study
320 param_study = self._get_parametric_study(salomeStudyID, entry)
322 # Export parametric study to CSV file
323 param_study.export_data_to_csv_file(filePath)
325 self.endService("PARAMETRIC.ExportToCSV")
327 self._raiseSalomeError()
329 def Save(self, theComponent, theURL, isMultiFile):
331 # Select parametric studies to save
332 salomeStudyID = theComponent.GetStudy()._get_StudyId()
333 componentEntry = theComponent.GetID()
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
340 if len(dict_to_save) > 0:
341 # Save parametric studies in temporary file
342 (fd, filename) = tempfile.mkstemp(prefix = "PARAMETRIC_", suffix = ".hdf")
344 save_param_study_dict(dict_to_save, filename)
346 # Return the content of the temporary file as a byte sequence
347 with open(filename) as f:
350 # Delete the temporary file
357 logger.exception("Error while trying to save study")
360 def Load(self, theComponent, theStream, theURL, isMultiFile):
362 if len(theStream) == 0:
365 # Save the stream in a temporary file
366 (fd, filename) = tempfile.mkstemp(prefix = "PARAMETRIC_", suffix = ".hdf")
368 with open(filename, "w") as f:
371 # Load param studies dictionary
372 loaded_dict = load_param_study_dict(filename)
374 # Delete the temporary file
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
387 logger.exception("Error while trying to load study")