diff --git a/CHANGELOG b/CHANGELOG index f2fa05fd..6d17d65b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ Version 4.5.1 (development) =========================== + - Added a 'cutting_plane' script command to set the cutting plane orientation (phi, theta in degrees), translation, kind, and algorithm in a single command: 'cutting_plane [ []]'. @@ -27,6 +28,11 @@ Version 4.5.1 (development) They can only be issued after parallel streams have been initialized with the 'parallel' command (if used). +- Added a script command 'pmesh ' that loads a parallel mesh + without a solution. Like 'mesh', it captures reference nodes on the first load + and visualizes displacement on subsequent 'pmesh' loads. + + Version 4.5 released on Feb 6, 2026 =================================== diff --git a/lib/file_reader.cpp b/lib/file_reader.cpp index d046eef3..40adaf6a 100644 --- a/lib/file_reader.cpp +++ b/lib/file_reader.cpp @@ -29,9 +29,9 @@ int FileReader::ReadSerial(FileReader::FileType ft, const char *mesh_file, data.SetMesh(new Mesh(meshin, 1, 0, data.fix_elem_orient)); - if (ft == FileType::MESH) + if (ft == FileType::MESH || ft == FileType::MESH_ONLY) { - data.SetMeshSolution(); + if (ft == FileType::MESH) { data.SetMeshSolution(); } } else { @@ -114,7 +114,9 @@ int FileReader::ReadParallel(int np, FileType ft, const char *mesh_file, switch (ft) { case FileType::MESH: - read_err = ReadParMeshAndGridFunction(np, mesh_file, NULL); + case FileType::MESH_ONLY: + read_err = ReadParMeshAndGridFunction(np, mesh_file, NULL, component, + ft == FileType::MESH); break; case FileType::GRID_FUNC: read_err = ReadParMeshAndGridFunction(np, mesh_file, sol_file, component); @@ -146,7 +148,9 @@ bool FileReader::CheckStreamIsComplex(std::istream &solin, bool parallel) } int FileReader::ReadParMeshAndGridFunction(int np, const char *mesh_prefix, - const char *sol_prefix, int component) + const char *sol_prefix, + int component, + bool generate_mesh_solution) { data.SetMesh(NULL); @@ -263,7 +267,7 @@ int FileReader::ReadParMeshAndGridFunction(int np, const char *mesh_prefix, data.SetGridFunction(gf_array, np, component); } } - else + else if (generate_mesh_solution) { data.SetMeshSolution(); } diff --git a/lib/file_reader.hpp b/lib/file_reader.hpp index 23e3b9f8..c1afb9a0 100644 --- a/lib/file_reader.hpp +++ b/lib/file_reader.hpp @@ -22,7 +22,8 @@ class FileReader static bool CheckStreamIsComplex(std::istream &sol, bool parallel = false); int ReadParMeshAndGridFunction(int np, const char *mesh_prefix, - const char *sol_prefix, int component = -1); + const char *sol_prefix, int component = -1, + bool generate_mesh_solution = true); int ReadParMeshAndQuadFunction(int np, const char *mesh_prefix, const char *sol_prefix, int component = -1); @@ -30,6 +31,7 @@ class FileReader enum class FileType { MESH, + MESH_ONLY, ///< Mesh geometry without a generated coloring grid function. SCALAR_SOL, VECTOR_SOL, GRID_FUNC, diff --git a/lib/script_controller.cpp b/lib/script_controller.cpp index adb3e729..d5ffb156 100644 --- a/lib/script_controller.cpp +++ b/lib/script_controller.cpp @@ -29,6 +29,7 @@ using namespace mfem; enum class Command { Mesh, + ParMesh, Solution, ParSolution, Quadrature, @@ -95,6 +96,7 @@ static const ScriptCommands commands; ScriptCommands::ScriptCommands() { (*this)[Command::Mesh] = {"mesh", "", "Visualize the mesh."}; + (*this)[Command::ParMesh] = {"pmesh", " ", "Visualize the distributed mesh."}; (*this)[Command::Solution] = {"solution", " ", "Visualize the solution."}; (*this)[Command::ParSolution] = {"psolution", " ", "Visualize the distributed solution."}; (*this)[Command::Quadrature] = {"quadrature", " ", "Visualize the quadrature."}; @@ -256,24 +258,46 @@ int ScriptController::ScriptReadParQuadrature(istream &scr, DataState &state) return err_read; } -int ScriptController::ScriptReadDisplMesh(istream &scr, DataState &state) +int ScriptController::ScriptReadDisplMesh(istream &scr, DataState &state, + bool parallel) { DataState meshstate; string word; + int np = 1; - cout << "Script: mesh: " << flush; - scr >> ws >> word; + cout << "Script: " << (parallel ? "pmesh" : "mesh") << ": " << flush; + if (parallel) { - named_ifgzstream imesh(word.c_str()); - if (!imesh) + if (!(scr >> np)) { - cout << "Can not open mesh file: " << word << endl; + cout << "Error reading the number of processors." << endl; return 1; } - cout << word << endl; - meshstate.SetMesh(new Mesh(imesh, 1, 0, state.fix_elem_orient)); + if (np <= 0) + { + cout << "Invalid number of processors: " << np << endl; + return 1; + } + cout << "# processors: " << np << "; " << flush; } - meshstate.ExtrudeMeshAndSolution(); + if (!(scr >> ws >> word)) + { + cout << "Error reading the mesh " << (parallel ? "prefix" : "filename") + << endl; + return 1; + } + cout << word << endl; + + meshstate.keep_attr = state.keep_attr; + meshstate.fix_elem_orient = state.fix_elem_orient; + FileReader reader(meshstate); + int read_err = parallel ? + reader.ReadParallel(np, FileReader::FileType::MESH_ONLY, + word.c_str(), NULL) : + reader.ReadSerial(FileReader::FileType::MESH_ONLY, + word.c_str(), NULL); + if (read_err) { return read_err; } + Mesh* const m = meshstate.mesh.get(); if (init_nodes == NULL) { @@ -420,6 +444,7 @@ bool ScriptController::ExecuteScriptCommand() switch (cmd) { case Command::Mesh: + case Command::ParMesh: case Command::Solution: case Command::ParSolution: case Command::Quadrature: @@ -428,7 +453,7 @@ bool ScriptController::ExecuteScriptCommand() case Command::DataCollField: case Command::DataCollQuad: { - DataState new_state; + DataState new_state = win.data_state.CloneEmpty(); switch (cmd) { @@ -447,14 +472,17 @@ bool ScriptController::ExecuteScriptCommand() } break; case Command::Mesh: - if (ScriptReadDisplMesh(scr, new_state)) + case Command::ParMesh: + if (ScriptReadDisplMesh(scr, new_state, + cmd == Command::ParMesh)) { done_one_command = 1; continue; } if (new_state.mesh == NULL) { - cout << "Script: unexpected 'mesh' command!" << endl; + cout << "Script: unexpected '" << word << "' command!" + << endl; done_one_command = 1; continue; } @@ -1019,7 +1047,9 @@ void ScriptController::PlayScript(Window win, istream &scr) done = true; // start the visualization break; case Command::Mesh: - if (script.ScriptReadDisplMesh(scr, script.win.data_state)) + case Command::ParMesh: + if (script.ScriptReadDisplMesh(scr, script.win.data_state, + cmd == Command::ParMesh)) { return; } diff --git a/lib/script_controller.hpp b/lib/script_controller.hpp index 331e6cec..08b50b5a 100644 --- a/lib/script_controller.hpp +++ b/lib/script_controller.hpp @@ -37,7 +37,8 @@ class ScriptController static int ScriptReadQuadrature(std::istream &scr, DataState &state); static int ScriptReadParSolution(std::istream &scr, DataState &state); static int ScriptReadParQuadrature(std::istream &scr, DataState &state); - int ScriptReadDisplMesh(std::istream &scr, DataState &state); + int ScriptReadDisplMesh(std::istream &scr, DataState &state, + bool parallel = false); int ScriptReadDataColl(std::istream &scr, DataState &state, bool mesh_only = true, bool quad = false);