Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/tools_gpl/pre_c_sumo/include/FF2NF_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ namespace pre_c_sumo
FarFieldPoint2D diffuser;
std::optional<FarFieldPoint2D> intake;
std::vector<FarFieldPoint2D> ambient_points;
/// Optional copy of the raw &lt;settings&gt; XML node from the C-SUMO configuration file.
/// When set, the node is copied verbatim as a &lt;settings&gt; child of &lt;COSUMO&gt;
/// in the generated FF2NF file. The source document must remain alive until generate()
/// or toFile() has returned.
pugi::xml_node settings_xml_node;
};

/**
Expand Down Expand Up @@ -96,6 +101,7 @@ namespace pre_c_sumo
void createFileVersionSection(pugi::xml_node& root) const;
void createCommSection(pugi::xml_node& root) const;
void createSubgridModelSection(pugi::xml_node& root) const;
void createSettingsSection(pugi::xml_node& root) const;
};
} // namespace pre_c_sumo
#endif // SRC_TOOLS_GPL_PRE_C_SUMO_FF2NF_WRITER_HPP
13 changes: 12 additions & 1 deletion src/tools_gpl/pre_c_sumo/include/csumo_settings_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <expected>
#include <filesystem>
#include <optional>
#include <pugixml.hpp>
#include <string>
#include <string_view>
#include <vector>
Expand Down Expand Up @@ -66,6 +67,11 @@ namespace pre_c_sumo
// --- comm section ---
std::filesystem::path ff2nf_dir; ///< Directory for FF2NF communication files (&lt;FF2NFdir&gt;)
std::filesystem::path ff_run_dir; ///< Far-field model run directory (&lt;FFrundir&gt;)

// --- raw XML ---
pugi::xml_node settings_xml_node; ///< The raw &lt;settings&gt; XML node from the parsed document.
///< Valid for as long as the owning CSumoSettingsReader is alive.
///< Use pugi::xml_node::append_copy() to insert it into another document.
};

/**
Expand Down Expand Up @@ -107,14 +113,19 @@ namespace pre_c_sumo

/**
* @brief All diffuser settings blocks read from the XML, in document order.
*
* Each @ref DiffuserSettings also carries its raw @c settings_xml_node, which is valid
* for as long as this CSumoSettingsReader object is alive.
*/
[[nodiscard]] const std::vector<DiffuserSettings>& diffusers() const;

private:
explicit CSumoSettingsReader(std::string file_version, std::vector<DiffuserSettings> diffusers);
explicit CSumoSettingsReader(std::string file_version, std::vector<DiffuserSettings> diffusers,
pugi::xml_document document);

std::string file_version_;
std::vector<DiffuserSettings> diffusers_;
pugi::xml_document document_;
};
} // namespace pre_c_sumo

Expand Down
4 changes: 3 additions & 1 deletion src/tools_gpl/pre_c_sumo/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ add_library(pre_c_sumo_lib ${source_files} ${header_files})
target_link_libraries(pre_c_sumo_lib PRIVATE
compiler_warnings_settings
precice::precice
pugixml::pugixml
Boost::headers
)
target_link_libraries(pre_c_sumo_lib PUBLIC
pugixml::pugixml
)

target_include_directories(pre_c_sumo_lib PUBLIC ${include_dir})

Expand Down
19 changes: 17 additions & 2 deletions src/tools_gpl/pre_c_sumo/src/FF2NF_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ namespace
return {};
}

static constexpr size_t indent_size = 4;
static constexpr char indent_chars[] = " "; // indent_size spaces
static_assert(std::char_traits<char>::length(indent_chars) == indent_size);

struct IndentTextWalker : pugi::xml_tree_walker
{
bool for_each(pugi::xml_node& node) override
Expand All @@ -167,7 +171,6 @@ namespace
// Inline text does not need indentation
return true;
}
constexpr size_t indent_size = 4;
const auto current_depth = static_cast<size_t>(depth());
const std::string indent(current_depth * indent_size, ' ');
const std::string parent_indent(current_depth > 0 ? (current_depth - 1) * indent_size : 0, ' ');
Expand Down Expand Up @@ -199,10 +202,11 @@ namespace pre_c_sumo
createFileVersionSection(root);
createCommSection(root);
createSubgridModelSection(root);
createSettingsSection(root);
IndentTextWalker indent_walker;
document.traverse(indent_walker);
std::ostringstream oss;
document.save(oss);
document.save(oss, indent_chars);
return oss.str();
}

Expand Down Expand Up @@ -294,4 +298,15 @@ namespace pre_c_sumo
}
addFarFieldPoints(subgrid_model, "FFAmbient", config_.ambient_points);
}

void FF2NFWriter::createSettingsSection(pugi::xml_node& root) const
{
// The settings_xml_node is an unowned handle into the caller's pugi::xml_document.
// append_copy() performs a deep copy, so the source document can be released
// immediately after generate() / toFile() returns.
if (config_.settings_xml_node)
{
root.append_copy(config_.settings_xml_node);
}
}
} // namespace pre_c_sumo
5 changes: 3 additions & 2 deletions src/tools_gpl/pre_c_sumo/src/coupling_steps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ namespace pre_c_sumo
std::println(stderr, "Error parsing C-SUMO configuration: {}", expectedCsumoSettings.error().message);
return expectedCsumoSettings;
}
const auto csumo_settings = std::move(expectedCsumoSettings).value();
auto csumo_settings = std::move(expectedCsumoSettings).value();
std::println("Successfully parsed C-SUMO configuration file version: {}", csumo_settings.fileVersion());
return csumo_settings;
return std::move(csumo_settings);
}

void receiveFFData() { std::println("Receiving far-field data..."); }
Expand Down Expand Up @@ -76,6 +76,7 @@ namespace pre_c_sumo
.diffuser = make_point(diffuser.position),
.intake = diffuser.intake.has_value() ? std::optional{make_point(*diffuser.intake)} : std::nullopt,
.ambient_points = ambient_points,
.settings_xml_node = diffuser.settings_xml_node,
};

const auto result = FF2NFWriter(std::move(ff2nf_config)).toFile(ff2nf_filename);
Expand Down
9 changes: 6 additions & 3 deletions src/tools_gpl/pre_c_sumo/src/csumo_settings_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <sstream>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "monadic_utils.hpp"
Expand Down Expand Up @@ -203,6 +204,7 @@ namespace
.nf2ff_file = std::move(data.nf2ff_file),
.ff2nf_dir = std::move(comm.ff2nf_dir),
.ff_run_dir = std::move(comm.ff_run_dir),
.settings_xml_node = settings_node,
};
}

Expand Down Expand Up @@ -275,11 +277,12 @@ namespace pre_c_sumo
ASSIGN_OR_RETURN(const auto root, validateRoot(doc));
ASSIGN_OR_RETURN(auto file_version, parseFileVersion(root));
ASSIGN_OR_RETURN(auto diffusers, parseAllDiffusers(root));
return CSumoSettingsReader{std::move(file_version), std::move(diffusers)};
return CSumoSettingsReader{std::move(file_version), std::move(diffusers), std::move(doc)};
}

CSumoSettingsReader::CSumoSettingsReader(std::string file_version, std::vector<DiffuserSettings> diffusers)
: file_version_{std::move(file_version)}, diffusers_{std::move(diffusers)}
CSumoSettingsReader::CSumoSettingsReader(std::string file_version, std::vector<DiffuserSettings> diffusers,
pugi::xml_document document)
: file_version_{std::move(file_version)}, diffusers_{std::move(diffusers)}, document_{std::move(document)}
{
}

Expand Down
98 changes: 98 additions & 0 deletions src/tools_gpl/pre_c_sumo/test/test_FF2NF_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,101 @@ TEST(FF2NFWriterTest, DISABLED_WriteToFile)
ASSERT_TRUE(result.has_value()) << result.error().message;
EXPECT_TRUE(std::filesystem::exists("FF2NF_test_output.xml"));
}

// ---------------------------------------------------------------------------
// Settings section (copied from the C-SUMO configuration file)
// ---------------------------------------------------------------------------

TEST(FF2NFWriterTest, NoSettingsSectionWhenNodeNotSet)
{
// Default config has no settings_xml_node — the <settings> element must be absent.
const auto document = generateDocument(buildExampleConfig());
EXPECT_FALSE(document.select_node("COSUMO/settings")) << "<settings> should not appear when node is not set";
}

TEST(FF2NFWriterTest, SettingsSectionIsPresentWhenNodeIsSet)
{
// Build a minimal <settings> node and attach it to the config.
pugi::xml_document settings_document;
settings_document.load_string("<settings><general><id>Diffusor_1</id></general></settings>");

auto config = buildExampleConfig();
config.settings_xml_node = settings_document.document_element();

const auto document = generateDocument(std::move(config));
expectNodeExists(document, "COSUMO/settings");
}

TEST(FF2NFWriterTest, SettingsSectionContentIsCorrectlyCopied)
{
// All child elements and their text values must survive the copy.
pugi::xml_document settings_document;
settings_document.load_string(
R"(<settings><general><id>Diffusor_1</id></general><data><XYdiff>550.0 350.0</XYdiff></data></settings>)");

auto config = buildExampleConfig();
config.settings_xml_node = settings_document.document_element();

const auto document = generateDocument(std::move(config));
EXPECT_EQ(nodeText(document, "COSUMO/settings/general/id"), "Diffusor_1");
EXPECT_EQ(nodeText(document, "COSUMO/settings/data/XYdiff"), "550.0 350.0");
}

TEST(FF2NFWriterTest, SettingsSectionComesAfterSubgridModelInOutput)
{
pugi::xml_document settings_document;
settings_document.load_string("<settings><general><id>A</id></general></settings>");

auto config = buildExampleConfig();
config.settings_xml_node = settings_document.document_element();

const auto xml = pre_c_sumo::FF2NFWriter(std::move(config)).generate();
ASSERT_TRUE(xml.has_value()) << xml.error().message;

const auto subgrid_pos = (*xml).find("<SubgridModel>");
const auto settings_pos = (*xml).find("<settings>");
ASSERT_NE(subgrid_pos, std::string::npos);
ASSERT_NE(settings_pos, std::string::npos);
EXPECT_LT(subgrid_pos, settings_pos) << "<SubgridModel> must appear before <settings>";
}

TEST(FF2NFWriterTest, SettingsSectionIsIndentedAtSameLevelAsSubgridModel)
{
// <settings> and <SubgridModel> are both direct children of <COSUMO> (depth 1),
// so they must both be preceded by 4 spaces (1 level × 4 spaces).
// Their direct children sit at depth 2, so 8 spaces.
pugi::xml_document settings_document;
settings_document.load_string("<settings><general><id>A</id></general></settings>");

auto config = buildExampleConfig();
config.settings_xml_node = settings_document.document_element();

const auto xml = pre_c_sumo::FF2NFWriter(std::move(config)).generate();
ASSERT_TRUE(xml.has_value()) << xml.error().message;
const auto& text = *xml;

// <settings> open tag should be indented at depth 1 (4 spaces)
const auto settings_open = text.find("<settings>");
ASSERT_NE(settings_open, std::string::npos);
const auto settings_line_start = text.rfind('\n', settings_open);
ASSERT_NE(settings_line_start, std::string::npos);
const auto settings_indent = settings_open - settings_line_start - 1;
EXPECT_EQ(settings_indent, 4u) << "Expected <settings> indent of 4 spaces, got " << settings_indent;

// <general> is a direct child of <settings> (depth 2), so 8 spaces
const auto general_open = text.find("<general>", settings_open);
ASSERT_NE(general_open, std::string::npos);
const auto general_line_start = text.rfind('\n', general_open);
ASSERT_NE(general_line_start, std::string::npos);
const auto general_indent = general_open - general_line_start - 1;
EXPECT_EQ(general_indent, 8u) << "Expected <general> indent of 8 spaces, got " << general_indent;

// </settings> closing tag should also be at depth 1 (4 spaces)
const auto settings_close = text.find("</settings>");
ASSERT_NE(settings_close, std::string::npos);
const auto settings_close_line_start = text.rfind('\n', settings_close);
ASSERT_NE(settings_close_line_start, std::string::npos);
const auto settings_close_indent = settings_close - settings_close_line_start - 1;
EXPECT_EQ(settings_close_indent, 4u)
<< "Expected </settings> indent of 4 spaces, got " << settings_close_indent;
}
Loading