diff --git a/interfaces/cython/cantera/test/test_convert.py b/interfaces/cython/cantera/test/test_convert.py index 42b39786f..ec2c43097 100644 --- a/interfaces/cython/cantera/test/test_convert.py +++ b/interfaces/cython/cantera/test/test_convert.py @@ -459,3 +459,33 @@ class CtmlConverterTest(utilities.CanteraTest): self.assertNear(R.orders.get('OH'), 0.15) self.assertTrue(R.allow_negative_orders) self.assertNear(R.orders.get('H2'), -0.25) + + def test_long_source_input(self): + """ + Here we are testing if passing a very long string will result in a + Solution object. This should result in a temp file creation in most OS's + """ + + gas = ct.Solution(pjoin(self.test_data_dir, 'pdep-test.cti')) + + with open(pjoin(self.test_data_dir, 'pdep-test.cti'), 'r') as f: + data = f.read() + data_size_2048kB = data + ' '*2048*1024 + gas2 = ct.Solution(source=data_size_2048kB) + + self.assertEqual(gas.n_reactions, gas2.n_reactions) + + def test_short_source_input(self): + """ + Here we are testing if passing a short string will result in a Solution + object. This should not result in a temp file creation in most OS's + """ + + gas = ct.Solution(pjoin(self.test_data_dir, 'pdep-test.cti')) + + with open(pjoin(self.test_data_dir, 'pdep-test.cti'), 'r') as f: + data = f.read() + data_size_32kB = data + ' '*18000 + gas2 = ct.Solution(source=data_size_32kB) + + self.assertEqual(gas.n_reactions, gas2.n_reactions) diff --git a/src/base/ct2ctml.cpp b/src/base/ct2ctml.cpp index e32bc423d..36f4d813c 100644 --- a/src/base/ct2ctml.cpp +++ b/src/base/ct2ctml.cpp @@ -11,12 +11,15 @@ #include "cantera/base/stringUtils.h" #include "../../ext/libexecstream/exec-stream.h" +#include #include #include #include #ifdef _WIN32 #include +#else +#include #endif using namespace std; @@ -79,6 +82,9 @@ void ct2ctml(const char* file, const int debug) static std::string call_ctml_writer(const std::string& text, bool isfile) { std::string file, arg; + bool temp_file_created = false; + std::string temp_cti_file_name = std::tmpnam(nullptr); + if (isfile) { file = text; arg = "r'" + text + "'"; @@ -87,6 +93,44 @@ static std::string call_ctml_writer(const std::string& text, bool isfile) arg = "text=r'''" + text + "'''"; } + // If the user wants to convert a mechanism using a text passed via the + // source="""...""" + // argument in python, then we have to make sure that it is short enough + // to fit in the command line when routed to python as: + // python -c ... + // statement downstream in the code + + // So, check the max size of a string that can be passed on the command line + // This is OS Specific. *nix systems have the sysconf() function that tells + // us the largest argument we can pass. Since such a function does not exist + // for Windows, we set a safe limit of 32 kB + +#ifdef _WIN32 + long int max_argv_size = 32768; +#else + long int max_argv_size = sysconf(_SC_ARG_MAX); +#endif + + if (text.size() > static_cast(max_argv_size) - 500) { + // If the file is too big to be passed as a command line argument later + // in the file, then create a temporary file and execute this function + // as though an input file was specified as the source. + // We assume the text passed + 500 chars = total size of argv + + ofstream temp_cti_file(temp_cti_file_name); + + if (temp_cti_file) { + temp_cti_file << text; + file = temp_cti_file_name; + arg = "r'" + file + "'"; + temp_file_created = true; + } else { + // If we are here, then a temp file could not be created + throw CanteraError("call_ctml_writer", "Very long source argument. " + "Error creating temporary file"); + } + } + #ifdef HAS_NO_PYTHON //! Section to bomb out if python is not present in the computation //! environment. @@ -170,6 +214,15 @@ static std::string call_ctml_writer(const std::string& text, bool isfile) message << "--------------- end of converter log ---------------\n"; writelog(message.str()); } + + if (temp_file_created) { + // A temp file was created and has to be removed + bool status = std::remove(temp_cti_file_name.c_str()); + if (status) { + writelog("WARNING: Error removing tmp file {}\n", temp_cti_file_name); + } + } + return python_output; }