Salome HOME
d23d52c6c123b35efd288bea4146bbb55a03d7a2
[modules/smesh.git] / src / SMESH_I / SMESH_Meshio.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // SMESH SMESH_I : support of import / export with meshio library
24 // File   : SMESH_Meshio.h
25 // Author : Konstantin Leontev, Open CASCADE S.A.S.
26 //
27
28 #include "SMESH_Meshio.h"
29
30 // SALOME KERNEL includes
31 #include <SALOMEDS_Tool.hxx>
32 #include <Basics_DirUtils.hxx>
33 #include <SALOME_Exception.hh>
34 #include <utilities.h>
35
36 // Qt
37 #include <QFileInfo>
38
39 #include <fstream>
40
41
42 /*!
43   Constructor
44 */
45 SMESH_Meshio::SMESH_Meshio()
46 {
47   CreateErrorFileName();
48 }
49
50 /*!
51   Constructor
52 */
53 SMESH_Meshio::SMESH_Meshio(const QString& selectedFilter)
54 : SMESH_Meshio()
55 {
56   mySelectedFilter = selectedFilter;
57 }
58
59 /*!
60   Destructor
61 */
62 SMESH_Meshio::~SMESH_Meshio()
63 {
64   RemoveTempFile();
65   RemoveErrorFile();
66 }
67
68 /*!
69   Convert file with meshio convert command
70 */
71 void SMESH_Meshio::Convert(const QString& sourceFileName, const QString& targetFileName) const
72 {
73   // Execute meshio convert command
74   const QString convert = IsModernPythonVersion() ? "meshio convert " : "meshio-convert ";
75   const QString optArgs = GetConvertOptArgs();
76
77   const std::string cmd = 
78     (convert + optArgs + " " + sourceFileName + " " + targetFileName + " 2> " + myErrorFileName).toStdString();
79   MESSAGE("Call system(\"" << cmd << "\") ...");
80
81   const int status = system(cmd.c_str());
82   MESSAGE("status: " << status);
83
84   // Check results
85   if (status != 0 || !Kernel_Utils::IsExists(targetFileName.toStdString()))
86   {
87     // Get all the output from an error file
88     const std::string meshioErrors = ReadErrorsFromFile();
89     MESSAGE("meshioErrors: \n" << meshioErrors);
90
91     SALOME::ExceptionStruct es;
92     es.type = SALOME::ExceptionType::BAD_PARAM;
93     es.lineNumber = -1;
94     es.text = CORBA::string_dup(
95       ("MESHIO\nFailed system(\"" + cmd + "\").\n\n" + meshioErrors + "\nOperation canceled.").c_str());
96
97     throw SALOME::SALOME_Exception(es);
98   }
99 }
100
101 /*!
102   Returns a name for a file in default temp directory
103   based on a target basename.
104 */
105 QString SMESH_Meshio::CreateTempFileName(const QString& targetFileName)
106 {
107   // Make a name for a temp file
108   const QFileInfo fileInfo(targetFileName);
109   const QString targetBaseName = fileInfo.baseName();
110   const QString dirName(SALOMEDS_Tool::GetTmpDir().c_str());
111   myTempFileName = dirName + targetBaseName + ".med";
112
113   MESSAGE("targetFileName: " << targetFileName.toStdString());
114   MESSAGE("myTempFileName: " << myTempFileName.toStdString());
115
116   return myTempFileName;
117 }
118
119 /*!
120   Removes the temporary file if we have any
121 */
122 void SMESH_Meshio::RemoveTempFile()
123 {
124   if (!myTempFileName.isEmpty())
125   {
126     std::remove(myTempFileName.toStdString().c_str());
127     MESSAGE("Temp file " << myTempFileName.toStdString() << " was removed");
128   }
129 }
130
131 /*!
132   Returns true if current Python equal or newer than required version for
133   meshio release from 5.0 and greater.
134 */
135 bool SMESH_Meshio::IsModernPythonVersion()
136 {
137   // It's a version when meshio commands were changed from using
138   // many executables for each operation to one for everything (meshio 5.0).
139   // For example, from
140   // meshio-convert input.msh output.vtk
141   // to
142   // meshio convert input.msh output.vtk
143  
144   const std::vector<int> minReqVersionNums = { 3, 7 };
145
146   auto GetCurrentVersion = []() -> QString
147   {
148     const char *envVar = std::getenv("PYTHON_VERSION");
149     if (envVar && (envVar[0] != '\0'))
150     {
151       return envVar;
152     }
153
154     return {};
155   };
156
157   auto IsModernVersion = [&]() -> bool
158   {
159     const QString curVersion = GetCurrentVersion();
160     MESSAGE("Current Python version: " << curVersion.toStdString())
161     if (curVersion.length() < 3)
162       return false;
163
164     int index = 0;
165     const QStringList curVersionNums = curVersion.split('.');
166     for (const int minVersion : minReqVersionNums)
167     {
168       if (minVersion > curVersionNums[index].toInt())
169       {
170         return false;
171       }
172
173       ++index;
174     }
175
176     return true;
177   };
178
179   static const bool isModern = IsModernVersion();
180   return isModern;
181 }
182
183 /*!
184   Creates a temp file for error output from meshio command.
185 */
186 void SMESH_Meshio::CreateErrorFileName()
187 {
188   // Make a name for a temp file
189   const QString fileName = "meshio_errors.txt";
190   const QString dirName(SALOMEDS_Tool::GetTmpDir().c_str());
191   myErrorFileName = dirName + fileName;
192   
193   MESSAGE("myErrorFileName: " << myErrorFileName.toStdString());
194 }
195
196 /*!
197   Removes the temporary error output file if we have any
198 */
199 void SMESH_Meshio::RemoveErrorFile()
200 {
201   if (!myErrorFileName.isEmpty())
202   {
203     std::remove(myErrorFileName.toStdString().c_str());
204     MESSAGE("Temp file " << myErrorFileName.toStdString() << " was removed");
205   }
206 }
207
208 /*!
209   Read all errors output from a temp file
210 */
211 std::string SMESH_Meshio::ReadErrorsFromFile() const
212 {
213   if (myErrorFileName.isEmpty())
214     return {};
215
216   std::ifstream fileStream(myErrorFileName.toStdString());
217   if(fileStream)
218   {
219     std::ostringstream ss;
220     ss << fileStream.rdbuf();
221
222     return ss.str();
223   }
224
225   return {};
226 }
227
228 /*!
229   Get optional arguments for meshio convert command
230 */
231 QString SMESH_Meshio::GetConvertOptArgs() const
232 {
233   if (mySelectedFilter.isEmpty())
234     return mySelectedFilter;
235
236   // Check what kind of option we must provide
237   if (mySelectedFilter.startsWith("ANSYS"))
238     return "-o ansys";
239   else if (mySelectedFilter.startsWith("Gmsh 2"))
240     return "-o gmsh22";
241   else if (mySelectedFilter.startsWith("Gmsh 4"))
242     return "-o gmsh";
243
244   return {};
245 }