Commit 15eb18a5 authored by Mario Morales Hernandez's avatar Mario Morales Hernandez
Browse files

output directory fixes

  1. SWMM Output Directory Fix

  Make SWMM output respect output_folder config

  - Add output_folder member to swmm_triton class
  - Pass output_folder through initialize() instead of using hardcoded OUTPUT_DIR
  - Replace hardcoded "output/swmm/" paths with configurable output_folder
  - Update call sites in triton.h

  2. Path Normalization

  Improve output_folder path handling

  - Add normalize_path() to strip trailing slashes
  - Add build_output_path() to handle absolute vs relative paths
  - Add create_directories_recursive() for nested directory creation
  - Update log functions to accept and use output_folder parameter
  - Add get_output_folder() getter to triton class
  - Update main.cpp to pass output_folder to log calls
parent 1642a7d4
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -88,13 +88,13 @@ int main(int argc, char* argv[])
    model.initialize(rank, size);

    // Write run log header
    Output::triton_log_run_header(model.get_project_dir(), rank, size);
    Output::triton_log_run_header(model.get_project_dir(), model.get_output_folder(), rank, size);

    //simulate
    model.simulate();

    // Write simulation time from timer
    Output::triton_log_total_time(model.get_project_dir(), model.get_simulation_time(), rank);
    Output::triton_log_total_time(model.get_project_dir(), model.get_output_folder(), model.get_simulation_time(), rank);
  }
  Kokkos::finalize();
#ifdef ENSEMBLE_BUILD
+99 −14
Original line number Diff line number Diff line
@@ -1608,6 +1608,92 @@ namespace Output
	}


/** @brief Normalize a path by removing trailing slashes and handling empty paths.
*
*  @param path The input path to normalize
*  @return Normalized path without trailing slash (or empty string if input is empty)
*/
inline std::string normalize_path(std::string path)
{
	if (path.empty()) return path;

	// Remove trailing slashes
	size_t end = path.find_last_not_of("/");
	if (end != std::string::npos)
	{
		path = path.substr(0, end + 1);
	}

	return path;
}


/** @brief Build output directory path by joining project_dir and output_folder.
*
*  This function handles absolute paths correctly - if output_folder is absolute,
*  it is used as-is. If relative, it is joined with project_dir.
*
*  @param project_dir The project directory path
*  @param output_folder The output folder from config (may be absolute or relative)
*  @return Normalized output directory path
*/
inline std::string build_output_path(std::string project_dir, std::string output_folder)
{
	project_dir = normalize_path(project_dir);
	output_folder = normalize_path(output_folder);

	if (output_folder.empty()) return project_dir;

	// Check if output_folder is an absolute path
	if (output_folder[0] == '/')
	{
		return output_folder;
	}

	// Relative path - join with project_dir
	return project_dir + "/" + output_folder;
}


/** @brief Recursively create directories for a given path.
*
*  This function creates all parent directories if they don't exist.
*
*  @param path The full directory path to create
*  @return true if successful or directory already exists, false on failure
*/
inline bool create_directories_recursive(const std::string& path)
{
	if (path.empty()) return false;

	// Check if directory already exists
	DIR* dir = opendir(path.c_str());
	if (dir)
	{
		closedir(dir);
		return true;
	}

	// Find the last separator and recursively create parent directories
	size_t pos = path.find_last_of("/");
	if (pos == 0 || pos == std::string::npos)
	{
		// Root directory or no more parents - try direct mkdir
		return (mkdir(path.c_str(), S_IRWXU) == 0 || errno == EEXIST);
	}

	// Recursively create parent directory
	std::string parent = path.substr(0, pos);
	if (!create_directories_recursive(parent))
	{
		return false;
	}

	// Create the final directory
	return (mkdir(path.c_str(), S_IRWXU) == 0 || errno == EEXIST);
}


/** @brief Writes the TRITON run header to output/log.out
*
*  This function writes run configuration information including machine,
@@ -1615,25 +1701,20 @@ namespace Output
*  Only MPI rank 0 writes to the file.
*
*  @param project_dir The project directory path
*  @param output_folder The output folder from config (may be empty for default)
*  @param rank Current MPI rank
*  @param size Total number of MPI ranks
*/
inline void triton_log_run_header(std::string project_dir, int rank, int size)
inline void triton_log_run_header(std::string project_dir, std::string output_folder, int rank, int size)
{
	// Only rank 0 writes the log header
	if (rank != 0) return;

	// Create output directory if it doesn't exist
	std::string outdir = project_dir + "/" + OUTPUT_DIR;
	DIR* dir = opendir(outdir.c_str());
	if (!dir)
	{
		mkdir(outdir.c_str(), S_IRWXU);
	}
	else
	{
		closedir(dir);
	}
	// Build output path using helper function
	std::string outdir = build_output_path(project_dir, output_folder);

	// Create output directory recursively if it doesn't exist
	create_directories_recursive(outdir);

	// Open log file
	std::string logfile = outdir + "/log.out";
@@ -1754,16 +1835,20 @@ inline void triton_log_run_header(std::string project_dir, int rank, int size)
*  Only MPI rank 0 writes to the file.
*
*  @param project_dir The project directory path
*  @param output_folder The output folder from config (may be empty for default)
*  @param total_time_sec Total wall time in seconds
*  @param rank Current MPI rank
*/
inline void triton_log_total_time(std::string project_dir, double total_time_sec, int rank)
inline void triton_log_total_time(std::string project_dir, std::string output_folder, double total_time_sec, int rank)
{
	// Only rank 0 writes the log
	if (rank != 0) return;

	// Build output path using helper function
	std::string outdir = build_output_path(project_dir, output_folder);

	// Append to log file
	std::string logfile = project_dir + "/" + OUTPUT_DIR + "/log.out";
	std::string logfile = outdir + "/log.out";
	std::ofstream log(logfile, std::ios::app);

	if (log.is_open())
+8 −4
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ namespace SWMM_triton
*  @param rank_ Subdomain id
*  @param size_ Number of subdomain
*/
		void initialize(int rank, int size, std::string inp_filename, std::string project_dir, const value_t  xll, const value_t  yll, const value_t  dx, const int global_rows, const int global_cols, const MpiUtils::partition_data_t pd, const value_t manhole_diameter, const value_t manhole_loss);
		void initialize(int rank, int size, std::string inp_filename, std::string project_dir, std::string output_folder, const value_t  xll, const value_t  yll, const value_t  dx, const int global_rows, const int global_cols, const MpiUtils::partition_data_t pd, const value_t manhole_diameter, const value_t manhole_loss);


		void end_swmm(std::string output_dir);
@@ -65,6 +65,8 @@ namespace SWMM_triton
		void local_to_global(value_t*  local, value_t*  global, int* dict);
		void global_to_local(value_t*  global, value_t*  local, int* dict);

		std::string get_output_folder() const { return output_folder; }

		int num_of_swmm_links; /**< Number of SWMM nodes connected to the surface per subdomain */
		int num_of_swmm_nodes; /**< Number of SWMM total nodes */
		int global_num_of_swmm_links; /**< Number of total (full domain) SWMM nodes connected to the surface */
@@ -94,6 +96,7 @@ namespace SWMM_triton
		int* node_to_rank_dict = NULL;

	private:
		std::string output_folder; /**< Output folder path from config */

		int calc_swmm_node_col(value_t  node_x, value_t  xllc, value_t  cell_size_);

@@ -126,11 +129,12 @@ namespace SWMM_triton



	void swmm_triton::initialize(int rank, int size, std::string inp_filename, std::string project_dir, const value_t  xll, const value_t  yll, const value_t  dx, const int global_rows, const int global_cols, const MpiUtils::partition_data_t pd, const value_t manhole_diameter, const value_t manhole_loss)
	void swmm_triton::initialize(int rank, int size, std::string inp_filename, std::string project_dir, std::string output_folder, const value_t  xll, const value_t  yll, const value_t  dx, const int global_rows, const int global_cols, const MpiUtils::partition_data_t pd, const value_t manhole_diameter, const value_t manhole_loss)
	{
		rank_=rank;
		size_=size;
		units=0;
		this->output_folder = output_folder;

		read_inp_file(inp_filename,dx, manhole_diameter, manhole_loss);
		process_swmm_node_locations(xll, yll, dx, global_rows, global_cols, pd);
@@ -440,8 +444,8 @@ namespace SWMM_triton
    		std::string filenameWithoutPath = inp_filename.substr(inp_filename.find_last_of("/\\") + 1);
			std::string filenameWithoutExtension = filenameWithoutPath.substr(0, filenameWithoutPath.rfind("."));

			std::string root_dir(project_dir + "/" + OUTPUT_DIR + "/");
			std::string output_dir_swmm = project_dir + "/" + OUTPUT_DIR + "/swmm/";
			std::string root_dir(project_dir + "/" + output_folder + "/");
			std::string output_dir_swmm = project_dir + "/" + output_folder + "/swmm/";


			DIR* dir;
+9 −2
Original line number Diff line number Diff line
@@ -78,6 +78,13 @@ namespace Triton
    double get_simulation_time() { return st.get_custom_time(SIMULATION_TIME); }


/** @brief Gets the output folder path from config.
*
*  @return The output folder path
*/
    std::string get_output_folder() const { return arglist.output_folder; }


  private:
    int rank; /**< Current subdomain id */
    int size; /**< Total sumber of subdomains */
@@ -418,7 +425,7 @@ namespace Triton
#ifdef TRITON_SWMM
    // Initialize SWMM coupling
    swmm_local_elapsedTime = 0.0;
    swmm_model.initialize(rank, size, arglist.inp_filename, project_dir, dem.get_xll_corner(),
    swmm_model.initialize(rank, size, arglist.inp_filename, project_dir, arglist.output_folder, dem.get_xll_corner(),
                          dem.get_yll_corner(), cell_size, org_rows, org_cols, pd,
                          arglist.manhole_diameter, arglist.manhole_loss);
#endif
@@ -2201,7 +2208,7 @@ namespace Triton
#ifdef TRITON_SWMM
    // Finalize SWMM coupling
    if (swmm_model.num_of_swmm_links > 0) {
      std::string output_dir_swmm = project_dir + "/" + OUTPUT_DIR + "/swmm/";
      std::string output_dir_swmm = project_dir + "/" + swmm_model.get_output_folder() + "/swmm/";
      swmm_model.end_swmm(output_dir_swmm);
    }
#endif