diff --git a/docs/inputs.rst b/docs/inputs.rst index ff6d1b41..2721d319 100644 --- a/docs/inputs.rst +++ b/docs/inputs.rst @@ -429,7 +429,15 @@ outputs are wanted. Eight output properties are currently possible: - c – internal damping force at each segment - s – strain of each segment - d – rate of strain of each segment - + - f – net node force + - W – weight at each node + - B – buoyancy force at each node + - P – dynamic pressure at each node + - X – transverse drag force at each node + - Y – tangential drag force at each node + - A – transverse fluid inertia force at each node + - a – tangential fluid inertia force at each node + - b – bottom contact force For example, outputting node positions and segment tensions could be achieved by writing “pt” for this last column. These outputs will go to a dedicated output file for each rod. For sending values to the global output file, use the Outputs section instead. diff --git a/source/Line.cpp b/source/Line.cpp index 2e738d0f..206dfeca 100644 --- a/source/Line.cpp +++ b/source/Line.cpp @@ -35,6 +35,7 @@ #include "Util/Interp.hpp" #include // #include +#include #ifdef USE_VTK #include "Util/VTK_Util.hpp" @@ -46,6 +47,10 @@ #include #endif +// Formating constants for line files outputs (iomanip) +constexpr int WIDTH = 20; // Width for output +constexpr int PRECISION = 7; // Precision for output + using namespace std; namespace moordyn { @@ -302,80 +307,87 @@ Line::initialize() // 1st line with the fields // output time - *outfile << "Time" - << "\t "; + *outfile << setw(10) << right + << "Time"; // output positions if (channels.find("p") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "px \t Node" << i << "py \t Node" - << i << "pz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "px") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "py") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "pz"); } } // output curvatures if (channels.find("K") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "Ku \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Ku"); } } // output velocities if (channels.find("v") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "vx \t Node" << i << "vy \t Node" - << i << "vz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "vx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "vy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "vz"); } } // output wave velocities if (channels.find("U") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "Ux \t Node" << i << "Uy \t Node" - << i << "Uz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Ux") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Uy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Uz"); } } // output hydro force if (channels.find("D") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "Dx \t Node" << i << "Dy \t Node" - << i << "Dz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dz"); } } // output VIV lift force if (channels.find("V") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "Vx \t Node" << i << "Vy \t Node" - << i << "Vz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Vx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Vy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Vz"); } } // output segment tensions if (channels.find("t") != string::npos) { for (unsigned int i = 1; i <= N; i++) { - *outfile << "Seg" << i << "Te \t "; + *outfile << setw(WIDTH) << right << ("Seg" + to_string((int)i) + "Te"); } } // output internal damping force if (channels.find("c") != string::npos) { for (unsigned int i = 1; i <= N; i++) { - *outfile << "Seg" << i << "cx \t Seg" << i << "cy \t Seg" << i - << "cz \t "; + *outfile << setw(WIDTH) << right << ("Seg" + to_string((int)i) + "cx") + << setw(WIDTH) << right << ("Seg" + to_string((int)i) + "cy") + << setw(WIDTH) << right << ("Seg" + to_string((int)i) + "cz"); } } // output segment strains if (channels.find("s") != string::npos) { for (unsigned int i = 1; i <= N; i++) { - *outfile << "Seg" << i << "St \t "; + *outfile << setw(WIDTH) << right << ("Seg" + to_string((int)i) + "St"); } } // output segment strain rates if (channels.find("d") != string::npos) { for (unsigned int i = 1; i <= N; i++) { - *outfile << "Seg" << i << "dSt \t "; + *outfile << setw(WIDTH) << right << ("Seg" + to_string((int)i) + "dSt"); } } // output seabed contact forces if (channels.find("b") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "bx \t Node" << i << "by \t Node" - << i << "bz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "bx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "by") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "bz"); } } @@ -385,64 +397,75 @@ Line::initialize() // 2nd line with the units // output time - *outfile << "(s)" - << "\t "; + *outfile << setw(10) << right + << "(s)"; // output positions if (channels.find("p") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(m) \t"; + *outfile << setw(WIDTH) << right + << "(m)"; } // output curvatures? if (channels.find("K") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "(1/m) \t "; + *outfile << setw(WIDTH) << right + << "(1/m)"; } } // output velocities? if (channels.find("v") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(m/s) \t"; + *outfile << setw(WIDTH) << right + << "(m/s)"; } // output wave velocities? if (channels.find("U") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(m/s) \t"; + *outfile << setw(WIDTH) << right + << "(m/s)"; } // output hydro force if (channels.find("D") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(N) \t"; + *outfile << setw(WIDTH) << right + << "(N)"; } // output VIV force if (channels.find("V") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(N) \t"; + *outfile << setw(WIDTH) << right + << "(N)"; } // output segment tensions? if (channels.find("t") != string::npos) { for (unsigned int i = 0; i < N; i++) - *outfile << "(N) \t"; + *outfile << setw(WIDTH) << right + << "(N)"; } // output internal damping force? if (channels.find("c") != string::npos) { for (unsigned int i = 0; i < 3 * N; i++) - *outfile << "(N) \t"; + *outfile << setw(WIDTH) << right + << "(N)"; } // output segment strains? if (channels.find("s") != string::npos) { for (unsigned int i = 0; i < N; i++) - *outfile << "(-) \t"; + *outfile << setw(WIDTH) << right + << "(-)"; } // output segment strain rates? if (channels.find("d") != string::npos) { for (unsigned int i = 0; i < N; i++) - *outfile << "(-/s) \t"; + *outfile << setw(WIDTH) << right + << "(-/s)"; } // output seabed contact force? if (channels.find("b") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(N) \t"; + *outfile << setw(WIDTH) << right + << "(N)"; } *outfile << "\n"; @@ -1554,66 +1577,73 @@ Line::Output(real time) // Flags changed to just be one character (case sensitive) per output flag. // To match FASTv8 version. +// Helper to format and write a single value +auto write_val = [&](real val) { + *outfile << std::setw(WIDTH) + << std::right + << std::scientific + << std::setprecision(PRECISION) + << val; + }; + if (outfile) // if not a null pointer (indicating no output) { if (!outfile->is_open()) { LOGWRN << "Unable to write to output file " << endl; return; } + // Loops through the nodes + auto write_vec_array = [&](const std::vector& arr) { + for (unsigned int i = 0; i <= N; i++) + for (unsigned int J = 0; J < 3; J++){ + write_val(arr[i][J]);} + + }; + // Loops through the nodes for scalars + auto write_scalar_array = [&](const std::vector& arr) { + for (unsigned int i = 0; i <= N; i++) + write_val(arr[i]); + }; // output time - *outfile << time << "\t "; + *outfile << setw(10) << right << fixed << setprecision(4) + << time; // output positions? // if (find(channels.begin(), channels.end(), "position") != // channels.end()) if (channels.find("p") != string::npos) { - for (unsigned int i = 0; i <= N; i++) // loop through nodes - { - for (unsigned int J = 0; J < 3; J++) - *outfile << r[i][J] << "\t "; - } + write_vec_array(r); // position } + // output curvatures? if (channels.find("K") != string::npos) { - for (unsigned int i = 0; i <= N; i++) { - *outfile << Kurv[i] << "\t "; - } + write_scalar_array(Kurv); } // output velocities? if (channels.find("v") != string::npos) { - for (unsigned int i = 0; i <= N; i++) { - for (int J = 0; J < 3; J++) - *outfile << rd[i][J] << "\t "; - } + write_vec_array(rd); } // output wave velocities? if (channels.find("U") != string::npos) { auto [_z, U, _ud, _pdyn] = waves->getWaveKinLine(lineId); - for (unsigned int i = 0; i <= N; i++) { - for (int J = 0; J < 3; J++) - *outfile << U[i][J] << "\t "; - } + write_vec_array(U); } // output hydro drag force? if (channels.find("D") != string::npos) { for (unsigned int i = 0; i <= N; i++) { for (int J = 0; J < 3; J++) - *outfile << Dp[i][J] + Dq[i][J] + Ap[i][J] + Aq[i][J] - << "\t "; + write_val(Dp[i][J] + Dq[i][J] + Ap[i][J] + Aq[i][J]); } } // output VIV force (only CF for now) if (channels.find("V") != string::npos) { - for (unsigned int i = 0; i <= N; i++) { - for (int J = 0; J < 3; J++) - *outfile << Lf[i][J] << "\t "; - } + write_vec_array(Lf); } // output segment tensions? if (channels.find("t") != string::npos) { for (unsigned int i = 0; i < N; i++) { - *outfile << T[i].norm() << "\t "; + write_val(T[i].norm()); // >>> preparation below for switching to outputs at nodes // <<< note that tension of end nodes will need weight and // buoyancy adjustment @@ -1627,29 +1657,23 @@ Line::Output(real time) } // output internal damping force? if (channels.find("c") != string::npos) { - for (unsigned int i = 0; i < N; i++) { - for (int J = 0; J < 3; J++) - *outfile << Td[i][J] << "\t "; - } + write_vec_array(Td); // internal damping force } // output segment strains? if (channels.find("s") != string::npos) { for (unsigned int i = 0; i < N; i++) { - *outfile << lstr[i] / l[i] - 1.0 << "\t "; + write_val(lstr[i] / l[i] - 1.0); } } // output segment strain rates? if (channels.find("d") != string::npos) { for (unsigned int i = 0; i < N; i++) { - *outfile << ldstr[i] / l[i] << "\t "; + write_val(ldstr[i] / l[i]); } } // output seabed contact forces? if (channels.find("b") != string::npos) { - for (unsigned int i = 0; i <= N; i++) { - for (int J = 0; J < 3; J++) - *outfile << B[i][J] << "\t "; - } + write_vec_array(B); } *outfile << "\n"; diff --git a/source/MoorDyn2.cpp b/source/MoorDyn2.cpp index 38430a6a..1ed52a75 100644 --- a/source/MoorDyn2.cpp +++ b/source/MoorDyn2.cpp @@ -35,6 +35,7 @@ #include "MoorDyn2.hpp" #include "Rod.hpp" #include +#include #ifdef LINUX #include @@ -50,6 +51,10 @@ using namespace std; +// Formating constants for rod files outputs (iomanip) +constexpr int WIDTH = 20; // Width for output +constexpr int PRECISION = 7; // Precision for output + /** * @brief A helper function for getting the size of a vector as an unsigned int * @@ -69,12 +74,17 @@ namespace moordyn { /// The list of units for the output const char* UnitList[] = { - "(s) ", "(m) ", "(m) ", "(m) ", "(deg) ", - "(deg) ", "(deg) ", "(m/s) ", "(m/s) ", "(m/s) ", - "(deg/s) ", "(deg/s) ", "(deg/s) ", "(m/s2) ", "(m/s2) ", - "(m/s2) ", "(deg/s2) ", "(deg/s2) ", "(deg/s2) ", "(N) ", - "(N) ", "(N) ", "(N) ", "(Nm) ", "(Nm) ", - "(Nm) ", "(frac) " + "s", // 0: Time + "m", "m", "m", // 1: PosX 2: PosY 3: PosZ + "deg", "deg", "deg", // 4: RX 5: RY 6: RZ + "m/s", "m/s", "m/s", // 7: VelX 8: VelY 9: VelZ + "deg/s", "deg/s", "deg/s", // 10: RVelX 11: RVelY 12: RVelZ + "m/s^2", "m/s^2", "m/s^2", // 13: AccX 14: AccY 15: AccZ + "deg/s^2", "deg/s^2", "deg/s^2", // 16: RAccX 17: RAccY 18: RAccZ + "N", // 19: Ten + "N", "N", "N", // 20: FX 21: FY 22: FZ + "N*m", "N*m", "N*m", // 23: MX 24: MY 25: MZ + "(frac)" // 26: Sub }; std::atomic __systems_counter(0); @@ -621,18 +631,19 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) } // --- channel titles --- - outfileMain << "Time" - << "\t "; + outfileMain << setw(10) << right + << "Time"; for (auto channel : outChans) - outfileMain << channel.Name << "\t "; + outfileMain << setw(WIDTH) << right << channel.Name; outfileMain << endl; if (env->WriteUnits > 0) { // --- units --- - outfileMain << "(s)" - << "\t "; + outfileMain << setw(10) << right + << "(s)"; for (auto channel : outChans) - outfileMain << channel.Units << "\t "; + outfileMain << setw(WIDTH) << right + << channel.Units; outfileMain << "\n"; } @@ -2413,12 +2424,15 @@ moordyn::MoorDyn::WriteOutputs(double t, double dt) LOGERR << "Error: Unable to write to main output file " << endl; return MOORDYN_INVALID_OUTPUT_FILE; } - outfileMain << t << "\t "; // output time + outfileMain << setw(10) << right << fixed << setprecision(4) + << t; // output time for (auto channel : outChans) { moordyn::error_id err = MOORDYN_SUCCESS; string err_msg; try { - outfileMain << GetOutput(channel) << "\t "; + outfileMain << setw(WIDTH) << right << fixed << scientific + << setprecision(PRECISION) + << GetOutput(channel); } MOORDYN_CATCHER(err, err_msg); if (err != MOORDYN_SUCCESS) { diff --git a/source/Rod.cpp b/source/Rod.cpp index de5b8f3e..18a4d821 100644 --- a/source/Rod.cpp +++ b/source/Rod.cpp @@ -33,6 +33,7 @@ #include "Line.hpp" #include "Waves.hpp" #include +#include #ifdef USE_VTK #include @@ -46,6 +47,10 @@ using namespace std; +// Formating constants for rod files outputs (iomanip) +constexpr int WIDTH = 20; // Width for output +constexpr int PRECISION = 7; // Precision for output + namespace moordyn { // here is the new numbering scheme (N segments per line) @@ -243,30 +248,91 @@ Rod::openoutput() // 1st line with the fields // output time - *outfile << "Time" - << "\t "; + *outfile << setw(10) << right + << "Time"; // output positions if (channels.find("p") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "px \t Node" << i << "py \t Node" - << i << "pz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "px") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "py") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "pz"); } } // output velocities if (channels.find("v") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "vx \t Node" << i << "vy \t Node" - << i << "vz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "vx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "vy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "vz"); } } // output net node force if (channels.find("f") != string::npos) { for (unsigned int i = 0; i <= N; i++) { - *outfile << "Node" << i << "Fx \t Node" << i << "Fy \t Node" - << i << "Fz \t "; + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Fx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Fy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Fz"); } } + // Output Weight + if (channels.find("W") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Wx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Wy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Wz"); + } + // output Buoyancy + if (channels.find("B") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Box") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Boy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Boz"); + } + // output transverse drag + if (channels.find("X") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dpx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dpy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dpz"); + } + // output tangential drag + if (channels.find("Y") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dqx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dqy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Dqz"); + } + // output transverse inertia force + if (channels.find("A") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "ApX") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "ApY") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "ApZ"); + + } + // output tangential fluid inertia force + if (channels.find("a") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "AqX") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "AqY") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "AqZ"); + } + // output dynamic pressure + if (channels.find("P") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Pdx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Pdy") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Pdz"); + + } + // output bottom contact force + if (channels.find("b") != string::npos) { + for (unsigned int i = 0; i <= N; i++) + *outfile << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Bx") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "By") + << setw(WIDTH) << right << ("Node" + to_string((int)i) + "Bz"); + } *outfile << "\n"; @@ -274,23 +340,63 @@ Rod::openoutput() // 2nd line with the units // output time - *outfile << "(s)" - << "\t "; + *outfile << setw(10) << right + << "(s)"; // output positions if (channels.find("p") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(m) \t"; + *outfile << setw(WIDTH) << right << "(m)"; } - // output velocities? + // output velocities if (channels.find("v") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(m/s) \t"; + *outfile << setw(WIDTH) << right << "(m/s)"; } - // output net node force? + // output net node force if (channels.find("f") != string::npos) { for (unsigned int i = 0; i <= 3 * N + 2; i++) - *outfile << "(N) \t"; + *outfile << setw(WIDTH) << right << "(N)"; + } + // Output Weight + if (channels.find("W") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(N)"; + } + // output Buoyancy + if (channels.find("B") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(N)"; + } + // output transverse drag + if (channels.find("X") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(N)"; + } + // output tangential drag + if (channels.find("Y") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(N)"; + } + // output transverse fluid inertia force + if (channels.find("A") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(N)"; + } + // output tangential fluid inertia force + if (channels.find("a") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(N)"; + } + // output dynamic pressure + if (channels.find("P") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(Pa)"; + } + // output bottom contact force + if (channels.find("b") != string::npos) { + for (unsigned int i = 0; i <= 3 * N + 2; i++) + *outfile << setw(WIDTH) << right << "(N)"; } *outfile << "\n"; @@ -988,12 +1094,12 @@ Rod::doRHS() // get scalar for submerged portion if (h0 < 0.0) { // Upside down case - if (Lsum + dL >= h0) // if fully submerged + if (Lsum >= -h0) // if fully submerged VOF0 = 1.0; - else if (Lsum > h0) // if partially below waterline - VOF0 = (h0 - Lsum) / dL; + else if (Lsum + dL > -h0) // if partially below waterline + VOF0 = (Lsum + dL + h0) / dL; // partially submerged else // must be out of water - VOF0 = 0.0; + VOF0 = 0.0; // fully out of water } else { if (Lsum + dL <= h0) // if fully submerged VOF0 = 1.0; @@ -1395,6 +1501,15 @@ Rod::Output(real time) // Flags changed to just be one character (case sensitive) per output flag. // To match FASTv8 version. +// Helper to format and write a single value +auto write_val = [&](real val) { + *outfile << std::setw(WIDTH) + << std::right + << std::scientific + << std::setprecision(PRECISION) + << val; + }; + if (outfile) // if not a null pointer (indicating no output) { if (openedoutfile == 0) { @@ -1408,36 +1523,56 @@ Rod::Output(real time) return; } // output time - *outfile << time << "\t "; + *outfile << setw(10) << right << fixed << setprecision(4) + << time; + // Loops through the nodes and writes the values + auto write_vec_array = [&](const std::vector& arr) { + for (unsigned int i = 0; i <= N; i++) + for (unsigned int J = 0; J < 3; J++){ + write_val(arr[i][J]);} + }; + + // --------------------- + // Output data per channel + // --------------------- + if (channels.find("p") != string::npos) { + write_vec_array(r); // position + } + if (channels.find("v") != string::npos) { + write_vec_array(rd); // velocity + } + if (channels.find("f") != string::npos) { + write_vec_array(Fnet); // net node forces + } + if (channels.find("W") != string::npos) { + write_vec_array(W); // weight + } + if (channels.find("B") != string::npos) { + write_vec_array(Bo); // buoyancy + } + if (channels.find("Y") != string::npos) { + write_vec_array(Dq); // tangential drag + } + if (channels.find("X") != string::npos) { + write_vec_array(Dp); // transverse drag + } + if (channels.find("A") != string::npos) { + write_vec_array(Ap); // transverse fluid inertia + } + if (channels.find("a") != string::npos) { + write_vec_array(Aq); // tangential fluid inertia + } + if (channels.find("P") != string::npos) { + write_vec_array(Pd); // dynamic pressure + } + if (channels.find("b") != string::npos) { + write_vec_array(B); // seabed contact (bottom contact forces) + } - // output positions? - if (channels.find("p") != string::npos) { - for (unsigned int i = 0; i <= N; i++) // loop through nodes - { - for (int J = 0; J < 3; J++) - *outfile << r[i][J] << "\t "; - } - } - // output velocities? - if (channels.find("v") != string::npos) { - for (unsigned int i = 0; i <= N; i++) { - for (int J = 0; J < 3; J++) - *outfile << rd[i][J] << "\t "; - } - } - // output net node forces? - if (channels.find("f") != string::npos) { - for (unsigned int i = 0; i <= N; i++) { - for (unsigned int J = 0; J < 3; J++) - *outfile << Fnet[i][J] << "\t "; - } - } + *outfile << "\n"; + } - *outfile << "\n"; - } - return; } - std::vector Rod::Serialize(void) {