Salome HOME
Replace Eficas by a custom GUI for the definition of execution parameters
[modules/parametric.git] / src / PARAMETRIC / PARAMETRIC.py
1 # Copyright (C) 2012 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 re
23 import copy
24
25 import salome
26 import SALOME
27 import SALOME_ModuleCatalog
28 import PARAMETRIC_ORB__POA
29 from SALOME_ComponentPy import SALOME_ComponentPy_i
30 from SALOME_DriverPy import SALOME_DriverPy_i
31 import SALOMERuntime
32 import loader
33 import pilot
34
35 from salome.kernel.logger import Logger
36 from salome.kernel import termcolor
37 logger = Logger("PARAMETRIC", color = termcolor.BLUE)
38 logger.setLevel(logging.DEBUG)
39
40 from salome.parametric.study import ParametricStudyEditor
41
42 class PARAMETRIC(PARAMETRIC_ORB__POA.PARAMETRIC_Gen, SALOME_ComponentPy_i, SALOME_DriverPy_i):
43
44   lock = threading.Lock()
45
46   def __init__(self, orb, poa, contID, containerName, instanceName, interfaceName):
47     SALOME_ComponentPy_i.__init__(self, orb, poa, contID, containerName, instanceName, interfaceName, 0)
48     SALOME_DriverPy_i.__init__(self, interfaceName)
49     self.salome_runtime = None
50     self.session_catalog = None
51
52   def _raiseSalomeError(self):
53     message = "Error in component %s running in container %s." % (self._instanceName, self._containerName)
54     logger.exception(message)
55     message += " " + traceback.format_exc()
56     exc = SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR, message,
57                                  inspect.stack()[1][1], inspect.stack()[1][2])
58     raise SALOME.SALOME_Exception(exc)
59
60   def _get_salome_runtime(self):
61     if self.salome_runtime is None:
62       # Initialize runtime for YACS
63       SALOMERuntime.RuntimeSALOME.setRuntime()
64       self.salome_runtime = SALOMERuntime.getSALOMERuntime()
65       mc = salome.naming_service.Resolve('/Kernel/ModulCatalog')
66       if mc is None:
67         raise Exception ("Internal error: Cannot find SALOME Module Catalog")
68       ior = salome.orb.object_to_string(mc)
69       self.session_catalog = self.salome_runtime.loadCatalog("session", ior)
70       self.salome_runtime.addCatalog(self.session_catalog)
71     return self.salome_runtime
72
73   def _parse_entry(self, selected_value):
74     """
75     Find entry if selected_value is something like "name (entry)"
76     """
77     entry = selected_value
78     match = re.search("\((.*)\)$", entry)
79     if match is not None:
80       entry = match.group(1)
81     return entry
82
83   def RunStudy(self, studyId, caseEntry):
84     try:
85       self.beginService("PARAMETRIC.RunStudy")
86
87       PARAMETRIC.lock.acquire()
88       salome.salome_init()
89       PARAMETRIC.lock.release()
90       
91       # Get parametric study from the case in Salome study
92       ed = ParametricStudyEditor(studyId)
93       param_study = ed.get_parametric_study(caseEntry)
94
95       # Generate YACS schema
96       runtime = self._get_salome_runtime()
97       proc = pilot.Proc("ParametricSchema")
98       param_input_tc = runtime.getTypeCode("SALOME_TYPES/ParametricInput")
99       if param_input_tc is None:
100         raise Exception ("Internal error: No typecode found for type 'SALOME_TYPES/ParametricInput'")
101       foreach = pilot.ForEachLoop("ForEach", param_input_tc)
102       foreach.edGetNbOfBranchesPort().edInit(param_study.nb_parallel_computations)
103       proc.edAddChild(foreach)
104
105       solver_code = param_study.salome_component_name
106       solver_compo_inst = proc.createComponentInstance(solver_code)
107       solver_compo_def = self.session_catalog._componentMap[solver_code]
108       
109       distrib_container = proc.createContainer("DistribContainer")
110       distrib_container.setProperty("hostname", "localhost")
111       solver_compo_inst.setContainer(distrib_container)
112
113       init_solver = solver_compo_def._serviceMap["Init"].clone(None)
114       init_solver.setComponent(solver_compo_inst)
115       init_solver.getInputPort("studyID").edInit(studyId)
116       entry = self._parse_entry(param_study.solver_case_entry)
117       init_solver.getInputPort("detCaseEntry").edInit(entry)
118       foreach.edSetInitNode(init_solver)
119
120       exec_solver = solver_compo_def._serviceMap["Exec"].clone(None)
121       exec_solver.setComponent(solver_compo_inst)
122       foreach.edSetNode(exec_solver)
123
124       finalize_solver = solver_compo_def._serviceMap["Finalize"].clone(None)
125       finalize_solver.setComponent(solver_compo_inst)
126       foreach.edSetFinalizeNode(finalize_solver)
127
128       param_output_tc = runtime.getTypeCode("SALOME_TYPES/ParametricOutput")
129       if param_output_tc is None:
130         raise Exception ("Internal error: No typecode found for type 'SALOME_TYPES/ParametricOutput'")
131       seq_param_output_tc = proc.createSequenceTc("", "seq_param_output", param_output_tc)
132       aggregator = runtime.createScriptNode(SALOMERuntime.PythonNode.KIND, "Aggregator")
133       aggregator_input_port = aggregator.edAddInputPort("results", seq_param_output_tc)
134       proc.edAddChild(aggregator)
135
136       #proc.edAddLink(init_data_output_port, foreach.edGetSeqOfSamplesPort())
137       proc.edAddLink(foreach.edGetSamplePort(), exec_solver.getInputPort("paramInput"))
138       proc.edAddCFLink(foreach, aggregator)
139       proc.edAddLink(exec_solver.getOutputPort("paramOutput"), aggregator_input_port)
140
141       # Set input data
142       if param_study.data is None:
143         param_study.generate_data()
144       
145       seqsamples = []
146       refsample = {"inputVarList": [],
147                    "outputVarList": [],
148                    "inputValues": [[[]]],
149                    "specificParameters": [],
150                   }
151       for varname in param_study.output_vars:
152         refsample["outputVarList"].append(varname)
153
154       for i in range(param_study.datasize):
155         sample = copy.deepcopy(refsample)
156         for var in param_study.input_vars:
157           sample["inputVarList"].append(var.name)
158           sample["inputValues"][0][0].append([param_study.data[var.name][i]])
159         seqsamples.append(sample)
160       foreach.edGetSeqOfSamplesPort().edInitPy(seqsamples)
161
162       logger.debug("Checking validity...")
163       if not proc.isValid():
164         raise Exception("The schema is not valid and can not be executed.")
165       
166       logger.debug("Checking consistency...")
167       info = pilot.LinkInfo(pilot.LinkInfo.ALL_DONT_STOP)
168       proc.checkConsistency(info)
169       if info.areWarningsOrErrors():
170         logger.error(info.getGlobalRepr())
171         raise Exception("The schema is not consistent and can not be executed.")
172       logger.debug("Schema validated")
173   
174       # Launch computation
175       executor = pilot.ExecutorSwig()
176       executor.RunPy(proc)
177       if proc.getEffectiveState() != pilot.DONE:
178         msg = proc.getErrorReport()
179         if msg != "":
180           raise Exception("YACS schema execution ended with errors:\n%s" % msg)
181         else:
182           raise Exception("YACS schema execution failed. No error report available.")
183
184       # Get output values
185       seqresults = aggregator.getInputPort("results").getPyObj()
186       for varname in param_study.output_vars:
187         param_study.data[varname] = []
188       param_study.data["__ERROR_MESSAGE__"] = []
189
190       for result in seqresults:
191         if result["returnCode"] == 0:
192           valuelist = result["outputValues"][0][0]
193           if len(valuelist) != len(param_study.output_vars):
194             raise Exception("Incoherent number of result variables")
195           for i in range(len(valuelist)):
196             param_study.data[param_study.output_vars[i]].append(valuelist[i][0])
197           param_study.data["__ERROR_MESSAGE__"].append(None)
198         else:
199           for varname in param_study.output_vars:
200             param_study.data[varname].append(None)
201           param_study.data["__ERROR_MESSAGE__"].append(result["errorMessage"])
202
203       # Save results in Salome study
204       ed.set_parametric_study_at_entry(param_study, caseEntry)
205
206       self.endService("PARAMETRIC.RunStudy")
207     except:
208       self._raiseSalomeError()