From 52fa018273f662e7b5ec8e82b047a87b28e39189 Mon Sep 17 00:00:00 2001 From: Paul RASCLE Date: Thu, 20 Jul 2017 15:58:07 +0200 Subject: [PATCH] Revert "Merge branch 'yan/V8_3_BR' into pre/V8_3_BR" This reverts commit 859dac6d961b1b9918f10e057eab185b18ca0a53, reversing changes made to 133608acdd6339df431d784728ef64615eacb65c. --- CMakeLists.txt | 1 + adm_local/cmake_files/CMakeLists.txt | 2 + adm_local/cmake_files/FindMascaret.cmake | 23 + .../cmake_files/FindSalomeMascaret.cmake | 28 + adm_local/cmake_files/FindSalomeTelemac.cmake | 1 - adm_local/cmake_files/FindTelemac.cmake | 27 +- idl/HYDROSOLVER.idl | 171 ++++++ src/CMakeLists.txt | 1 + src/HYDRO/CMakeLists.txt | 2 + src/HYDRO/MASCARET.py | 412 +++++++++++++ src/HYDRO/TELEMAC2D.py | 579 ++++++++++++++++++ src/mascaret_wrapper/CMakeLists.txt | 67 ++ src/mascaret_wrapper/Mascaret.cxx | 225 +++++++ src/mascaret_wrapper/Mascaret.hxx | 87 +++ src/mascaret_wrapper/mascaret_swig.i | 43 ++ src/salome_hydro/CMakeLists.txt | 1 + src/salome_hydro/coupling1d2d/CMakeLists.txt | 28 + src/salome_hydro/coupling1d2d/__init__.py | 0 .../coupling1d2d/eficas/CMakeLists.txt | 39 ++ .../coupling1d2d/eficas/__init__.py | 0 src/salome_hydro/coupling1d2d/eficas/appli.py | 118 ++++ .../eficas/configuration_coupling1d2d.py | 55 ++ .../coupling1d2d/eficas/coupling1d2d_cata.py | 47 ++ .../eficas/coupling1d2d_template_schema.xml | 447 ++++++++++++++ .../eficas/generator_coupling1d2d.py | 67 ++ src/salome_hydro/coupling1d2d/eficas/prefs.py | 18 + .../coupling1d2d/eficas/prefs_coupling1d2d.py | 28 + src/salome_hydro/mascaret/__init__.py | 6 + src/salome_hydro/pytel/eficas/pytel_cata.py | 2 +- src/salome_hydro/study.py | 54 ++ 30 files changed, 2562 insertions(+), 17 deletions(-) create mode 100644 adm_local/cmake_files/FindMascaret.cmake create mode 100644 adm_local/cmake_files/FindSalomeMascaret.cmake create mode 100644 src/HYDRO/MASCARET.py create mode 100644 src/HYDRO/TELEMAC2D.py create mode 100644 src/mascaret_wrapper/CMakeLists.txt create mode 100644 src/mascaret_wrapper/Mascaret.cxx create mode 100644 src/mascaret_wrapper/Mascaret.hxx create mode 100644 src/mascaret_wrapper/mascaret_swig.i create mode 100644 src/salome_hydro/coupling1d2d/CMakeLists.txt create mode 100644 src/salome_hydro/coupling1d2d/__init__.py create mode 100644 src/salome_hydro/coupling1d2d/eficas/CMakeLists.txt create mode 100644 src/salome_hydro/coupling1d2d/eficas/__init__.py create mode 100644 src/salome_hydro/coupling1d2d/eficas/appli.py create mode 100644 src/salome_hydro/coupling1d2d/eficas/configuration_coupling1d2d.py create mode 100644 src/salome_hydro/coupling1d2d/eficas/coupling1d2d_cata.py create mode 100644 src/salome_hydro/coupling1d2d/eficas/coupling1d2d_template_schema.xml create mode 100644 src/salome_hydro/coupling1d2d/eficas/generator_coupling1d2d.py create mode 100644 src/salome_hydro/coupling1d2d/eficas/prefs.py create mode 100644 src/salome_hydro/coupling1d2d/eficas/prefs_coupling1d2d.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f21473..c9829ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,7 @@ FIND_PACKAGE(SalomePyQt5 REQUIRED) ## HYDROSOLVER specifics ## +FIND_PACKAGE(SalomeMascaret REQUIRED) FIND_PACKAGE(SalomeTelemac REQUIRED) # Directories diff --git a/adm_local/cmake_files/CMakeLists.txt b/adm_local/cmake_files/CMakeLists.txt index 489d80f..4051084 100644 --- a/adm_local/cmake_files/CMakeLists.txt +++ b/adm_local/cmake_files/CMakeLists.txt @@ -21,6 +21,8 @@ # These files are data, module or lib files SET(_adm_data + FindMascaret.cmake + FindSalomeMascaret.cmake FindTelemac.cmake FindSalomeTelemac.cmake ) diff --git a/adm_local/cmake_files/FindMascaret.cmake b/adm_local/cmake_files/FindMascaret.cmake new file mode 100644 index 0000000..1602e88 --- /dev/null +++ b/adm_local/cmake_files/FindMascaret.cmake @@ -0,0 +1,23 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +FIND_LIBRARY(MASCARET_LIBRARIES mascaret) +FIND_PATH(MASCARET_INCLUDE_DIR apimascaret.h) + +# Handle the standard arguments of the find_package() command: +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Mascaret REQUIRED_VARS MASCARET_LIBRARIES MASCARET_INCLUDE_DIR) diff --git a/adm_local/cmake_files/FindSalomeMascaret.cmake b/adm_local/cmake_files/FindSalomeMascaret.cmake new file mode 100644 index 0000000..fa7c5ce --- /dev/null +++ b/adm_local/cmake_files/FindSalomeMascaret.cmake @@ -0,0 +1,28 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +# Mascaret detection for Salome +# +# !! Please read the generic detection procedure in SalomeMacros.cmake !! +# +SALOME_FIND_PACKAGE_AND_DETECT_CONFLICTS(Mascaret MASCARET_ROOT_DIR 0) +MARK_AS_ADVANCED(MASCARET_LIBRARIES MASCARET_INCLUDE_DIR) + +IF(Mascaret_FOUND OR MASCARET_FOUND) + SALOME_ACCUMULATE_HEADERS(MASCARET_INCLUDE_DIR) + SALOME_ACCUMULATE_ENVIRONMENT(LD_LIBRARY_PATH ${MASCARET_LIBRARIES}) +ENDIF() diff --git a/adm_local/cmake_files/FindSalomeTelemac.cmake b/adm_local/cmake_files/FindSalomeTelemac.cmake index c1b3b53..c16a2cb 100644 --- a/adm_local/cmake_files/FindSalomeTelemac.cmake +++ b/adm_local/cmake_files/FindSalomeTelemac.cmake @@ -27,7 +27,6 @@ MARK_AS_ADVANCED(TELEMAC_LIBRARY_api TELEMAC_LIBRARY_sisyphe TELEMAC_LIBRARY_special TELEMAC_LIBRARY_telemac2d - TELEMAC_LIBRARY_mascaret TELEMAC_LIBRARY_tomawac TELEMAC_LIBRARY_gretel TELEMAC_LIBRARY_partel diff --git a/adm_local/cmake_files/FindTelemac.cmake b/adm_local/cmake_files/FindTelemac.cmake index 4920ae3..6be9348 100644 --- a/adm_local/cmake_files/FindTelemac.cmake +++ b/adm_local/cmake_files/FindTelemac.cmake @@ -15,32 +15,30 @@ # You should have received a copy of the GNU General Public License # along with SALOME HYDRO module. If not, see . -FIND_LIBRARY(TELEMAC_LIBRARY_mascaret mascaret - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_api api - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_bief bief - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_damocles damocles - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_parallel parallel - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_sisyphe sisyphe - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_special special - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_telemac2d telemac2d - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_tomawac tomawac - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_gretel gretel - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_partel partel - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_LIBRARY(TELEMAC_LIBRARY_hermes hermes - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/lib) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/lib) FIND_PATH(TELEMAC_INCLUDE_DIR interface_telemac2d.mod - PATHS ${TELEMAC_ROOT_DIR}/builds/salomeHPC/wrap_api/include) + PATHS ${TELEMAC_ROOT_DIR}/builds/salome/wrap_api/include) # Handle the standard arguments of the find_package() command: INCLUDE(FindPackageHandleStandardArgs) @@ -51,7 +49,6 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Telemac REQUIRED_VARS TELEMAC_LIBRARY_api TELEMAC_LIBRARY_sisyphe TELEMAC_LIBRARY_special TELEMAC_LIBRARY_telemac2d - TELEMAC_LIBRARY_mascaret TELEMAC_LIBRARY_tomawac TELEMAC_LIBRARY_gretel TELEMAC_LIBRARY_partel diff --git a/idl/HYDROSOLVER.idl b/idl/HYDROSOLVER.idl index 5abddcf..77065ce 100644 --- a/idl/HYDROSOLVER.idl +++ b/idl/HYDROSOLVER.idl @@ -29,9 +29,180 @@ module HYDROSOLVER_ORB { + struct MascaretFile { + string fileName; + string fileType; + }; + + typedef sequence MascaretFileList; + typedef sequence stringvec; typedef sequence dblevec; + interface MASCARET: Engines::Superv_Component + { + /** + * @brief Execute a computation of a complete Mascaret case. + * + * The Compute method realizes the computation with the files specified in input. The + * variables outputVars are extracted in output and returned in outputValues. + * + * @param fileList the list of Mascaret files describing the case to compute + * @param ligFile the file containing the initial water line + * @param outputVars the list of the output variables to extract + * @param outputValues the extracted values + */ + void Compute(in MascaretFileList fileList, in string ligFile, + in stringvec outputVars, out dblevec outputValues) + raises (SALOME::SALOME_Exception); + + /** + * @brief Initialize the component with the Mascaret case. + * + * The Init method prepares the component for a series of computation with + * the method Exec or ExecStep. It extracts the deterministic data from Salome study and + * stores this data along with the lists of input and output variables to + * identify them in future calls to Exec. + * + * @param studyID the identifier of the study containing the deterministic data + * @param detCaseEntry the identifier of the deterministic case within the study + */ + void Init(in long studyID, in SALOMEDS::ID detCaseEntry) + raises (SALOME::SALOME_Exception); + + /** + * @brief Execute a computation with a given sample of variables. + * + * The Exec method realizes the computation with the probabilistic variables + * described in paramInput and the deterministic variables set previously with + * the Init method. The result is put in paramOutput in the order specified by + * paramInput.outputVarList. + * + * @param paramInput a structure describing the probabilistic variables and the order + * of the output variables. + * @param paramOutput a structure containing the result of the computation + */ + void Exec(in SALOME_TYPES::ParametricInput paramInput, + out SALOME_TYPES::ParametricOutput paramOutput) + raises (SALOME::SALOME_Exception); + + /** + * @brief Initialize the border(s) for coupling + * + * @param borders structure describing the borders + */ + void InitBorders(in Engines::fileBlock borders) + raises (SALOME::SALOME_Exception); + + /** + * @brief Compute a single time step + * + * @param timeData the data describing the time step to execute + * @param inputData the state data coming from the coupled code + * @param outputData the data to send to the coupled code + */ + void ExecStep(in Engines::fileBlock timeData, + in Engines::fileBlock inputData, + out Engines::fileBlock outputData) + raises (SALOME::SALOME_Exception); + + /** + * @brief Cleanup everything that was previously set + * + * The Finalize method is in charge of cleaning everything that what set hitherto. + * It may be empty. + */ + void Finalize() + raises (SALOME::SALOME_Exception); + + /** + * @brief Old coupling method with datastream. + */ + void ExecCoupling(in stringvec inputVarList, in stringvec outputVarList) + raises (SALOME::SALOME_Exception); + + /** + * @brief Old method to log values from datastream coupling. + */ + void Log(in long studyID, in stringvec inputVarList) + raises (SALOME::SALOME_Exception); + + }; + + interface TELEMAC2D: Engines::Superv_Component + { + /** + * @brief Execute a computation of a complete Telemac2D case. + * + * The Compute method realizes the computation of the case specified in input. + * + * @param studyID the identifier of the study containing Telemac2D case data + * @param caseEntry the identifier of the Telemac2D case within the study + */ + void Compute(in long studyID, in SALOMEDS::ID caseEntry) + raises (SALOME::SALOME_Exception); + + /** + * @brief Initialize the component with the Telemac2D case. + * + * The Init method prepares the component for a series of computation with + * the method Exec or ExecStep. It extracts the deterministic data from Salome study and + * stores this data along with the lists of input and output variables to + * identify them in future calls to Exec. + * + * @param studyID the identifier of the study containing Telemac2D case data + * @param caseEntry the identifier of the Telemac2D case within the study + */ + void Init(in long studyID, in SALOMEDS::ID detCaseEntry) + raises (SALOME::SALOME_Exception); + + /** + * @brief Execute a computation with a given sample of variables. + * + * The Exec method realizes the computation with the probabilistic variables + * described in paramInput and the deterministic variables set previously with + * the Init method. The result is put in paramOutput in the order specified by + * paramInput.outputVarList. + * + * @param paramInput a structure describing the probabilistic variables and the order + * of the output variables. + * @param paramOutput a structure containing the result of the computation + */ + void Exec(in SALOME_TYPES::ParametricInput paramInput, + out SALOME_TYPES::ParametricOutput paramOutput) + raises (SALOME::SALOME_Exception); + + /** + * @brief Initialize the border(s) for coupling + * + * @param borders structure describing the borders + */ + void InitBorders(in Engines::fileBlock borders) + raises (SALOME::SALOME_Exception); + + /** + * @brief Compute a single time step + * + * @param timeData the data describing the time step to execute + * @param inputData the state data coming from the coupled code + * @param outputData the data to send to the coupled code + */ + void ExecStep(in Engines::fileBlock timeData, + in Engines::fileBlock inputData, + out Engines::fileBlock outputData) + raises (SALOME::SALOME_Exception); + + /** + * @brief Cleanup everything that was previously set + * + * The Finalize method is in charge of cleaning everything that what set hitherto. + * It may be empty. + */ + void Finalize() + raises (SALOME::SALOME_Exception); + + }; + interface HYDROSOLVER: Engines::EngineComponent, SALOMEDS::Driver { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7cbaee0..ef4e69c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,3 +19,4 @@ ADD_SUBDIRECTORY(HYDRO) ADD_SUBDIRECTORY(HYDROGUI) ADD_SUBDIRECTORY(HYDROTools) ADD_SUBDIRECTORY(salome_hydro) +ADD_SUBDIRECTORY(mascaret_wrapper) diff --git a/src/HYDRO/CMakeLists.txt b/src/HYDRO/CMakeLists.txt index 1cc5dcc..e818e78 100644 --- a/src/HYDRO/CMakeLists.txt +++ b/src/HYDRO/CMakeLists.txt @@ -20,6 +20,8 @@ # scripts / static SET(_bin_SCRIPTS HYDROSOLVER.py + MASCARET.py + TELEMAC2D.py ) # --- rules --- diff --git a/src/HYDRO/MASCARET.py b/src/HYDRO/MASCARET.py new file mode 100644 index 0000000..bebfccc --- /dev/null +++ b/src/HYDRO/MASCARET.py @@ -0,0 +1,412 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +import os +import logging +import threading +import inspect +import traceback +import cPickle + +import salome +import HYDROSOLVER_ORB__POA +import SALOME_ComponentPy +import SALOME +import calcium +import dsccalcium + +from salome.kernel.logger import Logger +from salome.kernel import termcolor +logger = Logger("MASCARET", color = termcolor.BLUE) +logger.setLevel(logging.DEBUG) + +from salome.kernel.parametric.compo_utils import \ + create_input_dict, create_normal_parametric_output, create_error_parametric_output + +from salome.hydro.mascaret import Mascaret, MascaretFile +from salome.hydro.study import HydroStudyEditor + +def mascaretFileListCorbaToCpp(file_list_corba): + file_list_cpp = [] + for file_corba in file_list_corba: + file_cpp = MascaretFile() + file_cpp.fileName = file_corba.fileName + file_cpp.fileType = file_corba.fileType + file_list_cpp.append(file_cpp) + return file_list_cpp + + +class MascaretVariable: + + def __init__(self, inst, varstr): + self.inst = inst + par1 = varstr.find("(") + par2 = varstr.find(")") + self.varname = varstr[:par1] + ranges_str = varstr[par1+1:par2].split(",") + if len(ranges_str) != 3: + raise Exception('Invalid variable "%s"' % varstr) + self.ranges = [] + self.valid_for_output = True + for currange in ranges_str: + limits = currange.split("-") + if len(limits) != 1 and len(limits) != 2: + raise Exception('Invalid variable "%s"' % varstr) + limit_inf = int(limits[0]) + if len(limits) == 2: + limit_sup = int(limits[1]) + else: + limit_sup = limit_inf + newrange = range(limit_inf, limit_sup + 1) + if len(newrange) > 1: + self.valid_for_output = False + self.ranges.append(newrange) + + def get_value(self): + if not self.valid_for_output: + raise Exception('Variable "%s" is not valid as an output variable' % self.varname) + logger.debug("Getting value: getDouble(%s, %d, %d, %d)" % + (self.varname, self.ranges[0][0], self.ranges[1][0], self.ranges[2][0])) + return self.inst.getDouble(self.varname, self.ranges[0][0], self.ranges[1][0], self.ranges[2][0]) + + def set_value(self, value): + for x in self.ranges[0]: + for y in self.ranges[1]: + for z in self.ranges[2]: + logger.debug("Setting value: setDouble(%s, %d, %d, %d, %f)" % + (self.varname, x, y, z, value)) + self.inst.setDouble(self.varname, x, y, z, value) + +################################################ + +class MASCARET(HYDROSOLVER_ORB__POA.MASCARET, dsccalcium.PyDSCComponent): + + lock = threading.Lock() + + """ + Pour etre un composant SALOME cette classe Python + doit avoir le nom du composant et heriter de la + classe HYDRO_ORB__POA.MASCARET issue de la compilation de l'idl + par omniidl et de la classe SALOME_ComponentPy_i + qui porte les services generaux d'un composant SALOME + """ + def __init__ ( self, orb, poa, contID, containerName, instanceName, + interfaceName ): + logger.info("__init__: " + containerName + ' ; ' + instanceName) + dsccalcium.PyDSCComponent.__init__(self, orb, poa,contID, + containerName,instanceName,interfaceName) + self.file_list = None + self.lig_file = None + self.inst = None + self.last_start_time = None + self.state_id = None + self.initial_state_id = None + self.input_var_map = None + self.output_var_map = None + + def init_service(self,service): + if service == "ExecCoupling": + # initialization CALCIUM ports IN + calcium.create_calcium_port(self.proxy, "inputValues", "CALCIUM_double", "IN", "T") + # initialization CALCIUM ports OUT + calcium.create_calcium_port(self.proxy, "outputValues", "CALCIUM_double", "OUT", "T") + elif service == "Log": + # initialization CALCIUM ports IN + calcium.create_calcium_port(self.proxy, "inputValues", "CALCIUM_double", "IN", "T") + return service in ("Compute", "Init", "Exec", "Finalize", "ExecCoupling", "Log") + + def _raiseSalomeError(self): + message = "Error in component %s running in container %s." % (self._instanceName, self._containerName) + logger.exception(message) + message += " " + traceback.format_exc() + exc = SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR, message, + inspect.stack()[1][1], inspect.stack()[1][2]) + raise SALOME.SALOME_Exception(exc) + + def Compute(self, fileList, ligFile, outputVars): + try: + self.beginService("MASCARET.Compute") + + # Initialize + inst = Mascaret() + inst.importModel(mascaretFileListCorbaToCpp(fileList)) + inst.initState(ligFile) + + # Compute + inst.compute() + + # Get the output values + output_values = [MascaretVariable(inst, var).get_value() for var in outputVars] + + self.endService("MASCARET.Compute") + return output_values + except: + self._raiseSalomeError() + + def Init(self, studyId, detCaseEntry): + try: + self.beginService("MASCARET.Init") + MASCARET.lock.acquire() + salome.salome_init() + MASCARET.lock.release() + + ed = HydroStudyEditor(studyId) + sobj = ed.editor.study.FindObjectID(detCaseEntry) + (file_list_corba, self.lig_file, input_vars, output_vars) = ed.get_mascaret_params_from_case(sobj) + + self.file_list = mascaretFileListCorbaToCpp(file_list_corba) + + # Initialize Mascaret instance + self.inst = Mascaret() + #self.inst.setPrinting(True) + self.inst.importModel(self.file_list) + self.inst.initState(self.lig_file) + + # Create variable mappings + self.input_var_map = {} + for input_var in input_vars: + name = input_var["NOM"] + if not self.input_var_map.has_key(name): + self.input_var_map[name] = [] + self.input_var_map[name] += [MascaretVariable(self.inst, input_var["VARIABLE_MASCARET"])] + + self.output_var_map = {} + for output_var in output_vars: + masc_output_var = MascaretVariable(self.inst, output_var["VARIABLE_MASCARET"]) + self.output_var_map[output_var["NOM"]] = masc_output_var + + self.endService("MASCARET.Init") + except: + self._raiseSalomeError() + + def Exec(self, paramInput): + try: + self.beginService("MASCARET.Exec") + + if self.initial_state_id is not None: + self.inst.restoreState(self.initial_state_id) + self.initial_state_id = self.inst.saveState() + + logger.debug("inputVarList: %s" % paramInput.inputVarList) + logger.debug("outputVarList: %s" % paramInput.outputVarList) + logger.debug("inputValues: %s" % paramInput.inputValues) + + input_dict = create_input_dict({}, paramInput) + logger.debug("input_dict = %s" % input_dict) + + for (key, value) in input_dict.iteritems(): + for masc_var in self.input_var_map[key]: + masc_var.set_value(value) + + # Compute + self.inst.compute() + + # Get the output values + output_dict = {} + for output_var in paramInput.outputVarList: + output_dict[output_var] = self.output_var_map[output_var].get_value() + + param_output = create_normal_parametric_output(output_dict, paramInput) + logger.debug("outputValues: %s" % param_output.outputValues) + self.endService("MASCARET.Exec") + return param_output + except: + self._raiseSalomeError() + + def InitBorders(self, bordersPickled): + """ + This method initializes the border(s) for coupling + """ + try: + self.beginService("MASCARET.InitBorders") + borders = cPickle.loads(bordersPickled) + self.borders = {} + for border in borders: + if border["model1"] is not None and border["model1"]["code"] == "MASCARET": + self.borders[border["name"]] = border["model1"] + elif border["model2"] is not None and border["model2"]["code"] == "MASCARET": + self.borders[border["name"]] = border["model2"] + self.endService("MASCARET.InitBorders") + except: + self._raiseSalomeError() + + def setData(self, inputData): + if inputData is not None: + for (name, desc) in self.borders.iteritems(): + if name in inputData: + if desc["position"] == "upstream": + if self.froude[name] < 1.0: + Z = inputData[name]["Z"] + self.inst.setDouble("Modele.Lois.Cote", desc["loi_id"], 1, 0, Z) + self.inst.setDouble("Modele.Lois.Cote", desc["loi_id"], 2, 0, Z) + else: + Q = inputData[name]["Q"] + self.inst.setDouble("Modele.Lois.Debit", desc["loi_id"], 1, 0, Q) + self.inst.setDouble("Modele.Lois.Debit", desc["loi_id"], 2, 0, Q) + if self.froude[name] >= 1.0: + Z = inputData[name]["Z"] + self.inst.setDouble("Modele.Lois.Cote", desc["loi_id"], 1, 0, Z) + self.inst.setDouble("Modele.Lois.Cote", desc["loi_id"], 2, 0, Z) + + def ExecStep(self, timeDataPickled, inputDataPickled): + """ + This method computes a single time step + """ + try: + self.beginService("MASCARET.ExecStep") + timeData = cPickle.loads(timeDataPickled) + inputData = cPickle.loads(inputDataPickled) + + if self.last_start_time is not None: + self.inst.restoreState(self.state_id) + # If it's a new time step, we perform a last iteration with + # the last time step to restore the state properly + if self.last_start_time != timeData["start_time"]: + self.setData(inputData) + self.inst.compute(self.last_start_time, timeData["start_time"], timeData["time_step"]) + + self.last_start_time = timeData["start_time"] + self.state_id = self.inst.saveState() + + self.setData(inputData) + + # Computation + self.inst.compute(timeData["start_time"], timeData["end_time"], timeData["time_step"]) + + # Get the output values + outputData = {} + self.froude = {} + for (name, desc) in self.borders.iteritems(): + Z = self.inst.getDouble("Etat.Z", desc["section_id"], 0, 0) + Q1 = self.inst.getDouble("Etat.Q1", desc["section_id"], 0, 0) + S1 = self.inst.getDouble("Etat.S1", desc["section_id"], 0, 0) + V = Q1/S1 + #V = self.inst.getDouble("Etat.V1", desc["section_id"], 0, 0) + Q = self.inst.getDouble("Etat.Q", desc["section_id"], 0, 0) + Froude = self.inst.getDouble("Etat.Froude", desc["section_id"], 0, 0) + outputData[name] = {"Z": Z, "V": V, "Froude": Froude, "Q": Q} + self.froude[name] = Froude + outputDataPickled = cPickle.dumps(outputData, -1) + + self.endService("MASCARET.ExecStep") + return outputDataPickled + except: + self._raiseSalomeError() + + def Finalize(self): + try: + self.beginService("MASCARET.Finalize") + self.file_list = None + self.lig_file = None + self.inst = None + self.last_start_time = None + self.state_id = None + self.input_var_map = None + self.output_var_map = None + self.endService("MASCARET.Finalize") + except: + self._raiseSalomeError() + + def ExecCoupling(self, inputVarList, outputVarList): + try: + self.beginService("MASCARET.ExecCoupling") + component = self.proxy + + # Get time data from model + start_time = self.inst.getDouble("Modele.TempsInitial", 0, 0, 0) + end_time = self.inst.getDouble("Modele.TempsMaximum", 0, 0, 0) + time_step = self.inst.getDouble("Modele.DT", 0, 0, 0) + + # Time loop + current_time = start_time + calcium.cp_cd(component) + while current_time < end_time: + # Send data + if len(outputVarList) > 0: + output_values = [] + for output_var in outputVarList: + masc_var = self.output_var_map[output_var] + value = self.inst.getDouble(*split_var(masc_var)) + output_values += [value] + info = calcium.cp_edb(component, calcium.CP_TEMPS, current_time, 0, "outputValues", + len(outputVarList), output_values) + logger.debug("Instance %s sent %s" % (self._instanceName, zip(outputVarList, output_values))) + if info != 0: + raise Exception("Error in calcium.cp_edb, code = %d" % info) + + # Receive data + input_values = calcium.doubleArray(len(inputVarList)) + if len(inputVarList) > 0: + (info, t, ii, n) = calcium.cp_ldb(component, calcium.CP_TEMPS, + current_time, current_time + 1e-6, + 0, "inputValues", len(inputVarList), input_values) + if info != 0: + raise Exception("Error in calcium.cp_ldb, code = %d" % info) + if n != len(inputVarList): + raise Exception("Wrong number of input values: %d instead of %d" % (n, len(inputVarList))) + logger.debug("Instance %s received %s" % (self._instanceName, zip(inputVarList, input_values))) + + # Update model with received data + for (var, value) in zip(inputVarList, input_values): + for masc_var in self.input_var_map[var]: + self.inst.setDouble(*(split_var(masc_var) + (value,))) + + # Compute + end_step_time = current_time + time_step + self.inst.compute(current_time, end_step_time, time_step) + current_time = end_step_time + + calcium.cp_fin(component, calcium.CP_ARRET) + self.endService("MASCARET.ExecCoupling") + except: + self._raiseSalomeError() + + def Log(self, studyId, inputVarList): + """ + This method is not used anymore. It was used in the context of the calcium coupling test. + """ + try: + self.beginService("MASCARET.Log") + if len(inputVarList) > 0: + log = {} + for var in inputVarList: + log[var] = "" + component = self.proxy + finished = False + calcium.cp_cd(component) + while not finished: + # Receive data + input_values = calcium.doubleArray(len(inputVarList)) + (info, t, ii, n) = calcium.cp_ldb(component, calcium.CP_SEQUENTIEL, + 0, 0, 0, "inputValues", len(inputVarList), input_values) + if info == 33: + finished = True + elif info != 0: + raise Exception("Error in calcium.cp_ldb, code = %d" % info) + elif n != len(inputVarList): + raise Exception("Wrong number of input values: %d instead of %d" % (n, len(inputVarList))) + else: + logger.debug("Instance %s received %s" % (self._instanceName, zip(inputVarList, input_values))) + for (var, value) in zip(inputVarList, input_values): + log[var] += "t = %f, %s = %f\n" % (t, var, value) + calcium.cp_fin(component, calcium.CP_ARRET) + ed = HydroStudyEditor(studyId) + for var in inputVarList: + ed.add_coupling_log(var, log[var]) + self.endService("MASCARET.Log") + except: + self._raiseSalomeError() diff --git a/src/HYDRO/TELEMAC2D.py b/src/HYDRO/TELEMAC2D.py new file mode 100644 index 0000000..85f1f01 --- /dev/null +++ b/src/HYDRO/TELEMAC2D.py @@ -0,0 +1,579 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +import sys +import os +import logging +import threading +import inspect +import traceback +import cPickle +import math +import types + +import salome +import HYDROSOLVER_ORB__POA +import SALOME_ComponentPy +import SALOME +import calcium +import dsccalcium + +from salome.kernel.logger import Logger +from salome.kernel import termcolor +logger = Logger("TELEMAC2D", color = termcolor.BLUE) +logger.setLevel(logging.DEBUG) + +from salome.kernel.parametric.compo_utils import \ + create_input_dict, create_normal_parametric_output, create_error_parametric_output + +from TelApy.api.t2d import Telemac2D +from TelApy.tools.polygon import get_list_points_in_polygon +from salome.hydro.study import jdc_to_dict, get_jdc_dict_var_as_tuple, HydroStudyEditor + +################################################ + +class TELEMAC2D(HYDROSOLVER_ORB__POA.TELEMAC2D, dsccalcium.PyDSCComponent): + + lock = threading.Lock() + + """ + Pour etre un composant SALOME cette classe Python + doit avoir le nom du composant et heriter de la + classe HYDRO_ORB__POA.MASCARET issue de la compilation de l'idl + par omniidl et de la classe SALOME_ComponentPy_i + qui porte les services generaux d'un composant SALOME + """ + def __init__ ( self, orb, poa, contID, containerName, instanceName, + interfaceName ): + logger.info("__init__: " + containerName + ' ; ' + instanceName) + dsccalcium.PyDSCComponent.__init__(self, orb, poa,contID, + containerName,instanceName,interfaceName) + self.t2d = None + self.last_start_time = None + self.saved_state = None + + def init_service(self,service): + return service in ("Compute",) + + def _raiseSalomeError(self): + message = "Error in component %s running in container %s." % (self._instanceName, self._containerName) + logger.exception(message) + message += " " + traceback.format_exc() + exc = SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR, message, + inspect.stack()[1][1], inspect.stack()[1][2]) + raise SALOME.SALOME_Exception(exc) + + def Init(self, studyId, detCaseEntry): + try: + self.beginService("TELEMAC2D.Init") + self.jdc_dict = self.get_jdc_dict_from_case(studyId, detCaseEntry) + + # Ugly hack to check if we are in OpenTURNS context or Mascaret coupling context + if "VARIABLE_ENTREE" in self.jdc_dict: + # Create variable mappings for OpenTURNS + self.input_var_map = {} + for input_var in get_jdc_dict_var_as_tuple(self.jdc_dict, "VARIABLE_ENTREE"): + name = input_var["NOM"] + if not self.input_var_map.has_key(name): + self.input_var_map[name] = [] + self.input_var_map[name] += [Telemac2DInputVariable(input_var["VARIABLE_MODELE_T2D"])] + + self.output_var_map = {} + for output_var in get_jdc_dict_var_as_tuple(self.jdc_dict, "VARIABLE_SORTIE"): + t2d_output_var = Telemac2DOutputVariable(output_var["VARIABLE_T2D"]) + self.output_var_map[output_var["NOM"]] = t2d_output_var + + else: + # Initialize before launching the coupling with Mascaret + self.init_t2d_from_jdc_dict(self.jdc_dict) + + self.endService("TELEMAC2D.Init") + except: + self._raiseSalomeError() + + def get_jdc_dict_from_case(self, study_id, case_entry): + TELEMAC2D.lock.acquire() + salome.salome_init() + TELEMAC2D.lock.release() + + # Get filenames from the case in Salome study + ed = HydroStudyEditor(study_id) + sobj = ed.editor.study.FindObjectID(case_entry) + jdcpath = sobj.GetComment() + with open(jdcpath) as jdcfile: + jdc = jdcfile.read() + return jdc_to_dict(jdc, ["TELEMAC2D", "_F"]) + + def init_t2d_from_jdc_dict(self, jdc_dict): + steering_filename = jdc_dict["FICHIER_CAS"] + user_fortran = jdc_dict.get("FICHIER_FORTRAN_UTILISATEUR") + dico_filename = jdc_dict.get("FICHIER_DICO") + geo_filename = jdc_dict.get("FICHIER_GEOMETRIE") + bc_filename = jdc_dict.get("FICHIER_CONDITIONS_LIMITES") + result_filename = jdc_dict.get("RESULTAT") + + logger.debug("Initializing Telemac2D API") + self.t2d = Telemac2D(user_fortran) + logger.debug("Telemac2D API initialization OK") + os.chdir(os.path.dirname(steering_filename)) + self.t2d.run_read_case_t2d(steering_filename, dico_filename) + if bc_filename is not None: + self.t2d.set_string('MODEL.BCFILE', bc_filename) + if geo_filename is not None: + self.t2d.set_string('MODEL.GEOMETRYFILE', geo_filename) + if result_filename is not None: + self.t2d.set_string('MODEL.RESULTFILE', result_filename) + ierr = self.t2d.api.run_allocation_t2d(self.t2d.id) + if ierr != 0: + raise Exception('Error in run_allocation_t2d:', ierr) + ierr = self.t2d.api.run_init_t2d(self.t2d.id) + if ierr != 0: + raise Exception('Error in run_init_t2d:', ierr) + + def Exec(self, paramInput): + try: + self.beginService("TELEMAC2D.Exec") + + # Save / restore state + # Not used yet because time can not be reset + #if self.saved_state is None: + # self.saved_state = self.t2d.save_state() + #else: + # self.t2d.restore_state(self.saved_state) + + # Get id and execution mode + id = "" + exec_mode = "" + for parameter in paramInput.specificParameters: + if parameter.name == "id": + id = parameter.value + if parameter.name == "executionMode": + exec_mode = parameter.value + logger.debug("ID: %s" % id) + logger.debug("Execution mode: %s" % exec_mode) + + # Append id to result file name + result_filename = self.jdc_dict.get("RESULTAT") or "r2d.slf" + (result_filename_wo_ext, ext) = os.path.splitext(result_filename) + current_jdc_dict = self.jdc_dict.copy() + current_jdc_dict["RESULTAT"] = "%s_%s%s" % (result_filename_wo_ext, id, ext) + + # Reload model + self.init_t2d_from_jdc_dict(current_jdc_dict) + + # Set the input values + logger.debug("inputVarList: %s" % paramInput.inputVarList) + logger.debug("outputVarList: %s" % paramInput.outputVarList) + logger.debug("inputValues: %s" % paramInput.inputValues) + + input_dict = create_input_dict({}, paramInput) + logger.debug("input_dict = %s" % input_dict) + + for (key, value) in input_dict.iteritems(): + for t2d_var in self.input_var_map[key]: + t2d_var.set_value(self.t2d, value) + + # Compute + self.t2d.run_all_timesteps() + + # Get the output values + output_dict = {} + for output_var in paramInput.outputVarList: + output_dict[output_var] = self.output_var_map[output_var].get_value(self.t2d) + + param_output = create_normal_parametric_output(output_dict, paramInput) + logger.debug("outputValues: %s" % param_output.outputValues) + + # Finalize T2D + self.t2d.finalize() + self.t2d = None + + self.endService("TELEMAC2D.Exec") + return param_output + except: + self._raiseSalomeError() + + def InitBorders(self, bordersPickled): + """ + This method initializes the border(s) for coupling + """ + try: + self.beginService("TELEMAC2D.InitBorders") + borders = cPickle.loads(bordersPickled) + self.borders = {} + for border in borders: + if border["model1"] is not None and border["model1"]["code"] == "TELEMAC2D": + self.borders[border["name"]] = border["model1"] + elif border["model2"] is not None and border["model2"]["code"] == "TELEMAC2D": + self.borders[border["name"]] = border["model2"] + self.endService("TELEMAC2D.InitBorders") + except: + self._raiseSalomeError() + + def ExecStep(self, timeDataPickled, inputDataPickled): + """ + This method computes a single time step + """ + try: + self.beginService("TELEMAC2D.ExecStep") + timeData = cPickle.loads(timeDataPickled) + inputData = cPickle.loads(inputDataPickled) + + if timeData["start_time"] == self.last_start_time: + # Convergence iteration, restore saved state + self.t2d.restore_state(self.saved_state) + else: + # First iteration of a time step, save state + self.saved_state = self.t2d.save_state(self.saved_state) + + self.last_start_time = timeData["start_time"] + + if inputData is not None: + for (name, desc) in self.borders.iteritems(): + if name in inputData: + z = None + v = None + q = None + if desc["position"] == "upstream": + if inputData[name]["Froude"] < 1.0: # Fluvial + z = inputData[name]["Z"] + else: + v = inputData[name]["V"] + q = inputData[name]["Q"] + if inputData[name]["Froude"] > 1.0: # Torrential + z = inputData[name]["Z"] + self.set_z_on_border(desc, z) + #self.set_v_on_border(desc, v) + self.set_q_on_border(desc, q) + + # Compute + # TODO: Use time values from coupling + ierr = self.t2d.api.run_timestep_t2d(self.t2d.id) + if ierr != 0: + raise Exception('Error in run_timestep_t2d:', ierr) + + # Get the output values + outputData = {} + for (name, desc) in self.borders.iteritems(): + outputData[name] = {} + (outputData[name]["Z"], idx) = self.get_z_on_border(desc) + if idx is None: + outputData[name]["V"] = 0.0 + else: + (outputData[name]["V"], froude) = self.get_v_at_point(idx) + outputData[name]["Q"] = self.get_q_on_border(desc) + outputDataPickled = cPickle.dumps(outputData, -1) + + self.endService("TELEMAC2D.ExecStep") + return outputDataPickled + except: + self._raiseSalomeError() + + def get_z_on_border(self, border): + """ + Find the water elevation (i.e. water height + bottom elevation) on a border. + Return a tuple (water_elevation, index_of_model_point_with_min_water_elevation). + If we use method 2 (compute mean water elevation), index is set to None. + """ + # Method 1: Get point with minimum elevation + """ + idx = -1 + bor_idx = -1 + z_min = sys.float_info.max + (first, after_last) = border["points_id"] + k = first + while k != after_last: + nbor_k = self.t2d.get_integer('MODEL.NBOR', k) + h_k = self.t2d.get_double('MODEL.WATERDEPTH', nbor_k) + z_bottom_k = self.t2d.get_double('MODEL.BOTTOMELEVATION', nbor_k) + z_k = h_k + z_bottom_k + logger.debug("extract z for border point %d, h:%f, zf:%f, z:%f" % (k, h_k, z_bottom_k, z_k)) + if (z_k < z_min): + z_min = z_k + bor_idx = k + idx = nbor_k + k = self.t2d.get_integer('MODEL.KP1BOR', k) + logger.debug("min z for border %d with method 1 is %f at border point %d (model point %d)" % + (border["border_id"], z_min, bor_idx, idx)) + z = z_min + """ + # Method 2: Compute mean elevation, ignoring dry zones (method from PALM coupling) + z_mean = sys.float_info.max + for i in range(10): + h_tot = 0.0 + l_tot = 0.0 + zf_min = sys.float_info.max + (first, after_last) = border["points_id"] + k = first + while k != after_last: + knext = self.t2d.get_integer('MODEL.KP1BOR', k) + nbor_k = self.t2d.get_integer('MODEL.NBOR', k) + nbor_knext = self.t2d.get_integer('MODEL.NBOR', knext) + zf1 = self.t2d.get_double('MODEL.BOTTOMELEVATION', nbor_k) + zf2 = self.t2d.get_double('MODEL.BOTTOMELEVATION', nbor_knext) + zf_min = min(zf_min, zf1) + h1 = self.t2d.get_double('MODEL.WATERDEPTH', nbor_k) + h2 = self.t2d.get_double('MODEL.WATERDEPTH', nbor_knext) + z1 = h1 + zf1 + z2 = h2 + zf2 + x1 = self.t2d.get_double('MODEL.X', nbor_k) + x2 = self.t2d.get_double('MODEL.X', nbor_knext) + y1 = self.t2d.get_double('MODEL.Y', nbor_k) + y2 = self.t2d.get_double('MODEL.Y', nbor_knext) + l = math.sqrt((x1-x2)**2 + (y1-y2)**2) + if zf1 <= z_mean and zf2 <= z_mean: + h_tot += (z1+z2) * 0.5 * l + l_tot += l + k = knext + + new_z_mean = h_tot / l_tot + delta = abs(z_mean - new_z_mean) + z_mean = new_z_mean + if delta < 1.0e-6: + break + + logger.debug("mean z for border %d with method 2 is %f" % (border["border_id"], z_mean)) + z = z_mean + idx = None + + return (z, idx) + + def get_v_at_point(self, idx): + """ + Find the water velocity at the model point idx. + Return a tuple (velocity, froude number) + """ + u_i = self.t2d.get_double('MODEL.VELOCITYU', idx) + v_i = self.t2d.get_double('MODEL.VELOCITYV', idx) + h_i = self.t2d.get_double('MODEL.WATERDEPTH', idx) + v = math.sqrt(u_i**2 + v_i**2) + ##### TODO: Remove that and find the real error + if h_i <= 0.0: + print 'Error: water depth is negative or zero on point', idx + #raise Exception('Null water depth value') + h_i = 0.01 + froude = v / (h_i * 9.81) + return (v, froude) + + def get_q_on_border(self, border): + """ + Find the flow on a border. + The returned value is positive if the flow goes in the natural direction + according to the borders description (from upstream to downstream). + """ + # Method 1: Integrate the flow on the whole border + """ + q = 0.0 + (first, after_last) = border["points_id"] + k = first + while k != after_last: + knext = self.t2d.get_integer('MODEL.KP1BOR', k) + nbor_k = self.t2d.get_integer('MODEL.NBOR', k) + nbor_knext = self.t2d.get_integer('MODEL.NBOR', knext) + h_i = self.t2d.get_double('MODEL.WATERDEPTH', nbor_k) + h_i2 = self.t2d.get_double('MODEL.WATERDEPTH', nbor_knext) + h2d1 = 0.5 * (h_i + h_i2) + if (h2d1 > 0.0): + u_i = self.t2d.get_double('MODEL.VELOCITYU', nbor_k) + u_i2 = self.t2d.get_double('MODEL.VELOCITYU', nbor_knext) + v_i = self.t2d.get_double('MODEL.VELOCITYV', nbor_k) + v_i2 = self.t2d.get_double('MODEL.VELOCITYV', nbor_knext) + v2d1 = 0.5 * (math.sqrt(u_i**2+v_i**2) + math.sqrt(u_i2**2+v_i2**2)) + x2d1 = self.t2d.get_double('MODEL.X', nbor_k) + x2d2 = self.t2d.get_double('MODEL.X', nbor_knext) + y2d1 = self.t2d.get_double('MODEL.Y', nbor_k) + y2d2 = self.t2d.get_double('MODEL.Y', nbor_knext) + q += v2d1 * h2d1 * math.sqrt((x2d1-x2d2)**2 + (y2d1-y2d2)**2) + k = knext + logger.debug("flow for border %d with method 1 is %f" % (border["border_id"], q)) + + # Method 2: Get the flow from Telemac model + q = self.t2d.get_double('MODEL.FLUX_BOUNDARIES', border["border_id"]) + if border["position"] == "downstream": + q = -q + logger.debug("flow for border %d with method 2 is %f" % (border["border_id"], q)) + """ + + # Method 3: Method from PALM coupling + q = 0.0 + (first, after_last) = border["points_id"] + k = first + while k != after_last: + knext = self.t2d.get_integer('MODEL.KP1BOR', k) + nbor_k = self.t2d.get_integer('MODEL.NBOR', k) + nbor_knext = self.t2d.get_integer('MODEL.NBOR', knext) + h_i = self.t2d.get_double('MODEL.WATERDEPTH', nbor_k) + h_i2 = self.t2d.get_double('MODEL.WATERDEPTH', nbor_knext) + u_i = self.t2d.get_double('MODEL.VELOCITYU', nbor_k) + u_i2 = self.t2d.get_double('MODEL.VELOCITYU', nbor_knext) + v_i = self.t2d.get_double('MODEL.VELOCITYV', nbor_k) + v_i2 = self.t2d.get_double('MODEL.VELOCITYV', nbor_knext) + x2d1 = self.t2d.get_double('MODEL.X', nbor_k) + x2d2 = self.t2d.get_double('MODEL.X', nbor_knext) + y2d1 = self.t2d.get_double('MODEL.Y', nbor_k) + y2d2 = self.t2d.get_double('MODEL.Y', nbor_knext) + NX=y2d1-y2d2 + NY=x2d2-x2d1 + UN1=u_i*NX+v_i*NY + UN2=u_i2*NX+v_i2*NY + q += ((h_i+h_i2)*(UN1+UN2)+h_i2*UN2+h_i*UN1)/6.0 + k = knext + if border["position"] == "upstream": + q = -q + logger.debug("flow for border %d with method 3 is %f" % (border["border_id"], q)) + + return q + + def set_z_on_border(self, border, z): + """ + Set the water elevation (i.e. water height + bottom elevation) on a border. + If z is None, then the water elevation for this border is free (not imposed). + """ + # Method 1: Impose water elevation point by point + """ + # Deactivate water level imposition in bord.f (requires a patch in bord.f) + self.t2d.set_double('MODEL.COTE', -1.0, border["border_id"]) + + (first, after_last) = border["points_id"] + k = first + while k != after_last: + if z is None: + self.t2d.set_integer('MODEL.LIHBOR', 4, k) # Free elevation on that border + else: + self.t2d.set_integer('MODEL.LIHBOR', 5, k) # Imposed elevation on that border + nbor_k = self.t2d.get_integer('MODEL.NBOR', k) + bottom_elevation = self.t2d.get_double('MODEL.BOTTOMELEVATION', nbor_k) + hbor_k = max(0.0, z - bottom_elevation) + self.t2d.set_double('MODEL.HBOR', hbor_k, k) + logger.debug("set z for border point %d, h:%f, zf:%f, z:%f" % (k, hbor_k, bottom_elevation, z)) + k = self.t2d.get_integer('MODEL.KP1BOR', k) + """ + + # Method 2: Just tell Telemac what is the imposed elevation for the border + if z is not None: + self.t2d.set_double('MODEL.COTE', z, border["border_id"]) + (first, after_last) = border["points_id"] + k = first + while k != after_last: + if z is None: + self.t2d.set_integer('MODEL.LIHBOR', 4, k) # Free elevation on that border + else: + self.t2d.set_integer('MODEL.LIHBOR', 5, k) # Imposed elevation on that border + k = self.t2d.get_integer('MODEL.KP1BOR', k) + + def set_v_on_border(self, border, v): + """ + Set the water velocity on a border. + If v is None, then the water velocity for this border is free (not imposed). + """ + # This method works only if the water level imposition is deactivated in bord.f + # (requires a patch in bord.f) + (first, after_last) = border["points_id"] + k = first + while k != after_last: + if v is None: + self.t2d.set_integer('MODEL.LIUBOR', 4, k) # Free velocity on that border + self.t2d.set_integer('MODEL.LIVBOR', 4, k) + else: + self.t2d.set_integer('MODEL.LIUBOR', 6, k) # Imposed velocity on that border + self.t2d.set_integer('MODEL.LIVBOR', 6, k) + xnebor_k = self.t2d.get_double('MODEL.XNEBOR', k) + ubor_k = -xnebor_k * v + ynebor_k = self.t2d.get_double('MODEL.YNEBOR', k) + vbor_k = -ynebor_k * v + self.t2d.set_double('MODEL.UBOR', ubor_k, k) + self.t2d.set_double('MODEL.VBOR', vbor_k, k) + k = self.t2d.get_integer('MODEL.KP1BOR', k) + + def set_q_on_border(self, border, q): + """ + Set the water flow on a border. + If q is None, then the water flow for this border is free (not imposed). + """ + if q is not None: + self.t2d.set_double('MODEL.DEBIT', q, border["border_id"]) + logger.debug("flow for border %d is set to %f" % (border["border_id"], q)) + (first, after_last) = border["points_id"] + k = first + while k != after_last: + if q is None: + self.t2d.set_integer('MODEL.LIUBOR', 4, k) # Free velocity on that border + self.t2d.set_integer('MODEL.LIVBOR', 4, k) + else: + self.t2d.set_integer('MODEL.LIUBOR', 5, k) # Imposed discharge on that border + self.t2d.set_integer('MODEL.LIVBOR', 5, k) + k = self.t2d.get_integer('MODEL.KP1BOR', k) + + def Finalize(self): + try: + self.beginService("TELEMAC2D.Finalize") + if self.t2d: + self.t2d.finalize() + self.t2d = None + self.endService("TELEMAC2D.Finalize") + except: + self._raiseSalomeError() + + def Compute(self, studyId, caseEntry): + try: + self.beginService("TELEMAC2D.Compute") + + jdc_dict = self.get_jdc_dict_from_case(studyId, caseEntry) + self.init_t2d_from_jdc_dict(jdc_dict) + + # Compute + self.t2d.run_all_timesteps() + + # Cleanup + self.t2d.finalize() + + self.endService("TELEMAC2D.Compute") + except: + self._raiseSalomeError() + + +class Telemac2DOutputVariable: + + def __init__(self, varstr): + par1 = varstr.find("(") + par2 = varstr.find(")") + self.varname = varstr[:par1] + self.idx = int(varstr[par1+1:par2]) + + def get_value(self, inst): + return inst.get_double(self.varname, self.idx) + + +class Telemac2DInputVariable: + + def __init__(self, vardict): + self.varname = vardict["NOM_VARIABLE_MODELE"] + def_area_dict = vardict["ZONE_DE_DEFINITION"] + self.idx = def_area_dict.get("INDICE") + self.polygon = def_area_dict.get("POLYGONE") + self.points_in_polygon_list = None + + def set_value(self, inst, value): + if self.idx is not None: + inst.set_double(self.varname, value, self.idx) + elif self.polygon is not None: + if self.points_in_polygon_list is None: + self.points_in_polygon_list = get_list_points_in_polygon(inst, self.polygon) + for idx in self.points_in_polygon_list: + inst.set_double(self.varname, value, idx) + else: + raise Exception("Invalid area definition for input variable {0}".format(self.varname)) diff --git a/src/mascaret_wrapper/CMakeLists.txt b/src/mascaret_wrapper/CMakeLists.txt new file mode 100644 index 0000000..a84cb5b --- /dev/null +++ b/src/mascaret_wrapper/CMakeLists.txt @@ -0,0 +1,67 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +INCLUDE(${SWIG_USE_FILE}) + +# --- options --- + +# additional include directories +INCLUDE_DIRECTORIES( + ${PYTHON_INCLUDE_DIRS} + ${MASCARET_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# swig flags +SET_SOURCE_FILES_PROPERTIES(mascaret_swig.i PROPERTIES + CPLUSPLUS ON + SWIG_DEFINITIONS "-shadow") + +# additional preprocessor / compiler flags +ADD_DEFINITIONS( + ${PYTHON_DEFINITIONS} + ) + +# libraries to link to +SET(_link_LIBRARIES + ${PYTHON_LIBRARIES} + ${MASCARET_LIBRARIES} + ) + +# --- sources --- +SET(mascaret_SOURCES + Mascaret.cxx + ) +# --- headers --- +SET(mascaret_HEADERS + Mascaret.hxx + ) + +# --- scripts --- +# scripts / swig wrappings +SET(_swig_SCRIPTS + ${CMAKE_CURRENT_BINARY_DIR}/mascaret_swig.py +) + +# --- rules --- +SWIG_ADD_MODULE(mascaret_swig python mascaret_swig.i ${mascaret_SOURCES}) +SWIG_LINK_LIBRARIES(mascaret_swig "${_link_LIBRARIES}") + +SET(mypkgpythondir ${SALOME_INSTALL_PYTHON}/salome/hydro/mascaret) + +INSTALL(TARGETS ${SWIG_MODULE_mascaret_swig_REAL_NAME} DESTINATION ${mypkgpythondir}) +SALOME_INSTALL_SCRIPTS("${_swig_SCRIPTS}" ${mypkgpythondir}) diff --git a/src/mascaret_wrapper/Mascaret.cxx b/src/mascaret_wrapper/Mascaret.cxx new file mode 100644 index 0000000..db999b0 --- /dev/null +++ b/src/mascaret_wrapper/Mascaret.cxx @@ -0,0 +1,225 @@ +// Copyright (C) 2012-2013 EDF +// +// This file is part of SALOME HYDRO module. +// +// SALOME HYDRO module is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// SALOME HYDRO 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SALOME HYDRO module. If not, see . + +#include +#include +#include +#include + +extern "C" +{ +#include +} + +#include "Mascaret.hxx" + +using namespace std; + +namespace SalomeHydro +{ + +char * createPChar(const string & str) +{ + char * data = new char[str.size() + 1]; + strcpy(data, str.c_str()); + return data; +} + + +class CString +{ +public: + + CString(const string & str) + { + _data = createPChar(str); + } + + virtual ~CString() + { + delete[] _data; + } + + operator char *() + { + return _data; + } + +private: + char * _data; +}; + + +MascaretException::MascaretException(const std::string & msg) + : runtime_error(msg) +{ +} + +MascaretException::~MascaretException() throw() +{ +} + +const char * MascaretException::__str__() const +{ + return what(); +} + +Mascaret::Mascaret() + : _id(-1), + _printing(false) +{ + // Initialize model + int res = C_CREATE_MASCARET(&_id); + testMascaretResult(res, "C_CREATE_MASCARET"); +} + + +Mascaret::~Mascaret() +{ + // Delete the model + int res = C_DELETE_MASCARET(_id); + testMascaretResult(res, "C_DELETE_MASCARET"); +} + + +void Mascaret::testMascaretResult(int res, const string & functionName) +{ + if (res != 0) + { + char * mascErrorMsg; + C_GET_ERREUR_MASCARET(_id, &mascErrorMsg); + ostringstream msg; + msg << "Mascaret error:" << endl; + msg << " Function: " << functionName << endl; + msg << " Message: " << mascErrorMsg; + free(mascErrorMsg); + throw MascaretException(msg.str()); + } +} + + +bool Mascaret::isPrinting() +{ + return _printing; +} + + +void Mascaret::setPrinting(bool printing) +{ + _printing = printing; +} + + +void Mascaret::importModel(const MascaretFileList & fileList) +{ + // Create arrays of C strings fileArray and typeArray + char** fileArray = new char*[fileList.size()]; + char** typeArray = new char*[fileList.size()]; + for (int i=0 ; i. + +#ifndef MASCARET_HXX_ +#define MASCARET_HXX_ + +#include +#include + +namespace SalomeHydro +{ + +typedef struct MascaretFile +{ + std::string fileName; + std::string fileType; +} MascaretFile; + +typedef std::vector MascaretFileList; + +class MascaretException: public std::runtime_error +{ +public: + + MascaretException(const std::string & msg); + virtual ~MascaretException() throw(); + + const char * __str__() const; + +}; + +class Mascaret +{ +public: + + // Constructor and destructor + Mascaret(); + virtual ~Mascaret(); + + // Get and set printing flag + bool isPrinting(); + void setPrinting(bool printing); + + // Model initialization + void importModel(const MascaretFileList & fileList); + void initState(const std::string & ligFileName); + + // Save / restore state + int saveState(); + void restoreState(int stateId); + + // Computation + void compute(double startTime, double endTime, double timeStep); + void compute(); + + // Model and state edition + int getInt(const std::string & varName, int index1, int index2, int index3); + double getDouble(const std::string & varName, int index1, int index2, int index3); + void setInt(const std::string & varName, int index1, int index2, int index3, int value); + void setDouble(const std::string & varName, int index1, int index2, int index3, double value); + +protected: + + void testMascaretResult(int res, const std::string & functionName); + + int _id; + bool _printing; + +}; + +} + +#endif /* MASCARET_HXX_ */ diff --git a/src/mascaret_wrapper/mascaret_swig.i b/src/mascaret_wrapper/mascaret_swig.i new file mode 100644 index 0000000..08fd1d4 --- /dev/null +++ b/src/mascaret_wrapper/mascaret_swig.i @@ -0,0 +1,43 @@ +// Copyright (C) 2012-2013 EDF +// +// This file is part of SALOME HYDRO module. +// +// SALOME HYDRO module is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// SALOME HYDRO 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SALOME HYDRO module. If not, see . + +%module mascaret_swig + +%include std_string.i + +%include std_vector.i + +%{ +#include "Mascaret.hxx" +%} + +// Instantiate template used by Mascaret +%template(MascaretFileVector) std::vector; + +// Exception handling +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::Mascaret(); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::~Mascaret(); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::importModel(const MascaretFileList & fileList); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::initState(const std::string & ligFileName); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::compute(double startTime, double endTime, double timeStep); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::compute(); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::getInt(const std::string & varName, int index1, int index2, int index3); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::getDouble(const std::string & varName, int index1, int index2, int index3); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::setInt(const std::string & varName, int index1, int index2, int index3, int value); +%catches(SalomeHydro::MascaretException, ...) SalomeHydro::Mascaret::setDouble(const std::string & varName, int index1, int index2, int index3, double value); + +%include "Mascaret.hxx" diff --git a/src/salome_hydro/CMakeLists.txt b/src/salome_hydro/CMakeLists.txt index a6c8307..5300240 100644 --- a/src/salome_hydro/CMakeLists.txt +++ b/src/salome_hydro/CMakeLists.txt @@ -18,6 +18,7 @@ ADD_SUBDIRECTORY(mascaret) ADD_SUBDIRECTORY(telemac2d) ADD_SUBDIRECTORY(pytel) +ADD_SUBDIRECTORY(coupling1d2d) ADD_SUBDIRECTORY(boundary_conditions) # --- Python files --- diff --git a/src/salome_hydro/coupling1d2d/CMakeLists.txt b/src/salome_hydro/coupling1d2d/CMakeLists.txt new file mode 100644 index 0000000..5274761 --- /dev/null +++ b/src/salome_hydro/coupling1d2d/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +ADD_SUBDIRECTORY(eficas) + +# --- Python files --- + +SET(PYFILES + __init__.py +) + +# --- rules --- + +SALOME_INSTALL_SCRIPTS("${PYFILES}" ${SALOME_INSTALL_PYTHON}/salome/hydro/coupling1d2d) diff --git a/src/salome_hydro/coupling1d2d/__init__.py b/src/salome_hydro/coupling1d2d/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/salome_hydro/coupling1d2d/eficas/CMakeLists.txt b/src/salome_hydro/coupling1d2d/eficas/CMakeLists.txt new file mode 100644 index 0000000..3fea4fa --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +# --- Python files --- + +SET(PYFILES + __init__.py + configuration_coupling1d2d.py + prefs_coupling1d2d.py + prefs.py + coupling1d2d_cata.py + appli.py + generator_coupling1d2d.py +) + +# --- Data files --- + +SET(DATAFILES + coupling1d2d_template_schema.xml +) + +# --- rules --- + +SALOME_INSTALL_SCRIPTS("${PYFILES}" ${SALOME_INSTALL_PYTHON}/salome/hydro/coupling1d2d/eficas) +INSTALL(FILES ${DATAFILES} DESTINATION ${SALOME_INSTALL_PYTHON}/salome/hydro/coupling1d2d/eficas) diff --git a/src/salome_hydro/coupling1d2d/eficas/__init__.py b/src/salome_hydro/coupling1d2d/eficas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/salome_hydro/coupling1d2d/eficas/appli.py b/src/salome_hydro/coupling1d2d/eficas/appli.py new file mode 100644 index 0000000..e9c576c --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/appli.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +import os +import sys +import re + +from PyQt5.QtWidgets import QMessageBox , QScrollArea, QGridLayout + +import salome +import SalomePyQt +sgPyQt = SalomePyQt.SalomePyQt() + +from salome.kernel.logger import Logger +from salome.kernel import termcolor +logger = Logger("salome.hydro.coupling1d2d.eficas.appli", + color = termcolor.GREEN_FG) + +import eficasSalome + +from salome.hydro.study import HydroStudyEditor + +class SalomeEntry: + + enable_salome_selection = True + help_message = u"Une entrée de l'arbre d'étude de Salome est attendue" + + def __init__(self, entryStr): + self._entry = entryStr + + @staticmethod + def __convert__(entryStr): + return SalomeEntry(entryStr) + + @staticmethod + def get_selected_value(selected_entry, study_editor): + sobj = study_editor.study.FindObjectID(selected_entry) + name = sobj.GetName() + return "%s (%s)" % (name, selected_entry) + +class EficasForCoupling1D2DAppli(eficasSalome.MyEficas): + """ + This class launches Eficas and adds entries for the created files in + HYDRO component in the study tree. The messages in this class are in + french because they are displayed in Eficas interface. + + :type fichier: string + :param fichier: path of an Eficas file to open + + """ + def __init__(self, fichier = None, version = None): + self.ed = HydroStudyEditor() + self.codedir = os.path.dirname(__file__) + sys.path[:0] = [self.codedir] + area = QScrollArea(SalomePyQt.SalomePyQt().getDesktop()); + eficasSalome.MyEficas.__init__(self, area, "coupling1d2d", + fichier, version = version) + gridLayout = QGridLayout(area) + gridLayout.addWidget(self) + area.setWidgetResizable(1) + + sgPyQt.createView("Eficas Coupling 1D/2D", self) + + def selectGroupFromSalome(self, kwType = None, editor=None): + """ + Select an entry from Salome object browser + """ + nbEntries = salome.sg.SelectedCount() + if nbEntries < 1: + msg = u"Veuillez sélectionner une entrée de l'arbre d'étude de Salome" + QMessageBox.information(self, self.tr(u"Sélection depuis Salome"), self.tr(msg)) + return [], msg + elif nbEntries > 1: + msg = u"Une seule entrée doit être sélectionnée dans l'arbre d'étude de Salome" + QMessageBox.information(self, self.tr(u"Sélection depuis Salome"), self.tr(msg)) + return [], msg + else: + try: + value = kwType.get_selected_value(salome.sg.getSelected(0), self.ed.editor) + msg = u"L'entrée de l'arbre d'étude de Salome a été sélectionnée" + return [value], msg + except Exception, e: + QMessageBox.information(self, self.tr(u"Sélection depuis Salome"), self.tr(unicode(e))) + return [], unicode(e) + + def addJdcInSalome(self, jdcPath): + """ + Add the newly created file in Salome study + """ + try: + self.ed.find_or_create_coupling1d2d_case(jdcPath) + except Exception, exc: + msgError = "Can't add file to Salome study tree" + logger.exception(msgError) + QMessageBox.warning(self, self.tr("Warning"), + self.tr("%s. Reason:\n%s\n\nSee logs for more details." % (msgError, exc))) + salome.sg.updateObjBrowser(0) + + def closeEvent(self, event): + while self.codedir in sys.path: + sys.path.remove(self.codedir) + eficasSalome.MyEficas.closeEvent(self, event) diff --git a/src/salome_hydro/coupling1d2d/eficas/configuration_coupling1d2d.py b/src/salome_hydro/coupling1d2d/eficas/configuration_coupling1d2d.py new file mode 100644 index 0000000..503fa36 --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/configuration_coupling1d2d.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +import os + +from Editeur.catadesc import CatalogDescription +from InterfaceQT4.configuration import CONFIG_BASE + +class CONFIG(CONFIG_BASE): + + def __init__(self, appli, repIni): + """ + This class stores the configuration parameters for Eficas + """ + CONFIG_BASE.__init__(self, appli, repIni) + + # Configuration parameters + self.savedir = os.getenv("HOME") + self.catalogues = (CatalogDescription("coupling1d2d", + os.path.join(repIni, "coupling1d2d_cata.py"), + file_format = "coupling1d2d"),) + self.lang = 'fr' + + self.generator_module = "generator_coupling1d2d" + + def save_params(self): + pass + + def get_template_file(self): + return os.path.join(self.repIni, "coupling1d2d_template_schema.xml") + + def get_extension(self): + return ".xml" + +def make_config(appli, rep): + return CONFIG(appli, rep) + +def make_config_style(appli, rep): + return None diff --git a/src/salome_hydro/coupling1d2d/eficas/coupling1d2d_cata.py b/src/salome_hydro/coupling1d2d/eficas/coupling1d2d_cata.py new file mode 100644 index 0000000..1fad998 --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/coupling1d2d_cata.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +from salome.hydro.coupling1d2d.eficas.appli import SalomeEntry +from Accas import * + +JdC = JDC_CATA(regles = (UN_PARMI('COUPLAGE1D2D',)), + ) + +COUPLAGE1D2D = PROC( + nom = "COUPLAGE1D2D", op = None, + fr = u"Définition d'un couplage Mascaret / Telemac2D", + ang = u"Definition of a Mascaret / Telemac2D coupling", + CAS_MASCARET = SIMP(statut = "o", typ = SalomeEntry, + fr = u"Entrée Salome contenant le cas d'étude Mascaret", + ang = u"Salome entry containing Mascaret study case"), + CAS_TELEMAC2D = SIMP(statut = "o", typ = SalomeEntry, + fr = u"Entrée Salome contenant le cas d'étude Telemac2D", + ang = u"Salome entry containing Telemac2D study case"), + FICHIER_COUPLAGE = SIMP(statut = "o", typ = ('Fichier', 'Fichiers Python (*.py);;Tous les fichiers (*)',), + fr = u"Fichier de description du couplage", + ang = u"Coupling description file"), + FICHIER_LOG = SIMP(statut = "o", typ = ('Fichier', 'Tous les fichiers (*)', "Sauvegarde"), + fr = "Fichier de log", + ang = u"Log file"), + FICHIER_GRAPHIQUE = SIMP(statut = "o", + typ = ('Fichier', 'Fichiers CSV (*.csv);;Tous les fichiers (*)', "Sauvegarde"), + fr = u"Fichier de données pour la génération du graphique", + ang = u"Data file for the graphics generation"), +) +TEXTE_NEW_JDC="COUPLAGE1D2D()" diff --git a/src/salome_hydro/coupling1d2d/eficas/coupling1d2d_template_schema.xml b/src/salome_hydro/coupling1d2d/eficas/coupling1d2d_template_schema.xml new file mode 100644 index 0000000..38908ab --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/coupling1d2d_template_schema.xml @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MASCARET + + ExecStep + + + + + + TELEMAC2D + + ExecStep + + + + + MascExecStep ConvergenceController + MascExecStep TelExecStep + TelExecStep ConvergenceController + + ConvergenceController timeData + MascExecStep timeData + + + ConvergenceController timeData + TelExecStep timeData + + + ConvergenceController telemacData + MascExecStep inputData + + + MascExecStep outputData + ConvergenceController mascData + + + MascExecStep outputData + TelExecStep inputData + + + TelExecStep outputData + ConvergenceController telemacData + + + + ConvergenceBloc.ConvergenceController iter + ConvergenceBloc.ConvergenceController iter + + + ConvergenceBloc.ConvergenceController timeData + ConvergenceBloc.ConvergenceController timeData + + + ConvergenceLoop TimeController + + TimeController cont + ConvergenceLoop condition + + + TimeController timeData + ConvergenceLoop.ConvergenceBloc.ConvergenceController timeData + + + TimeController timeData + ConvergenceLoop.ConvergenceBloc.MascExecStep timeData + + + TimeController timeData + ConvergenceLoop.ConvergenceBloc.TelExecStep timeData + + + ConvergenceLoop.ConvergenceBloc.ConvergenceController cont + ConvergenceLoop condition + + + + TimeBloc.TimeController time + TimeBloc.TimeController time + + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.MascExecStep + Init + + + + + + + + + + + + + + + + + + + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.MascExecStep + Finalize + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.TelExecStep + Init + + + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.TelExecStep + Finalize + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.MascExecStep + InitBorders + + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.TelExecStep + InitBorders + + + TimeLoop FinalizeMascaret + TimeLoop FinalizeTelemac + InitMascaret TimeLoop + InitCoupling TimeLoop + InitCoupling InitMascBorders + InitCoupling InitTelBorders + InitTelemac TimeLoop + InitTelemac InitTelBorders + InitMascBorders TimeLoop + InitTelBorders TimeLoop + + InitCoupling starttime + TimeLoop.TimeBloc.TimeController time + + + InitCoupling endtime + TimeLoop.TimeBloc.TimeController endtime + + + InitCoupling timestep + TimeLoop.TimeBloc.TimeController timestep + + + InitCoupling eps_Z + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceController Z_tol + + + InitCoupling eps_Q + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceController Q_tol + + + InitCoupling borders + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceController borders + + + InitCoupling borders + InitMascBorders borders + + + InitCoupling borders + InitTelBorders borders + + + InitCoupling timeData + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceController timeData + + + InitCoupling timeData + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.MascExecStep timeData + + + InitCoupling timeData + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.TelExecStep timeData + + + InitCoupling log + TimeLoop.TimeBloc.TimeController log + + + InitCoupling log + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceController log + + + InitCoupling maxiter + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceController maxiter + + + InitCoupling graph + TimeLoop.TimeBloc.TimeController graph + + + InitCoupling graph + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceController graph + + + TimeLoop.TimeBloc.TimeController cont + TimeLoop condition + + + InitMascaretstudyID + 1 + + + InitMascaretdetCaseEntry + %parse_entry(CAS_MASCARET)% + + + InitCouplingcouplingFile + %FICHIER_COUPLAGE% + + + InitCouplinglogFile + %FICHIER_LOG% + + + InitCouplinggraphFile + %FICHIER_GRAPHIQUE% + + + TimeLoopcondition + true + + + TimeLoop.TimeBloc.ConvergenceLoopcondition + true + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.ConvergenceControlleriter + 1 + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.MascExecStepinputData + N. + + + TimeLoop.TimeBloc.ConvergenceLoop.ConvergenceBloc.TelExecStepinputData + N. + + + InitTelemacstudyID + 1 + + + InitTelemacdetCaseEntry + %parse_entry(CAS_TELEMAC2D)% + + + + + + + + + + + + + + + + + + diff --git a/src/salome_hydro/coupling1d2d/eficas/generator_coupling1d2d.py b/src/salome_hydro/coupling1d2d/eficas/generator_coupling1d2d.py new file mode 100644 index 0000000..4fd1225 --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/generator_coupling1d2d.py @@ -0,0 +1,67 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +import re + +from generator.generator_file_from_template import FileFromTemplateGenerator + +def entryPoint(): + return {'name': 'coupling1d2d', + 'factory' : Coupling1D2DGenerator} + +class Coupling1D2DGenerator(FileFromTemplateGenerator): + """ + This generator is mostly identical to FileFromTemplateGenerator, but it + can also perform replacements using functions. The syntax for this kind + of replacement is %func(KEYWORD)%. The replacement method will call + the function "func" that must be defined in this class with the parameter + KEYWORD. The available function is parse_entry. + """ + + def generate_output_from_template(self): + """ + Generate the output by replacing the keywords and the functions in the + template. + """ + FileFromTemplateGenerator.generate_output_from_template(self) + self.output_text = self.replace_functions(self.output_text) + + def replace_functions(self, template_string): + """ + Replace the functions in the template string. + """ + result = template_string + pattern = "%(.*)\((.*)\)%" + matchObj = re.search(pattern, result) + while matchObj: + (whole_string, func_name, param_keyword) = matchObj.group(0, 1, 2) + param_value = self.kw_dict[param_keyword] + func = eval(func_name) + value = func(param_value) + result = result.replace(whole_string, value) + matchObj = re.search(pattern, result) + return result + +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_hydro/coupling1d2d/eficas/prefs.py b/src/salome_hydro/coupling1d2d/eficas/prefs.py new file mode 100644 index 0000000..ddbb7a1 --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/prefs.py @@ -0,0 +1,18 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +code = "coupling1d2d" diff --git a/src/salome_hydro/coupling1d2d/eficas/prefs_coupling1d2d.py b/src/salome_hydro/coupling1d2d/eficas/prefs_coupling1d2d.py new file mode 100644 index 0000000..ed30a09 --- /dev/null +++ b/src/salome_hydro/coupling1d2d/eficas/prefs_coupling1d2d.py @@ -0,0 +1,28 @@ +# Copyright (C) 2012-2013 EDF +# +# This file is part of SALOME HYDRO module. +# +# SALOME HYDRO module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SALOME HYDRO 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SALOME HYDRO module. If not, see . + +import os +import sys + +repIni = os.path.dirname(__file__) +INSTALLDIR = os.getenv("EFICAS_ROOT") +closeAutreCommande=True +closeFrameRechercheCommande=True +closeArbre=True +closeCopier=True +suiteTelemac=True + diff --git a/src/salome_hydro/mascaret/__init__.py b/src/salome_hydro/mascaret/__init__.py index e4b3bfd..5bccc27 100644 --- a/src/salome_hydro/mascaret/__init__.py +++ b/src/salome_hydro/mascaret/__init__.py @@ -14,3 +14,9 @@ # # You should have received a copy of the GNU General Public License # along with SALOME HYDRO module. If not, see . + +import mascaret_swig + +Mascaret = mascaret_swig.Mascaret +MascaretFile = mascaret_swig.MascaretFile +MascaretException = mascaret_swig.MascaretException diff --git a/src/salome_hydro/pytel/eficas/pytel_cata.py b/src/salome_hydro/pytel/eficas/pytel_cata.py index 50f0c43..db77f20 100644 --- a/src/salome_hydro/pytel/eficas/pytel_cata.py +++ b/src/salome_hydro/pytel/eficas/pytel_cata.py @@ -19,7 +19,7 @@ from Accas import * -codelist = ("artemis", "estel3d", "postel3d", "sisyphe", "stbtel", "telemac2d", "telemac3d", "tomawac", "mascaret") +codelist = ("artemis", "estel3d", "postel3d", "sisyphe", "stbtel", "telemac2d", "telemac3d", "tomawac") JdC = JDC_CATA(regles = (UN_PARMI('PYTEL',)), ) diff --git a/src/salome_hydro/study.py b/src/salome_hydro/study.py index 550a189..f045f9b 100644 --- a/src/salome_hydro/study.py +++ b/src/salome_hydro/study.py @@ -42,6 +42,10 @@ TELEMAC2D_FILE_TYPE = "TELEMAC2D_EFICAS_FILE" TELEMAC2D_ICON = "case2d.png" TELEMAC2D_CASE_TYPE_ID = 3 +COUPLING1D2D_FILE_TYPE = "COUPLING1D2D_EFICAS_FILE" +COUPLING1D2D_ICON = "case_couplage.png" +COUPLING1D2D_CASE_TYPE_ID = 4 + PYTEL_FILE_TYPE = "PYTEL_EFICAS_FILE" PYTEL_ICON = "case_pytel.png" PYTEL_CASE_TYPE_ID = 5 @@ -116,6 +120,45 @@ class HydroStudyEditor: icon = MASCARET_ICON, comment = str(filePath), typeId = MASCARET_CASE_TYPE_ID) + # Create "Variables" item + (file_list, lig_file, input_vars, output_vars) = self.get_mascaret_params_from_case(sobj) + input_varname_list = [var["NOM"].strip() for var in input_vars] + # Remove duplicates + input_varname_list = list(set(input_varname_list)) + input_var_list = [study_exchange_vars.Variable(varname) for varname in input_varname_list] + output_var_list = [study_exchange_vars.Variable(var["NOM"].strip()) for var in output_vars] + exchange_vars = study_exchange_vars.ExchangeVariables(input_var_list, output_var_list) + study_exchange_vars.createSObjectForExchangeVariables(sobj, exchange_vars, icon = VARS_ICON) + + def get_mascaret_params_from_case(self, sobj): + jdcpath = sobj.GetComment() + with open(jdcpath) as jdcfile: + jdc = jdcfile.read() + params = jdc_to_dict(jdc, ["MASCARET", "_F"]) + input_vars = get_jdc_dict_var_as_tuple(params, "VARIABLE_ENTREE") + output_vars = get_jdc_dict_var_as_tuple(params, "VARIABLE_SORTIE") + file_list = [] + for (key, value) in params.iteritems(): + if key == "FICHIER_LOI": + file_list += [HYDROSOLVER_ORB.MascaretFile(f["NOM"], mascaretFileTypeDict[key]) for f in value] + elif key != "FICHIER_LIG" and key != "VARIABLE_SORTIE" and key != "VARIABLE_ENTREE": + file_list.append(HYDROSOLVER_ORB.MascaretFile(value, mascaretFileTypeDict[key])) + return (file_list, params["FICHIER_LIG"], input_vars, output_vars) + + def add_results_to_mascaret_case(self, sobj, output_variables, output_values): + results = self.editor.createItem(sobj, "Results") + for (var, value) in zip(output_variables, output_values): + self.editor.createItem(results, var, comment = unicode(value)) + + def add_coupling_log(self, varname, log): + self.find_or_create_hydro_component() + sObj = self.editor.createItem(self.hydroComp, + name = varname, + icon = LOG_ICON, + typeId = LOG_TYPE_ID) + attr = self.editor.builder.FindOrCreateAttribute(sObj, + "AttributeParameter") + attr.SetString("log", log) def find_or_create_telemac2d_case(self, filePath): self.find_or_create_hydro_component() @@ -171,6 +214,17 @@ class HydroStudyEditor: # Writting to file yacs_scheme.saveSchema(yacs_file) + def find_or_create_coupling1d2d_case(self, filePath): + self.find_or_create_hydro_component() + itemName = os.path.splitext(os.path.basename(filePath))[0] + sobj = self.editor.findOrCreateItem(self.hydroComp, + name = itemName, + fileType = COUPLING1D2D_FILE_TYPE, + fileName = filePath, + icon = COUPLING1D2D_ICON, + comment = str(filePath), + typeId = COUPLING1D2D_CASE_TYPE_ID) + def find_or_create_pytel_case(self, filePath): self.find_or_create_hydro_component() itemName = os.path.splitext(os.path.basename(filePath))[0] -- 2.39.2