From: Renaud Barate Date: Thu, 6 Dec 2012 10:31:02 +0000 (+0100) Subject: Add batch job generation X-Git-Tag: V6_6_0~3 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=c48a2e69eb806f4cc902fa70b9c3b8467921969b;p=modules%2Fparametric.git Add batch job generation --- diff --git a/resources/generate_job.png b/resources/generate_job.png new file mode 100644 index 0000000..a4429c6 Binary files /dev/null and b/resources/generate_job.png differ diff --git a/src/PARAMETRIC/PARAMETRIC.py b/src/PARAMETRIC/PARAMETRIC.py index 52d3ba6..631a49d 100644 --- a/src/PARAMETRIC/PARAMETRIC.py +++ b/src/PARAMETRIC/PARAMETRIC.py @@ -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) diff --git a/src/PARAMETRICGUI/PARAMETRICGUI.py b/src/PARAMETRICGUI/PARAMETRICGUI.py index e78753a..eea5a25 100644 --- a/src/PARAMETRICGUI/PARAMETRICGUI.py +++ b/src/PARAMETRICGUI/PARAMETRICGUI.py @@ -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 } diff --git a/src/salome/parametric/__init__.py b/src/salome/parametric/__init__.py index 18ce3ba..28860de 100644 --- a/src/salome/parametric/__init__.py +++ b/src/salome/parametric/__init__.py @@ -16,7 +16,10 @@ # along with SALOME PARAMETRIC module. If not, see . 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 index 0000000..351d4bd --- /dev/null +++ b/src/salome/parametric/genjob.py @@ -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 . + +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 diff --git a/src/salome/parametric/gui/CMakeLists.txt b/src/salome/parametric/gui/CMakeLists.txt index f1cf018..89f17ca 100644 --- a/src/salome/parametric/gui/CMakeLists.txt +++ b/src/salome/parametric/gui/CMakeLists.txt @@ -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 . -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}) diff --git a/src/salome/parametric/gui/__init__.py b/src/salome/parametric/gui/__init__.py index 882fff9..5563aa7 100644 --- a/src/salome/parametric/gui/__init__.py +++ b/src/salome/parametric/gui/__init__.py @@ -16,5 +16,7 @@ # along with SALOME PARAMETRIC module. If not, see . 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 index 0000000..976842b --- /dev/null +++ b/src/salome/parametric/gui/genjob.py @@ -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 . + +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 index 0000000..ec126b3 --- /dev/null +++ b/src/salome/parametric/gui/genjob.ui @@ -0,0 +1,110 @@ + + + GenJobDialog + + + + 0 + 0 + 636 + 202 + + + + Generate Job + + + + + + + + Result Study Name: + + + + + + + + + + Result Directory: + + + + + + + + + + 0 + 0 + + + + + + + + ... + + + + + + + + + Resource + + + + + + + + + + + + Qt::Vertical + + + + 20 + 43 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + +