diff --git a/src/DataTree.cc b/src/DataTree.cc
index df018564ec058515d0171363404fe9294feee818..e97204f70dd89aa6ea72cd60f67c30c79b5e2d94 100644
--- a/src/DataTree.cc
+++ b/src/DataTree.cc
@@ -20,7 +20,6 @@
 #include <cstdlib>
 #include <cassert>
 #include <iostream>
-#include <regex>
 #include <algorithm>
 #include <iterator>
 #include <filesystem>
@@ -962,17 +961,17 @@ DataTree::strsplit(string_view str, char delim)
   return result;
 }
 
-string
-DataTree::packageDir(const string &package)
+filesystem::path
+DataTree::packageDir(string_view package)
 {
-  regex pat{R"(\.)"};
-  string dirname = "+" + regex_replace(package, pat, "/+");
-  filesystem::create_directories(dirname);
-  return dirname;
+  filesystem::path d;
+  for (const auto &it : strsplit(move(package), '.'))
+    d /= "+" + it;
+  return d;
 }
 
 void
-DataTree::writeToFileIfModified(stringstream &new_contents, const string &filename)
+DataTree::writeToFileIfModified(stringstream &new_contents, const filesystem::path &filename)
 {
   ifstream old_file{filename, ios::in | ios::binary};
   if (old_file.is_open()
@@ -986,7 +985,7 @@ DataTree::writeToFileIfModified(stringstream &new_contents, const string &filena
   ofstream new_file{filename, ios::out | ios::binary};
   if (!new_file.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
   copy(istreambuf_iterator<char>{new_contents}, istreambuf_iterator<char>{},
diff --git a/src/DataTree.hh b/src/DataTree.hh
index 8299a0ee4a830a7a6634a8660b704ec33e1c4f02..42305b15595bb296ad41717454d301f1ac07d55f 100644
--- a/src/DataTree.hh
+++ b/src/DataTree.hh
@@ -28,6 +28,8 @@
 #include <cmath>
 #include <utility>
 #include <memory>
+#include <filesystem>
+#include <string_view>
 
 #include "SymbolTable.hh"
 #include "NumericalConstants.hh"
@@ -109,7 +111,7 @@ protected:
   /* Writes the contents of “new_contents” to the file “filename”. However, if
      the file already exists and would not be modified by this operation, then do
      nothing. */
-  static void writeToFileIfModified(stringstream &new_contents, const string &filename);
+  static void writeToFileIfModified(stringstream &new_contents, const filesystem::path &filename);
 
 private:
   constexpr static int constants_precision{16};
@@ -361,11 +363,10 @@ public:
   static vector<string> strsplit(string_view str, char delim);
 
   /*! Takes a MATLAB/Octave package name (possibly with several levels nested using dots),
-    and returns the name of the corresponding filesystem directory (which
-    is created by the function if it does not exist).
+    and returns the path to the corresponding filesystem directory.
     In practice the package nesting is used for the planner_objective (stored
     inside +objective subdir). */
-  static string packageDir(const string &package);
+  static filesystem::path packageDir(string_view package);
 };
 
 inline expr_t
diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc
index 096537a94a2395184cc7ae281855673ad784c517..93e9627e4ea41bf148f433181385ae562cdbb557 100644
--- a/src/DynamicModel.cc
+++ b/src/DynamicModel.cc
@@ -223,16 +223,16 @@ DynamicModel::writeDynamicPerBlockMFiles(const string &basename) const
       int nze_exo = blocks_derivatives_exo[blk].size();
       int nze_exo_det = blocks_derivatives_exo_det[blk].size();
 
-      string filename = packageDir(basename + ".block") + "/dynamic_" + to_string(blk+1) + ".m";
+      filesystem::path filename {packageDir(basename) / "+block" / ("dynamic_" + to_string(blk+1) + ".m")};
       ofstream output{filename, ios::out | ios::binary};
       if (!output.is_open())
         {
-          cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+          cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
           exit(EXIT_FAILURE);
         }
 
       output << "%" << endl
-             << "% " << filename << " : Computes dynamic version of one block" << endl
+             << "% " << filename.string() << " : Computes dynamic version of one block" << endl
              << "%" << endl
              << "% Warning : this file is generated automatically by Dynare" << endl
              << "%           from model file (.mod)" << endl << endl
@@ -987,11 +987,11 @@ DynamicModel::printNonZeroHessianEquations(ostream &output) const
 void
 DynamicModel::writeDynamicBlockMFile(const string &basename) const
 {
-  string filename = packageDir(basename) + "/dynamic.m";
+  filesystem::path filename {packageDir(basename) / "dynamic.m"};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -1102,7 +1102,7 @@ DynamicModel::writeDynamicBlockCFile(const string &basename, vector<filesystem::
   output.close();
 
   per_block_object_files.push_back(filename);
-  compileMEX("+" + basename, "dynamic", mexext, per_block_object_files, matlabroot, dynareroot);
+  compileMEX(packageDir(basename), "dynamic", mexext, per_block_object_files, matlabroot, dynareroot);
 }
 
 void
@@ -1116,11 +1116,11 @@ DynamicModel::writeDynamicMWrapperFunction(const string &basename, const string
   else if (ending == "g3")
     name = "dynamic_resid_g1_g2_g3";
 
-  string filename = packageDir(basename) + "/" + name + ".m";
+  filesystem::path filename {packageDir(basename) / (name + ".m")};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -1164,11 +1164,11 @@ DynamicModel::writeDynamicMFileHelper(const string &basename,
                                       const ostringstream &init_s, const ostringstream &end_s,
                                       const ostringstream &s, const ostringstream &s_tt) const
 {
-  string filename = packageDir(basename) + "/" + name_tt + ".m";
+  filesystem::path filename {packageDir(basename) / (name_tt + ".m")};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -1201,11 +1201,11 @@ DynamicModel::writeDynamicMFileHelper(const string &basename,
          << "end" << endl;
   output.close();
 
-  filename = packageDir(basename) + "/" + name + ".m";
+  filename = packageDir(basename) / (name + ".m");
   output.open(filename, ios::out | ios::binary);
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -1245,11 +1245,11 @@ DynamicModel::writeDynamicMFileHelper(const string &basename,
 void
 DynamicModel::writeDynamicMCompatFile(const string &basename) const
 {
-  string filename = packageDir(basename) + "/dynamic.m";
+  filesystem::path filename {packageDir(basename) / "dynamic.m"};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
   int ntt { static_cast<int>(temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size()) };
@@ -1291,7 +1291,7 @@ DynamicModel::writeDynamicJacobianNonZeroEltsFile(const string &basename) const
   sort(nzij_current.begin(), nzij_current.end());
   sort(nzij_fwrd.begin(), nzij_fwrd.end());
 
-  ofstream output{"+" + basename + "/dynamic_g1_nz.m", ios::out | ios::binary};
+  ofstream output{packageDir(basename) / "dynamic_g1_nz.m", ios::out | ios::binary};
   output << "function [nzij_pred, nzij_current, nzij_fwrd] = dynamic_g1_nz()" << endl
          << "% Returns the coordinates of non-zero elements in the Jacobian, in column-major order, for each lead/lag (only for endogenous)" << endl;
   auto print_nzij = [&output](const vector<pair<int, int>> &nzij, const string &name) {
@@ -3472,6 +3472,16 @@ DynamicModel::writeDynamicFile(const string &basename, bool block, bool use_dll,
   model_dir /= "model";
   if (use_dll)
     create_directories(model_dir / "src");
+  if (!julia)
+    {
+      auto plusfolder {packageDir(basename)};
+      /* The following is not a duplicate of the same call from
+         ModFile::writeMOutput(), because of planner_objective which needs its
+         +objective subdirectory */
+      create_directories(plusfolder);
+      if (block && !use_dll)
+        create_directories(plusfolder / "+block");
+    }
   create_directories(model_dir / "bytecode");
 
   if (block)
@@ -3543,7 +3553,22 @@ DynamicModel::writeSetAuxiliaryVariables(const string &basename, bool julia) con
     output << "end" << endl
            << "end" << endl;
 
-  writeToFileIfModified(output, julia ? basename + "DynamicSetAuxiliarySeries.jl" : packageDir(basename) + "/" + func_name + ".m");
+  if (julia)
+    writeToFileIfModified(output, basename + "DynamicSetAuxiliarySeries.jl");
+  else
+    {
+      /* Calling writeToFileIfModified() is useless here since we write inside
+         a subdirectory deleted at each preprocessor run. */
+      filesystem::path filename {packageDir(basename) / (func_name + ".m")};
+      ofstream output_file{filename, ios::out | ios::binary};
+      if (!output_file.is_open())
+        {
+          cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
+          exit(EXIT_FAILURE);
+        }
+      output_file << output.str();
+      output_file.close();
+    }
 }
 
 void
diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh
index 7887c82fdbc7f7f4ea26080255c721f593838e75..92c9c75cd6f2bfe3da2335c310922a7fa72a2dd6 100644
--- a/src/DynamicModel.hh
+++ b/src/DynamicModel.hh
@@ -837,11 +837,11 @@ DynamicModel::writeParamsDerivativesFile(const string &basename) const
   auto [tt_output, rp_output, gp_output, rpp_output, gpp_output, hp_output, g3p_output]
     { writeParamsDerivativesFileHelper<output_type>() };
 
-  string filename { julia ? basename + "DynamicParamsDerivs.jl" : packageDir(basename) + "/dynamic_params_derivs.m" };
+  const filesystem::path filename {julia ? filesystem::path{basename + "DynamicParamsDerivs.jl"} : packageDir(basename) / "dynamic_params_derivs.m"};
   ofstream paramsDerivsFile { filename, ios::out | ios::binary };
   if (!paramsDerivsFile.is_open())
     {
-      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
diff --git a/src/ModFile.cc b/src/ModFile.cc
index 6e989c090f5c0ec5e6bdd278956339f6beed8406..2225ffeb8a6924521cb8cf2af3b6f1009265caa0 100644
--- a/src/ModFile.cc
+++ b/src/ModFile.cc
@@ -782,6 +782,14 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
                       const filesystem::path &matlabroot,
                       const filesystem::path &dynareroot, bool onlymodel, bool gui, bool notime) const
 {
+  if (basename.empty())
+    {
+      cerr << "ERROR: Missing file name" << endl;
+      exit(EXIT_FAILURE);
+    }
+
+  auto plusfolder {DataTree::packageDir(basename)};
+
   bool hasModelChanged = !dynamic_model.isChecksumMatching(basename) || !check_model_changes;
   if (hasModelChanged)
     {
@@ -793,7 +801,7 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
          it before deleting it (the renaming must occur in the same directory,
          otherwise it may file if the destination is not on the same
          filesystem). */
-      if (filesystem::path plusfolder{"+" + basename}; exists(plusfolder))
+      if (exists(plusfolder))
         {
           if (exists(plusfolder / "+objective"))
             {
@@ -811,18 +819,12 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
       filesystem::remove_all(basename + "/model/bytecode");
     }
 
-  if (!basename.size())
-    {
-      cerr << "ERROR: Missing file name" << endl;
-      exit(EXIT_FAILURE);
-    }
-
-  filesystem::create_directory("+" + basename);
-  string fname = "+" + basename + "/driver.m";
+  create_directory(plusfolder);
+  filesystem::path fname {plusfolder / "driver.m"};
   ofstream mOutputFile{fname, ios::out | ios::binary};
   if (!mOutputFile.is_open())
     {
-      cerr << "ERROR: Can't open file " << fname << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << fname.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
diff --git a/src/ModelEquationBlock.cc b/src/ModelEquationBlock.cc
index dfe4ef54d9cf1dd6a4aa4ada3a2469b35c7d93b5..d07fa0d0add82bfdc6168a750741f4ab2c512b9e 100644
--- a/src/ModelEquationBlock.cc
+++ b/src/ModelEquationBlock.cc
@@ -259,7 +259,22 @@ SteadyStateModel::writeSteadyStateFile(const string &basename, bool julia) const
   if (julia)
     output << "end" << endl << "end" << endl;
 
-  writeToFileIfModified(output, julia ? basename + "SteadyState2.jl" : packageDir(basename) + "/steadystate.m");
+  if (julia)
+    writeToFileIfModified(output, basename + "SteadyState2.jl");
+  else
+    {
+      /* Calling writeToFileIfModified() is useless here since we write inside
+         a subdirectory deleted at each preprocessor run. */
+      filesystem::path filename {packageDir(basename) / "steadystate.m"};
+      ofstream output_file{filename, ios::out | ios::binary};
+      if (!output_file.is_open())
+        {
+          cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
+          exit(EXIT_FAILURE);
+        }
+      output_file << output.str();
+      output_file.close();
+    }
 }
 
 void
@@ -407,11 +422,11 @@ Epilogue::writeEpilogueFile(const string &basename) const
 void
 Epilogue::writeStaticEpilogueFile(const string &basename) const
 {
-  string filename = packageDir(basename) + "/epilogue_static.m";
+  filesystem::path filename {packageDir(basename) / "epilogue_static.m"};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -445,11 +460,11 @@ Epilogue::writeStaticEpilogueFile(const string &basename) const
 void
 Epilogue::writeDynamicEpilogueFile(const string &basename) const
 {
-  string filename = packageDir(basename) + "/epilogue_dynamic.m";
+  filesystem::path filename {packageDir(basename) / "epilogue_dynamic.m"};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
diff --git a/src/ModelTree.hh b/src/ModelTree.hh
index e2e2884983bf470e8d6a7a759c55bf15abd12f93..924257816453690bfe797ab5e0ba746b8ce40679 100644
--- a/src/ModelTree.hh
+++ b/src/ModelTree.hh
@@ -1031,7 +1031,7 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext,
   output.close();
 
   object_files.push_back(filename);
-  compileMEX("+" + basename, dynamic ? "dynamic" : "static", mexext, object_files, matlabroot,
+  compileMEX(packageDir(basename), dynamic ? "dynamic" : "static", mexext, object_files, matlabroot,
              dynareroot);
 }
 
diff --git a/src/StaticModel.cc b/src/StaticModel.cc
index f4d24f70692ce934e689e9d4c5036fdbf533e9c8..8db084783107037e7111083cffcd81d591467e5e 100644
--- a/src/StaticModel.cc
+++ b/src/StaticModel.cc
@@ -104,15 +104,15 @@ StaticModel::writeStaticPerBlockMFiles(const string &basename) const
     {
       BlockSimulationType simulation_type = blocks[blk].simulation_type;
 
-      string filename = packageDir(basename + ".block") + "/static_" + to_string(blk+1) + ".m";
+      filesystem::path filename {packageDir(basename) / "+block" / ("static_" + to_string(blk+1) + ".m")};
       ofstream output{filename, ios::out | ios::binary};
       if (!output.is_open())
         {
-          cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+          cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
           exit(EXIT_FAILURE);
         }
       output << "%" << endl
-             << "% " << filename << " : Computes static version of one block" << endl
+             << "% " << filename.string() << " : Computes static version of one block" << endl
              << "%" << endl
              << "% Warning : this file is generated automatically by Dynare" << endl
              << "%           from model file (.mod)" << endl << endl
@@ -465,11 +465,11 @@ StaticModel::writeStaticMWrapperFunction(const string &basename, const string &e
   else if (ending == "g3")
     name = "static_resid_g1_g2_g3";
 
-  string filename = packageDir(basename) + "/" + name + ".m";
+  filesystem::path filename {packageDir(basename) / (name + ".m")};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -513,11 +513,11 @@ StaticModel::writeStaticMFileHelper(const string &basename,
                                     const ostringstream &init_s, const ostringstream &end_s,
                                     const ostringstream &s, const ostringstream &s_tt) const
 {
-  string filename = packageDir(basename) + "/" + name_tt + ".m";
+  filesystem::path filename {packageDir(basename) / (name_tt + ".m")};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -545,11 +545,11 @@ StaticModel::writeStaticMFileHelper(const string &basename,
          << "end" << endl;
   output.close();
 
-  filename = packageDir(basename) + "/" + name + ".m";
+  filename = packageDir(basename) / (name + ".m");
   output.open(filename, ios::out | ios::binary);
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -585,11 +585,11 @@ StaticModel::writeStaticMFileHelper(const string &basename,
 void
 StaticModel::writeStaticMCompatFile(const string &basename) const
 {
-  string filename = packageDir(basename) + "/static.m";
+  filesystem::path filename {packageDir(basename) / "static.m"};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
   int ntt { static_cast<int>(temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size()) };
@@ -845,6 +845,16 @@ StaticModel::writeStaticFile(const string &basename, bool block, bool use_dll, c
   model_dir /= "model";
   if (use_dll)
     create_directories(model_dir / "src");
+  if (!julia)
+    {
+      auto plusfolder {packageDir(basename)};
+      /* The following is not a duplicate of the same call from
+         ModFile::writeMOutput(), because of planner_objective which needs its
+         +objective subdirectory */
+      create_directories(plusfolder);
+      if (block && !use_dll)
+        create_directories(plusfolder / "+block");
+    }
   create_directories(model_dir / "bytecode");
 
   if (block)
@@ -894,12 +904,12 @@ StaticModel::exoPresentInEqs() const
 void
 StaticModel::writeStaticBlockMFile(const string &basename) const
 {
-  string filename = packageDir(basename) + "/static.m";
+  filesystem::path filename {packageDir(basename) / "static.m"};
 
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -999,7 +1009,7 @@ StaticModel::writeStaticBlockCFile(const string &basename, vector<filesystem::pa
   output.close();
 
   per_block_object_files.push_back(filename);
-  compileMEX("+" + basename, "static", mexext, per_block_object_files, matlabroot, dynareroot);
+  compileMEX(packageDir(basename), "static", mexext, per_block_object_files, matlabroot, dynareroot);
 }
 
 void
@@ -1205,7 +1215,22 @@ StaticModel::writeSetAuxiliaryVariables(const string &basename, bool julia) cons
     output << "end" << endl
            << "end" << endl;
 
-  writeToFileIfModified(output, julia ? basename + "SetAuxiliaryVariables.jl" : packageDir(basename) + "/" + func_name + ".m");
+  if (julia)
+    writeToFileIfModified(output, basename + "SetAuxiliaryVariables.jl");
+  else
+    {
+      /* Calling writeToFileIfModified() is useless here since we write inside
+         a subdirectory deleted at each preprocessor run. */
+      filesystem::path filename {packageDir(basename) / (func_name + ".m")};
+      ofstream output_file{filename, ios::out | ios::binary};
+      if (!output_file.is_open())
+        {
+          cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
+          exit(EXIT_FAILURE);
+        }
+      output_file << output.str();
+      output_file.close();
+    }
 }
 
 void
diff --git a/src/StaticModel.hh b/src/StaticModel.hh
index dcc222f00f67d2c0792966c37a3d35362a5b1f04..4551ebd9fdf204b8f493d2912190a018576e573b 100644
--- a/src/StaticModel.hh
+++ b/src/StaticModel.hh
@@ -225,11 +225,11 @@ StaticModel::writeParamsDerivativesFile(const string &basename) const
     { writeParamsDerivativesFileHelper<output_type>() };
   // g3p_output is ignored
 
-  string filename { julia ? basename + "StaticParamsDerivs.jl" : packageDir(basename) + "/static_params_derivs.m" };
+  filesystem::path filename {julia ? filesystem::path{basename + "StaticParamsDerivs.jl"} : packageDir(basename) / "static_params_derivs.m"};
   ofstream paramsDerivsFile { filename, ios::out | ios::binary };
   if (!paramsDerivsFile.is_open())
     {
-      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
 
diff --git a/src/SubModel.cc b/src/SubModel.cc
index adc91816b48d9a608cfa64aff64e0ed557cf34fa..a4d080948e619d3983222e2ea44e6e86316e925d 100644
--- a/src/SubModel.cc
+++ b/src/SubModel.cc
@@ -246,11 +246,11 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
   if (names.empty())
     return;
 
-  string filename = "+" + basename + "/trend_component_ar_a0.m";
+  const filesystem::path filename {DataTree::packageDir(basename) / "trend_component_ar_a0.m"};
   ofstream ar_ec_output{filename, ios::out | ios::binary};
   if (!ar_ec_output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
   ar_ec_output << "function [AR, A0, A0star] = trend_component_ar_a0(model_name, params)" << endl
@@ -427,11 +427,11 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
   if (names.empty())
     return;
 
-  string filename = "+" + basename + "/varmatrices.m";
+  const filesystem::path filename {DataTree::packageDir(basename) / "varmatrices.m"};
   ofstream ar_output{filename, ios::out | ios::binary};
   if (!ar_output.is_open())
     {
-      cerr << "Error: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
   ar_output << "function [ar, a0, constants] = varmatrices(model_name, params, reducedform)" << endl
@@ -1751,11 +1751,11 @@ PacModelTable::writeTargetCoefficientsFile(const string &basename) const
   if (target_info.empty())
     return;
 
-  string filename = DataTree::packageDir(basename) + "/pac_target_coefficients.m";
+  filesystem::path filename {DataTree::packageDir(basename) / "pac_target_coefficients.m"};
   ofstream output{filename, ios::out | ios::binary};
   if (!output.is_open())
     {
-      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
+      cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
       exit(EXIT_FAILURE);
     }
   output << "function coeffs = pac_target_coefficients(model_name, params)" << endl;