]> SALOME platform Git repositories - modules/parametric.git/commitdiff
Salome HOME
Add batch job generation
authorRenaud Barate <renaud.barate@edf.fr>
Thu, 6 Dec 2012 10:31:02 +0000 (11:31 +0100)
committerRenaud Barate <renaud.barate@edf.fr>
Thu, 6 Dec 2012 10:31:02 +0000 (11:31 +0100)
resources/generate_job.png [new file with mode: 0644]
src/PARAMETRIC/PARAMETRIC.py
src/PARAMETRICGUI/PARAMETRICGUI.py
src/salome/parametric/__init__.py
src/salome/parametric/genjob.py [new file with mode: 0644]
src/salome/parametric/gui/CMakeLists.txt
src/salome/parametric/gui/__init__.py
src/salome/parametric/gui/genjob.py [new file with mode: 0644]
src/salome/parametric/gui/genjob.ui [new file with mode: 0644]

diff --git a/resources/generate_job.png b/resources/generate_job.png
new file mode 100644 (file)
index 0000000..a4429c6
Binary files /dev/null and b/resources/generate_job.png differ
index 52d3ba6769ff385e1f1435673dec21d9a78c9891..631a49d7aa0fd39d2ac5080fc82c71ebe7364f56 100644 (file)
@@ -19,7 +19,6 @@ import logging
 import threading
 import inspect
 import traceback
-import re
 import copy
 
 import salome
@@ -29,7 +28,6 @@ import PARAMETRIC_ORB__POA
 from SALOME_ComponentPy import SALOME_ComponentPy_i
 from SALOME_DriverPy import SALOME_DriverPy_i
 import SALOMERuntime
-import loader
 import pilot
 
 from salome.kernel.logger import Logger
@@ -37,7 +35,7 @@ from salome.kernel import termcolor
 logger = Logger("PARAMETRIC", color = termcolor.BLUE)
 logger.setLevel(logging.DEBUG)
 
-from salome.parametric import ParametricStudyEditor, ParametricStudy
+from salome.parametric import ParametricStudyEditor, ParametricStudy, parse_entry
 
 start_script = """
 from salome.kernel.parametric.pyscript_utils import \
@@ -97,16 +95,6 @@ class PARAMETRIC(PARAMETRIC_ORB__POA.PARAMETRIC_Gen, SALOME_ComponentPy_i, SALOM
       self.salome_runtime.addCatalog(self.session_catalog)
     return self.salome_runtime
 
-  def _parse_entry(self, selected_value):
-    """
-    Find entry if selected_value is something like "name (entry)"
-    """
-    entry = selected_value
-    match = re.search("\((.*)\)$", entry)
-    if match is not None:
-      entry = match.group(1)
-    return entry
-
   def RunStudy(self, studyId, caseEntry):
     try:
       self.beginService("PARAMETRIC.RunStudy")
@@ -144,7 +132,7 @@ class PARAMETRIC(PARAMETRIC_ORB__POA.PARAMETRIC_Gen, SALOME_ComponentPy_i, SALOM
         init_solver = solver_compo_def._serviceMap["Init"].clone(None)
         init_solver.setComponent(solver_compo_inst)
         init_solver.getInputPort("studyID").edInit(studyId)
-        entry = self._parse_entry(param_study.solver_case_entry)
+        entry = parse_entry(param_study.solver_case_entry)
         init_solver.getInputPort("detCaseEntry").edInit(entry)
         foreach.edSetInitNode(init_solver)
   
index e78753a3ede0ad038c29f3890b75ec2c34498821..eea5a25cd278e8e35f71bc42f9d4b9daa3389725 100644 (file)
@@ -34,7 +34,7 @@ logger = Logger("PARAMETRICGUI", color = termcolor.GREEN_FG)
 #logger.setLevel(logging.ERROR)
 
 import PARAMETRIC
-from salome.parametric.gui import MainPanel
+from salome.parametric.gui import MainPanel, GenJobDialog
 from salome.parametric import ParametricStudyEditor
 
 ################################################
@@ -44,11 +44,12 @@ from salome.parametric import ParametricStudyEditor
 
 class GUIcontext:
   # menus/toolbars/actions IDs
-  PARAMETRIC_MENU = 0
-  CREATE_PARAMETRIC_STUDY = 1
-  RUN_PARAMETRIC_STUDY = 2
-  EXPORT_DATA_TO_CSV = 3
-  EDIT_PARAMETRIC_STUDY = 4
+  PARAMETRIC_MENU = 8950
+  CREATE_PARAMETRIC_STUDY = 8951
+  RUN_PARAMETRIC_STUDY = 8952
+  EXPORT_DATA_TO_CSV = 8953
+  EDIT_PARAMETRIC_STUDY = 8954
+  GENERATE_JOB = 8955
 
   # constructor
   def __init__( self ):
@@ -84,6 +85,12 @@ class GUIcontext:
                         "Edit the selected parametric study",
                         "edit_param_study.png")
 
+    sgPyQt.createAction(GUIcontext.GENERATE_JOB,
+                        "Generate batch job",
+                        "Generate batch job",
+                        "Generate a batch job to run the selected parametric study",
+                        "generate_job.png")
+
 ################################################
 # Global variables
 ################################################
@@ -154,6 +161,7 @@ def createPopupMenu(popup, context):
     if selectedType == salome.parametric.study.PARAM_STUDY_TYPE_ID:
       popup.addAction(sgPyQt.action(GUIcontext.EDIT_PARAMETRIC_STUDY))
       popup.addAction(sgPyQt.action(GUIcontext.RUN_PARAMETRIC_STUDY))
+      popup.addAction(sgPyQt.action(GUIcontext.GENERATE_JOB))
       popup.addAction(sgPyQt.action(GUIcontext.EXPORT_DATA_TO_CSV))
 
 # process GUI action
@@ -177,9 +185,8 @@ def new_study():
   panel.new_study()
 
 def edit_study():
-  study_id = sgPyQt.getStudyId()
   entry = salome.sg.getSelected(0)
-  ed = ParametricStudyEditor(study_id)
+  ed = ParametricStudyEditor()
   panel = MainPanel()
   panel.edit_study(ed.get_parametric_study(entry))
 
@@ -226,10 +233,17 @@ def export_to_csv():
         qapp.translate("export_to_csv", "Error"),
         qapp.translate("export_to_csv", "Export to CSV file failed: %s" % exc))
 
+def generate_job():
+  entry = salome.sg.getSelected(0)
+  ed = ParametricStudyEditor()
+  dialog = GenJobDialog(sgPyQt.getDesktop(), ed.get_parametric_study(entry))
+  dialog.exec_()
+
 # ----------------------- #
 dict_command = {
   GUIcontext.CREATE_PARAMETRIC_STUDY: new_study,
   GUIcontext.RUN_PARAMETRIC_STUDY: run_study,
   GUIcontext.EXPORT_DATA_TO_CSV: export_to_csv,
-  GUIcontext.EDIT_PARAMETRIC_STUDY: edit_study
+  GUIcontext.EDIT_PARAMETRIC_STUDY: edit_study,
+  GUIcontext.GENERATE_JOB: generate_job
 }
index 18ce3bab202756fb6f7c37faec9754a61d25a0d7..28860dea1560d88f2b6c69774fe4eced835d0182 100644 (file)
 # along with SALOME PARAMETRIC module.  If not, see <http://www.gnu.org/licenses/>.
 
 import study
+import genjob
 
 ParametricStudy = study.ParametricStudy
 ParametricVariable = study.ParametricVariable
 ParametricStudyEditor = study.ParametricStudyEditor
+generate_job = genjob.generate_job
+parse_entry = genjob.parse_entry
diff --git a/src/salome/parametric/genjob.py b/src/salome/parametric/genjob.py
new file mode 100644 (file)
index 0000000..351d4bd
--- /dev/null
@@ -0,0 +1,118 @@
+# Copyright (C) 2012 EDF
+#
+# This file is part of SALOME PARAMETRIC module.
+#
+# SALOME PARAMETRIC module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# SALOME PARAMETRIC module is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with SALOME PARAMETRIC module.  If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import re
+import tempfile
+from datetime import datetime
+
+import salome
+from salome.kernel.studyedit import getStudyEditor
+from study import ParametricStudy
+
+job_script_template = """
+#!/usr/bin/env python
+
+import salome
+import PARAMETRIC
+
+salome.salome_init()
+
+# load study
+study = salome.myStudyManager.Open("%(input_study)s")
+
+# start container and load PARAMETRIC component
+comp = salome.lcc.FindOrLoadComponent("ParametricContainer", "PARAMETRIC")
+
+# run parametric study
+comp.RunStudy(study._get_StudyId(), "%(param_entry)s")
+
+# save study
+salome.myStudyManager.SaveAs("%(output_study)s", study, False)
+"""
+
+def generate_job(param_study, result_study_file_name, result_dir, resource):
+  """
+  Create a Launcher job using the parameters specified by the user.
+  """
+  # Save Salome study
+  ed = getStudyEditor()
+  name_wo_space = param_study.name.replace(" ", "_")
+  (fd, input_study) = tempfile.mkstemp(prefix = name_wo_space + "_Input_", suffix = ".hdf")
+  os.close(fd)
+  salome.myStudyManager.SaveAs(input_study, ed.study, False)
+
+  # Generate job script
+  job_script = job_script_template % {"input_study": os.path.basename(input_study),
+                                      "param_entry": param_study.entry,
+                                      "output_study": result_study_file_name}
+  (fd, job_script_file) = tempfile.mkstemp(prefix = "job_" + name_wo_space + "_", suffix = ".py")
+  os.close(fd)
+  f = open(job_script_file, "w")
+  f.write(job_script)
+  f.close()
+  
+  # Define job parameters
+  job_params = salome.JobParameters()
+  job_params.job_name = name_wo_space
+  job_params.job_type = "python_salome"
+  job_params.job_file = job_script_file
+  job_params.in_files = [input_study]
+  job_params.out_files = [result_study_file_name]
+  job_params.result_directory = result_dir
+
+  # Add files to transfer from the computation code
+  if param_study.solver_code_type == ParametricStudy.SALOME_COMPONENT:
+    code = param_study.salome_component_name
+    comp = salome.lcc.FindOrLoadComponent("FactoryServer", code)
+    if comp is not None and hasattr(comp, "GetFilesToTransfer"):
+        (code_in_files, code_out_files) = comp.GetFilesToTransfer(ed.studyId,
+                parse_entry(param_study.solver_case_entry))
+        job_params.in_files += code_in_files
+        job_params.out_files += code_out_files        
+
+  # Define resource parameters
+  job_params.resource_required = salome.ResourceParameters()
+  job_params.resource_required.name = resource
+  job_params.resource_required.nb_proc = param_study.nb_parallel_computations + 1
+
+  # Generate name for the working directory
+  res_manager = salome.naming_service.Resolve("/ResourcesManager")
+  res_definition = res_manager.GetResourceDefinition(resource)
+  res_work_dir = res_definition.working_directory
+  if res_work_dir != "":
+      timestr = datetime.now().ctime()
+      timestr = timestr.replace('/', '_')
+      timestr = timestr.replace('-', '_')
+      timestr = timestr.replace(':', '_')
+      timestr = timestr.replace(' ', '_')
+      work_dir = res_work_dir + "/" + job_params.job_name + "_" + timestr
+      job_params.work_directory = work_dir
+  
+  # Create Launcher job
+  launcher = salome.naming_service.Resolve('/SalomeLauncher')
+  launcher.createJob(job_params)
+
+def parse_entry(selected_value):
+  """
+  Find entry if selected_value is something like "name (entry)"
+  """
+  entry = selected_value
+  match = re.search("\((.*)\)$", entry)
+  if match is not None:
+    entry = match.group(1)
+  return entry
index f1cf0180729dccf557e017aebfa27ef2fc4bc78e..89f17ca1ee4112d1e04122f400de6a7d33f995c9 100644 (file)
@@ -15,7 +15,7 @@
 # You should have received a copy of the GNU Lesser General Public License
 # along with SALOME PARAMETRIC module.  If not, see <http://www.gnu.org/licenses/>.
 
-SET(PYUIC_FILES wizard_ui.py varrange_ui.py execparams_ui.py)
+SET(PYUIC_FILES wizard_ui.py varrange_ui.py execparams_ui.py genjob_ui.py)
 SET(INSTALL_DIR ${PYTHONDIR}/salome/parametric/gui)
 
 FOREACH(OUTPUT ${PYUIC_FILES})
index 882fff927c57fd472ccdf5bcb62a7b73850f1eaf..5563aa7b2439e1dd03191681b3af1acd99df80b2 100644 (file)
@@ -16,5 +16,7 @@
 # along with SALOME PARAMETRIC module.  If not, see <http://www.gnu.org/licenses/>.
 
 import mainpanel
+import genjob
 
 MainPanel = mainpanel.MainPanel
+GenJobDialog = genjob.GenJobDialog
diff --git a/src/salome/parametric/gui/genjob.py b/src/salome/parametric/gui/genjob.py
new file mode 100644 (file)
index 0000000..976842b
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright (C) 2012 EDF
+#
+# This file is part of SALOME PARAMETRIC module.
+#
+# SALOME PARAMETRIC module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# SALOME PARAMETRIC module is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with SALOME PARAMETRIC module.  If not, see <http://www.gnu.org/licenses/>.
+
+import os
+from PyQt4 import QtGui, QtCore
+
+import salome
+from salome.parametric import generate_job
+from genjob_ui import Ui_GenJobDialog
+
+
+class GenJobDialog(QtGui.QDialog, Ui_GenJobDialog):
+
+  def __init__(self, parent, param_study):
+    QtGui.QDialog.__init__(self, parent)
+    self.setupUi(self)
+    self.connect(self.dialogButtonBox, QtCore.SIGNAL("accepted()"), self.validate)
+    self.connect(self.dialogButtonBox, QtCore.SIGNAL("rejected()"), self.close)
+    self.connect(self.chooseResultDirectoryButton, QtCore.SIGNAL("clicked()"), self.choose_result_dir)
+    self.resultStudyLE.setText(param_study.name.replace(" ", "_") + "_Result.hdf")
+    self.resultDirectoryLE.setText(os.getcwd())
+    
+    # Populate resource combo box
+    res_manager = salome.naming_service.Resolve("/ResourcesManager")
+    res_params = salome.ResourceParameters()
+    res_list = res_manager.GetFittingResources(res_params)
+    self.resourceCB.addItems(res_list)
+    
+    self.param_study = param_study
+
+  def choose_result_dir(self):
+    directory = QtGui.QFileDialog.getExistingDirectory(self,
+            directory = self.resultDirectoryLE.text(),
+            options = QtGui.QFileDialog.ShowDirsOnly)
+    if not directory.isNull():
+      self.resultDirectoryLE.setText(directory)
+
+  def validate(self):
+    generate_job(self.param_study, str(self.resultStudyLE.text()),
+                 str(self.resultDirectoryLE.text()), str(self.resourceCB.currentText()))
+    self.close()
diff --git a/src/salome/parametric/gui/genjob.ui b/src/salome/parametric/gui/genjob.ui
new file mode 100644 (file)
index 0000000..ec126b3
--- /dev/null
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GenJobDialog</class>
+ <widget class="QDialog" name="GenJobDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>636</width>
+    <height>202</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Generate Job</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QFormLayout" name="formLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Result Study Name:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="resultStudyLE"/>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Result Directory:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <layout class="QHBoxLayout" name="horizontalLayout_2">
+       <item>
+        <widget class="QLineEdit" name="resultDirectoryLE">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="chooseResultDirectoryButton">
+         <property name="text">
+          <string>...</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Resource</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QComboBox" name="resourceCB"/>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>43</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QDialogButtonBox" name="dialogButtonBox">
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>