#include "fesa/app/fesa_application.h" #include #include #include #include #include #include #include #include #include #include namespace { class TempDirectory { public: explicit TempDirectory(const std::string& label) { static std::atomic sequence{0U}; const auto tick = std::chrono::steady_clock::now().time_since_epoch().count(); path_ = std::filesystem::temp_directory_path() / ("fesa-surface-pressure-app-" + label + "-" + std::to_string(tick) + "-" + std::to_string(sequence.fetch_add(1U))); std::error_code error; if (!std::filesystem::create_directory(path_, error) || error) { throw std::runtime_error{"Unable to create application fixture."}; } } TempDirectory(const TempDirectory&) = delete; TempDirectory& operator=(const TempDirectory&) = delete; ~TempDirectory() { std::error_code ignored; std::filesystem::remove_all(path_, ignored); } const std::filesystem::path& Path() const noexcept { return path_; } private: std::filesystem::path path_; }; void WriteText(const std::filesystem::path& path, const std::string& text) { std::ofstream stream{path, std::ios::binary | std::ios::trunc}; stream.write(text.data(), static_cast(text.size())); if (!stream) { throw std::runtime_error{"Unable to write application input."}; } } std::vector ReadBytes(const std::filesystem::path& path) { std::ifstream stream{path, std::ios::binary}; return {std::istreambuf_iterator{stream}, std::istreambuf_iterator{}}; } std::string ShellDeck(const bool with_pressure, const bool collapsed) { const std::string third_node = collapsed ? "3, 1., 0., 0.\n" : "3, 1., 1., 0.\n"; const std::string surface = with_pressure ? "*Surface, TYPE=ELEMENT, NAME=Pressure\n" "Shell-1.1, SPOS\n" : ""; const std::string dsload = with_pressure ? "*Dsload\nPressure, P, 4.0\n" : ""; return std::string{R"inp(*Part, name=ShellPart *Node 1, 0., 0., 0. 2, 1., 0., 0. )inp"} + third_node + R"inp(4, 0., 1., 0. *Element, type=S4 1, 1, 2, 3, 4 *Elset, elset=ShellSet 1 *Shell Section, elset=ShellSet, material=Steel 0.1 *End Part *Assembly, name=Assembly *Instance, name=Shell-1, part=ShellPart *End Instance )inp" + surface + R"inp(*Nset, nset=All, instance=Shell-1 1, 2, 3, 4 *End Assembly *Material, name=Steel *Elastic 1000., 0.25 *Boundary All, 1, 6 *Step, name=Load, nlgeom=NO *Static 0.1, 1., 0.01, 1. )inp" + dsload + "*End Step\n"; } } // namespace TEST(ShellSurfacePressureApplication, LinearFailurePreservesExistingFinalAndNoCandidate) { TempDirectory directory{"preserve-final"}; const auto input = directory.Path() / "invalid-pressure.inp"; const auto output = directory.Path() / "invalid-pressure_results.h5"; WriteText(input, ShellDeck(true, true)); const std::vector previous{'p', 'r', 'i', 'o', 'r'}; { std::ofstream stream{output, std::ios::binary | std::ios::trunc}; stream.write(previous.data(), static_cast(previous.size())); } const int exit_code = fesa::FesaApplication{}.Run({input.string()}); EXPECT_NE(exit_code, 0); EXPECT_EQ(ReadBytes(output), previous); } TEST(ShellSurfacePressureApplication, InputWithoutPressureRetainsExistingLinearBehavior) { TempDirectory directory{"no-pressure"}; const auto input = directory.Path() / "no-pressure.inp"; const auto output = directory.Path() / "no-pressure_results.h5"; WriteText(input, ShellDeck(false, false)); EXPECT_EQ(fesa::FesaApplication{}.Run({input.string()}), 0); ASSERT_TRUE(std::filesystem::exists(output)); ASSERT_GT(H5Fis_hdf5(output.string().c_str()), 0); const hid_t file = H5Fopen(output.string().c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); ASSERT_GE(file, 0); EXPECT_GT(H5Lexists(file, "/steps/Step-1/frames/0/nodal/displacement", H5P_DEFAULT), 0); EXPECT_EQ(H5Lexists(file, "/steps/Step-1/frames/0/surface_pressure", H5P_DEFAULT), 0); EXPECT_GE(H5Fclose(file), 0); }