diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 00000000..233f0224 --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1 @@ +source/Eigen/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cdd5889..3d522dad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,53 +1,185 @@ -## [](https://github.com/core-marine-dev/MoorDyn/compare/v2.3.6...v) (2024-08-23) +## [2.4.0](https://github.com/FloatingArrayDesign/MoorDyn/compare/v2.3.8...v2.4.0) (2025-03-26) + +### ⚠ BREAKING CHANGES + +* **core:** Less flexible but fast extensible state variables +* **core:** Less flexible but fast extensible state variables + +### Features + +* **body:** Add centripetal forces for rotating bodies ([7fa5aa0](https://github.com/FloatingArrayDesign/MoorDyn/commit/7fa5aa06f1ac186f735212e09500159154a1e595)) +* Cleaned up the hack-ish state to generalize it for visco stuff. Made # a comment character in input files. Readded diable VIV during ICgen ([23a48c2](https://github.com/FloatingArrayDesign/MoorDyn/commit/23a48c26171cfd30e2a318afeb632d3626cd983d)) +* **core:** Create a base class for the instances which provides a unique identifier ([9dae6f3](https://github.com/FloatingArrayDesign/MoorDyn/commit/9dae6f369a21a644b2427405ada0ed34482e8223)) +* **core:** Create a base class for the instances which provides a unique identifier ([ef48e40](https://github.com/FloatingArrayDesign/MoorDyn/commit/ef48e4070aeedb9c590b58a6b1c80fde6b2fd04e)) +* **core:** Less flexible but fast extensible state variables ([bb83cc0](https://github.com/FloatingArrayDesign/MoorDyn/commit/bb83cc01f27979c45cd0843d0df1e8070a4d200c)) +* **core:** Less flexible but fast extensible state variables ([f53b64f](https://github.com/FloatingArrayDesign/MoorDyn/commit/f53b64f6fb13c5d46e53647c0256c30356bcf095)) +* **core:** New flexible states ([806b766](https://github.com/FloatingArrayDesign/MoorDyn/commit/806b7664950407ee5b126280bb38ee4fdb070095)) +* **core:** New flexible states ([870bbc1](https://github.com/FloatingArrayDesign/MoorDyn/commit/870bbc10dec2765676a3f9731a6b9a47ef542d43)) +* disableOutTime added to all test input files. Tests all passing on MacOS ([5340d5f](https://github.com/FloatingArrayDesign/MoorDyn/commit/5340d5fd93e9ad96154d6fa38333f8541eda68a8)) +* **rust:** First test using the Rust wrapper ([c715c8a](https://github.com/FloatingArrayDesign/MoorDyn/commit/c715c8ab7792b2691b3be97e58bbeb52e5c241e5)) +* Viscoelastic model with constant and load dependent dynamic stiffness is now live! ([4c2f789](https://github.com/FloatingArrayDesign/MoorDyn/commit/4c2f789922b605522e7b29028f4bd2062a4f11c8)) +* viscoelastic test now regression test of plots in PR ([562d7de](https://github.com/FloatingArrayDesign/MoorDyn/commit/562d7de61249dadbcfa49b4c768bad3656c358b4)) +* VIV and viscoelastic model compatability with the flexstate method. Verfied via comparison to MD-F and Thorsen results ([d7f309d](https://github.com/FloatingArrayDesign/MoorDyn/commit/d7f309d5bfc509524051d4efc35218df336eb821)) + +### Bug Fixes + +* accelerations of Coupled/fixed bodies/rods when there are several isntances of them ([5f670e7](https://github.com/FloatingArrayDesign/MoorDyn/commit/5f670e79a4c4b5749414820e31d87524345f6cdf)) +* Add a centripetal force to bodies with a excentric COG ([8b68967](https://github.com/FloatingArrayDesign/MoorDyn/commit/8b6896758efba5e861fb944c92ab2501b60459bc)) +* added dummy AllOutput to old API ([24b9a91](https://github.com/FloatingArrayDesign/MoorDyn/commit/24b9a9183790a0fe5ebe58652d329d40f46b03cb)) +* added more debug messages to polyester test for windows compatibility ([a5aacc3](https://github.com/FloatingArrayDesign/MoorDyn/commit/a5aacc3c087a2f097d2d0e14ceaea8716d24f074)) +* added setDependentStates call to Body::initializeUnfreeBody ([1bce742](https://github.com/FloatingArrayDesign/MoorDyn/commit/1bce742b1102f44c582f2bae93ab16a339ca31b3)) +* added warning message to loading states from MoorPy ([2ac486a](https://github.com/FloatingArrayDesign/MoorDyn/commit/2ac486ad01506930ff11415209e9070cc288addb)) +* bug fixes in tests ([0da58e7](https://github.com/FloatingArrayDesign/MoorDyn/commit/0da58e7cf47ed60b04b7bd166d7de7f7db9c5e13)) +* **build:** Upgraded the FindRust.cmake (from https://github.com/corrosion-rs/corrosion) ([0b40fbd](https://github.com/FloatingArrayDesign/MoorDyn/commit/0b40fbd0f2334ba8b0eacecb979b19822f7d69b8)) +* Centripetal force for parallel axes shall be null ([7dd2a4c](https://github.com/FloatingArrayDesign/MoorDyn/commit/7dd2a4c46d0e2b043f9a08c99d75b18b631b4030)) +* change cout to MoorDyn_log for AllOutput wrapper ([7720e4a](https://github.com/FloatingArrayDesign/MoorDyn/commit/7720e4afeed0e3e274e4e2bc28a6e9f65b347e6e)) +* **ci:** Drop Ubuntu from MATLAB tests (for the time being) ([b4a00e8](https://github.com/FloatingArrayDesign/MoorDyn/commit/b4a00e8fbb16e42e408c8ea5b55760955bff1576)) +* **ci:** Drop Ubuntu from MATLAB tests (for the time being) ([fa23498](https://github.com/FloatingArrayDesign/MoorDyn/commit/fa23498e08f49798fb793a3431167c99de403a55)) +* **ci:** Run the Rust tests on Linux ([4810599](https://github.com/FloatingArrayDesign/MoorDyn/commit/481059926a675c715a8cc73eb70f4f5cf4aafe69)) +* cleaned up some time scheme stuff (added in more spots where Misc states should be accounted for) ([f575aef](https://github.com/FloatingArrayDesign/MoorDyn/commit/f575aeffe5d84b86f475d631f868f9d0ae2127e8)) +* cleaning up after merge ([86e1505](https://github.com/FloatingArrayDesign/MoorDyn/commit/86e150529a3a86c38fcdc27a56a5a397f561a8f4)) +* comment out include random ([0cbabea](https://github.com/FloatingArrayDesign/MoorDyn/commit/0cbabea241ae2531ea129ea4d544c6f9d3d890de)) +* **core:** Add subclasses to the DLL interface ([b1c6b8d](https://github.com/FloatingArrayDesign/MoorDyn/commit/b1c6b8d5785cd910bdd4ee17ea8c06257ce77f47)) +* **core:** Add subclasses to the DLL interface ([f7196a3](https://github.com/FloatingArrayDesign/MoorDyn/commit/f7196a3690bec142b84594d195e2636fba5eb52b)) +* **core:** CLang buildings ([1d32c6c](https://github.com/FloatingArrayDesign/MoorDyn/commit/1d32c6c672192a3bc285b17a99a4936d48bb5ae9)) +* **core:** CLang buildings ([2a22d8b](https://github.com/FloatingArrayDesign/MoorDyn/commit/2a22d8b3b2eda2a8f5bdf33b69f37cdb7b4a0f21)) +* **core:** Export some more symbols for state tests ([7cca1b7](https://github.com/FloatingArrayDesign/MoorDyn/commit/7cca1b769735a19fffbb7112a5a6bb287940b830)) +* **core:** Export some more symbols for state tests ([6a53a6e](https://github.com/FloatingArrayDesign/MoorDyn/commit/6a53a6e7ec5c04e92239ef8edd1b9dc1c1bec1e7)) +* **core:** Export some more symbols for state tests ([9174466](https://github.com/FloatingArrayDesign/MoorDyn/commit/9174466abd98e6aa65ef69a7e06e42167feab874)) +* **core:** Export some more symbols for state tests ([53aefb6](https://github.com/FloatingArrayDesign/MoorDyn/commit/53aefb6802162070b2ad95f0871cd8106aa2d578)) +* **core:** Give a common Instance::initialize() method ([63f8784](https://github.com/FloatingArrayDesign/MoorDyn/commit/63f8784dd948dc273c93b2a837f19c33668f12f1)) +* **core:** Give a common Instance::initialize() method ([cdac02f](https://github.com/FloatingArrayDesign/MoorDyn/commit/cdac02fddb3c1281a0fe1964a2e1dbbdfd8f33f3)) +* **core:** Initialize the state variables as zeroes by default ([c50de1b](https://github.com/FloatingArrayDesign/MoorDyn/commit/c50de1b3c1bb6833fa2eba821c78624bcb6c1ec0)) +* **core:** Initialize the state variables as zeroes by default ([30df38d](https://github.com/FloatingArrayDesign/MoorDyn/commit/30df38d02a9182a22e31533e75fa03052c9dc3ce)) +* **core:** Removed unused operator ([4becb1a](https://github.com/FloatingArrayDesign/MoorDyn/commit/4becb1abde441bacf3d9c263b7809a82a11705d0)) +* **core:** Removed unused operator ([eb7b28b](https://github.com/FloatingArrayDesign/MoorDyn/commit/eb7b28b5b56eba6ea9a0b56d70def4368fbc149c)) +* **core:** StateVarRef not used anymore ([709dbaa](https://github.com/FloatingArrayDesign/MoorDyn/commit/709dbaad64ec2ce73d9b2a3f8164c575e8f96f9d)) +* **core:** StateVarRef not used anymore ([be0a344](https://github.com/FloatingArrayDesign/MoorDyn/commit/be0a3442d01323c6c1c1cc6cee9ed19fdbb5ce6b)) +* **core:** Use non-static methods that are CLang templates compliant ([c0c6f6d](https://github.com/FloatingArrayDesign/MoorDyn/commit/c0c6f6da761705c2639d1aac27915c93ac536213)) +* **core:** Use non-static methods that are CLang templates compliant ([c2ac1e9](https://github.com/FloatingArrayDesign/MoorDyn/commit/c2ac1e9b7c32535cafc53068f3487c8173f3c5d0)) +* **core:** VS Code invalid exports ([72a81dc](https://github.com/FloatingArrayDesign/MoorDyn/commit/72a81dc256c15866ba1b3e81e06209a7cb2655f7)) +* **core:** VS Code invalid exports ([10c4db6](https://github.com/FloatingArrayDesign/MoorDyn/commit/10c4db686deacdf7af36261365d1c89c89563507)) +* **core:** VS Code invalid exports ([e14a065](https://github.com/FloatingArrayDesign/MoorDyn/commit/e14a0651293c09d136ea68c65fd426b18917a0a3)) +* **core:** VS Code invalid exports ([ed062c7](https://github.com/FloatingArrayDesign/MoorDyn/commit/ed062c7d5532ebf2a39f3f4b0a3e524a14d6fbed)) +* **core:** VSCode warnings ([851eb90](https://github.com/FloatingArrayDesign/MoorDyn/commit/851eb90b061d0b3f002696ba6a894ecd81755fba)) +* **core:** VSCode warnings ([c711ef6](https://github.com/FloatingArrayDesign/MoorDyn/commit/c711ef6af6c933b1adee4b3d5db747023d53eb83)) +* Drop the patch to move from extrinsic to intrinsic Euler angles ([9992312](https://github.com/FloatingArrayDesign/MoorDyn/commit/9992312a12f227d2906606f3e5032e6ebd4584db)) +* dynamic current inflile reading fix ([5f8006e](https://github.com/FloatingArrayDesign/MoorDyn/commit/5f8006ecdc81a3ca0f24aeb0f11bdb61fe0c14f2)) +* EulerXYZ intrinsic angles instead of extrinsic ([a62b60f](https://github.com/FloatingArrayDesign/MoorDyn/commit/a62b60fd4a7801e8fff4a6f2b4922e772bd25ce7)) +* EulerZYX -> EulerXYZ on moordyn::Euler2Quat() ([4feaeba](https://github.com/FloatingArrayDesign/MoorDyn/commit/4feaebacd9557519de44d751fdd5280b86147198)) +* fixed failing polyester test. Added comments for documentation ([c4ede97](https://github.com/FloatingArrayDesign/MoorDyn/commit/c4ede9727e3c1d3a1b77bc81af61bf76f2766a4f)) +* Freeze when writeLog is not the first option ([bcdf7fe](https://github.com/FloatingArrayDesign/MoorDyn/commit/bcdf7fe0b84551c2e9f69ceac17d9f7c3f6a6e06)) +* hopefully fixes windows and ubuntu failing builds ([47ea7c9](https://github.com/FloatingArrayDesign/MoorDyn/commit/47ea7c95b20e29bcd36b4564179efe58a71b1975)) +* Improve input file reading error messages ([da9d475](https://github.com/FloatingArrayDesign/MoorDyn/commit/da9d475fee0965738d600de80de3c1594eddff2a)) +* indentation fixes ([183701d](https://github.com/FloatingArrayDesign/MoorDyn/commit/183701dabdbd54fbd3566acd841301a8022bd19b)) +* major clean up to the synchronization model ([4abc5e5](https://github.com/FloatingArrayDesign/MoorDyn/commit/4abc5e5a62ce1116da159f7fc97689a6ac32ed10)) +* make rod submergence calcs match what is in MDF (verified code) ([d40897b](https://github.com/FloatingArrayDesign/MoorDyn/commit/d40897bf2a8480a20a169329e774186208d51ebd)) +* make rod submergence calcs match what is in MDF (verified code) ([5eb1d48](https://github.com/FloatingArrayDesign/MoorDyn/commit/5eb1d48fc15fd8d539bdfbc416773b7c617fb0f5)) +* mismatch between file and headed ([c78305a](https://github.com/FloatingArrayDesign/MoorDyn/commit/c78305a3371d14a45a678f46f2868c5a522f1a6d)) +* Odd treatment was meant for indexes from 1 to 3, not 0 to 2, and the matrix indexes were transposed ([d0ea9e1](https://github.com/FloatingArrayDesign/MoorDyn/commit/d0ea9e127e05ecc2016e948968520bb57209d8bd)) +* Old AllOutput back to voids, cleans it up a bit ([b5f89c4](https://github.com/FloatingArrayDesign/MoorDyn/commit/b5f89c48a4b85e10ca5f64f054dadf0a8d04ee03)) +* Read first the writelog option, and then anything else ([d842555](https://github.com/FloatingArrayDesign/MoorDyn/commit/d8425559851fa26e9ab8a10313265c3111aa7145)) +* Rebranding to include centripetal forces on getNetForceAndMass ([50a919e](https://github.com/FloatingArrayDesign/MoorDyn/commit/50a919ea6bd35bdad9de68b7d6d5a80bad6f4966)) +* removing files ([f3d4a2a](https://github.com/FloatingArrayDesign/MoorDyn/commit/f3d4a2a8e6b9ed5d4c4b1a9f708aea34fb6ce9af)) +* removing one more file ([b603998](https://github.com/FloatingArrayDesign/MoorDyn/commit/b60399881aeecc86f7c474e6c79f7a4a18ec2e72)) +* Rename AllOutput -> WriteOutputs (To match MD-F) ([10f1903](https://github.com/FloatingArrayDesign/MoorDyn/commit/10f19035600d8f3e0b8a1ed2af644a140efe5447)) +* Some more notes explaining the synchronization model ([b39211a](https://github.com/FloatingArrayDesign/MoorDyn/commit/b39211acb6dfe024e243a46790c34df073e45d77)) +* some more stiffness fixes. Noteably before when reading a non-linear look up table it assumed stress strain. This is not correct and doesnt match theory paper or docs. CHanges to stress tension. ([2413666](https://github.com/FloatingArrayDesign/MoorDyn/commit/24136667846b70abd36a55710f76cf9b7628b413)) +* some small fixes for viscoelastic stuff ([084f231](https://github.com/FloatingArrayDesign/MoorDyn/commit/084f23175511b62bfa778a8db6a26e7889c4b919)) +* standard initalize structure, standardizing setState calls, and some docs improvements ([4b4b6a7](https://github.com/FloatingArrayDesign/MoorDyn/commit/4b4b6a7e768836d92a1fac2ab67581ea6ed31afe)) +* The quaternions shall be renormalized to get the rotation matrix ([cc222d4](https://github.com/FloatingArrayDesign/MoorDyn/commit/cc222d455c9029bbf55a4cd9b820e7f63c7a20be)) +* update docs with minor clarifications, move VIV model to internal nodes only ([f9dde93](https://github.com/FloatingArrayDesign/MoorDyn/commit/f9dde93bf0c9d0f5dc171d1f9354d98ae2538e6e)) +## [2.3.8](https://github.com/FloatingArrayDesign/MoorDyn/compare/v2.3.6...v2.3.8) (2024-12-12) + +### Features + +* Added the possibility to load initial condition states from other tools ([b92b366](https://github.com/FloatingArrayDesign/MoorDyn/commit/b92b366958face9f500c83c44d79004896c4b184)) +* adds disableOutTime to turn off timestep printing to the console. Useful for the MATLAB wrapper ([327c2be](https://github.com/FloatingArrayDesign/MoorDyn/commit/327c2be319b73d0adf41e9c5d8f2887328ff99f0)) +* **ci:** Compile and test MATLAB wrapper (Linux and MacOS) ([34d7c07](https://github.com/FloatingArrayDesign/MoorDyn/commit/34d7c0740a45fd8b727d830ea3b82d59e6386fdb)) + +### Bug Fixes + +* **ci:** Ignore MUSLLinux wheels when testing ([63698bd](https://github.com/FloatingArrayDesign/MoorDyn/commit/63698bd87f4224c8d062f4b3b732b2f52e5dbeef)) +* **ci:** List of dependencies to publish a package ([2c9ea79](https://github.com/FloatingArrayDesign/MoorDyn/commit/2c9ea79d89002287bc0e718dcd433b9c891a3b92)) +* **ci:** Remove the MUSLLinux wheels before testing ([20a35bf](https://github.com/FloatingArrayDesign/MoorDyn/commit/20a35bf0ad51f4500b84b03e266848f503665720)) +* **ci:** Removed unused env variables ([584bda5](https://github.com/FloatingArrayDesign/MoorDyn/commit/584bda5581864d779d467875ee2b1a459cab8b91)) +* **ci:** Setting the VTK version ([3be2478](https://github.com/FloatingArrayDesign/MoorDyn/commit/3be24786c21753f8aaba898ee4bdf551ca3196af)) +* **ci:** The VTK tar.gz can be directly extracted on MacOS ([9422fb2](https://github.com/FloatingArrayDesign/MoorDyn/commit/9422fb21063254dc3e943f5a8b0399341aed491b)) +* **ci:** Update to VTK-9.3.1 ([154ab66](https://github.com/FloatingArrayDesign/MoorDyn/commit/154ab66d5d7442ad15fd31a855577a848f91f5a9)) +* **ci:** Use directly the VTK version placeholders ([e528054](https://github.com/FloatingArrayDesign/MoorDyn/commit/e5280542245ae5e7617aafb011c0f0f7a85cf7f9)) +* **ci:** Wrong VTK URI ([6ef95f9](https://github.com/FloatingArrayDesign/MoorDyn/commit/6ef95f92ab826f8f4e09661728a54f7d6cb3d870)) +* **core:** Water depth warning was printed no matter whether it was corrected or not ([2dadb16](https://github.com/FloatingArrayDesign/MoorDyn/commit/2dadb165a1924aecb397ba719e8eabef3e52f792)) +* **docs and tests:** Initialization notes with a practical application ([97c2653](https://github.com/FloatingArrayDesign/MoorDyn/commit/97c26538b426215c8020dcafc1267fa92fcaed7e)) +* fixed path errors in waves files. ([c45ff24](https://github.com/FloatingArrayDesign/MoorDyn/commit/c45ff24f1cb69f1bb026f6a2b4c2d6062d637050)) +* **fortran:** Added the serialization/deserialization ([c253a43](https://github.com/FloatingArrayDesign/MoorDyn/commit/c253a43f2b78bcdfa68e946418a1011924ea58a6)) +* **fortran:** Added the time scheme manipulation entries ([c1a13ed](https://github.com/FloatingArrayDesign/MoorDyn/commit/c1a13ed9cb8c9c6d9ad51fd37c12a4db0507f8e5)) +* **matlab:** Added the time scheme manipulation entries ([8e5b609](https://github.com/FloatingArrayDesign/MoorDyn/commit/8e5b609ce9f82730309bbd01e37c7fb6e960d639)) +* **matlab:** Serialization/deserialization entries ([5f19e10](https://github.com/FloatingArrayDesign/MoorDyn/commit/5f19e107bd1c9482165f6e4b2e60c8e69b62948d)) +* **python-wheels:** Test the wheels ([f534b48](https://github.com/FloatingArrayDesign/MoorDyn/commit/f534b48bd9eb508b00e6ff102e62a7d84addea0a)) +* **python:** Absolute paths are not accepted any longer ([9d246f2](https://github.com/FloatingArrayDesign/MoorDyn/commit/9d246f2cbb38bff0f6ae767802880ef3c5eb6d3d)) +* **python:** Added the missing time scheme manipulation API entries ([e71e8f2](https://github.com/FloatingArrayDesign/MoorDyn/commit/e71e8f28584383886010b06817c557f26adb4ab1)) +* **python:** Autonomous MoorPy IC exporter ([d51c21c](https://github.com/FloatingArrayDesign/MoorDyn/commit/d51c21cfe197146df02b97cc8b0a1bf6599006ab)) +* **python:** Avoid using brew on MacOS-13 statically linking VTK ([a521444](https://github.com/FloatingArrayDesign/MoorDyn/commit/a521444281e9117c09135640f49154c2d3d0a18a)) +* **python:** Enable MUSLLinux builds ([7f20dab](https://github.com/FloatingArrayDesign/MoorDyn/commit/7f20dab357b8863320d35bee1723f21099900023)) +* **python:** Enable pypy builds again ([224f8e4](https://github.com/FloatingArrayDesign/MoorDyn/commit/224f8e4f31271a96b6a4ef170d8337d252305cb7)) +* **python:** Missing GetXXXNumberNodes missing entries ([e9ffaca](https://github.com/FloatingArrayDesign/MoorDyn/commit/e9ffaca8b1e4fde116fa494f2fff9f896d9c5124)) +* **python:** Set the install name id on MacOS ([32a9fca](https://github.com/FloatingArrayDesign/MoorDyn/commit/32a9fcae8a8aee0558c632fe236f92d9e6bfda8d)) +* **python:** Set the MACOSX_DEPLOYMENT_TARGET to 10.15 ([f44e9c4](https://github.com/FloatingArrayDesign/MoorDyn/commit/f44e9c4df1c1c9645d1a08255f16722baa519188)) +* **python:** The sea bed force was actually returning the Froude-Krilov one ([d44096a](https://github.com/FloatingArrayDesign/MoorDyn/commit/d44096a8f98d657a25d8688afa373f90048f521a)) +* **python:** The time is not required on moordyn.GetWavesKin() anymore ([d10c1e4](https://github.com/FloatingArrayDesign/MoorDyn/commit/d10c1e4b38d826264633a2f859e9703215b25e47)) +* **python:** Use the MUSLLinux VTK compilation when needed ([e5fe619](https://github.com/FloatingArrayDesign/MoorDyn/commit/e5fe6190d5fdc67f6bb48c3fc7133a6ed5c5a4ec)) +* removed case sensitivity in the options list keywords ([0ac1e8e](https://github.com/FloatingArrayDesign/MoorDyn/commit/0ac1e8e3f57cf92a0d7443629fe9df560fb6b883)) +* **tests:** Ignore the force on the anchor point because it is not computed ([4828499](https://github.com/FloatingArrayDesign/MoorDyn/commit/4828499f8ade98521011f563c99fbd71c0429647)) +## [2.3.6](https://github.com/FloatingArrayDesign/MoorDyn/compare/v2.3.5...v2.3.6) (2024-08-23) ### Bug Fixes -* **ci:** Ignore MUSLLinux wheels when testing ([63698bd](https://github.com/core-marine-dev/MoorDyn/commit/63698bd87f4224c8d062f4b3b732b2f52e5dbeef)) -* **ci:** List of dependencies to publish a package ([2c9ea79](https://github.com/core-marine-dev/MoorDyn/commit/2c9ea79d89002287bc0e718dcd433b9c891a3b92)) -* **ci:** Remove the MUSLLinux wheels before testing ([20a35bf](https://github.com/core-marine-dev/MoorDyn/commit/20a35bf0ad51f4500b84b03e266848f503665720)) -* **ci:** Removed unused env variables ([584bda5](https://github.com/core-marine-dev/MoorDyn/commit/584bda5581864d779d467875ee2b1a459cab8b91)) -* **ci:** Setting the VTK version ([3be2478](https://github.com/core-marine-dev/MoorDyn/commit/3be24786c21753f8aaba898ee4bdf551ca3196af)) -* **ci:** The VTK tar.gz can be directly extracted on MacOS ([9422fb2](https://github.com/core-marine-dev/MoorDyn/commit/9422fb21063254dc3e943f5a8b0399341aed491b)) -* **ci:** Update to VTK-9.3.1 ([154ab66](https://github.com/core-marine-dev/MoorDyn/commit/154ab66d5d7442ad15fd31a855577a848f91f5a9)) -* **ci:** Use directly the VTK version placeholders ([e528054](https://github.com/core-marine-dev/MoorDyn/commit/e5280542245ae5e7617aafb011c0f0f7a85cf7f9)) -* **ci:** Wrong VTK URI ([6ef95f9](https://github.com/core-marine-dev/MoorDyn/commit/6ef95f92ab826f8f4e09661728a54f7d6cb3d870)) -* **python-wheels:** Test the wheels ([f534b48](https://github.com/core-marine-dev/MoorDyn/commit/f534b48bd9eb508b00e6ff102e62a7d84addea0a)) -* **python:** Avoid using brew on MacOS-13 statically linking VTK ([a521444](https://github.com/core-marine-dev/MoorDyn/commit/a521444281e9117c09135640f49154c2d3d0a18a)) -* **python:** Enable MUSLLinux builds ([7f20dab](https://github.com/core-marine-dev/MoorDyn/commit/7f20dab357b8863320d35bee1723f21099900023)) -* **python:** Enable pypy builds again ([224f8e4](https://github.com/core-marine-dev/MoorDyn/commit/224f8e4f31271a96b6a4ef170d8337d252305cb7)) -* **python:** Set the install name id on MacOS ([32a9fca](https://github.com/core-marine-dev/MoorDyn/commit/32a9fcae8a8aee0558c632fe236f92d9e6bfda8d)) -* **python:** Set the MACOSX_DEPLOYMENT_TARGET to 10.15 ([f44e9c4](https://github.com/core-marine-dev/MoorDyn/commit/f44e9c4df1c1c9645d1a08255f16722baa519188)) -* **python:** Use the MUSLLinux VTK compilation when needed ([e5fe619](https://github.com/core-marine-dev/MoorDyn/commit/e5fe6190d5fdc67f6bb48c3fc7133a6ed5c5a4ec)) -## [](https://github.com/core-marine-dev/MoorDyn/compare/v2.3.5...v) (2024-08-14) +* **ci:** Ignore MUSLLinux wheels when testing ([63698bd](https://github.com/FloatingArrayDesign/MoorDyn/commit/63698bd87f4224c8d062f4b3b732b2f52e5dbeef)) +* **ci:** List of dependencies to publish a package ([2c9ea79](https://github.com/FloatingArrayDesign/MoorDyn/commit/2c9ea79d89002287bc0e718dcd433b9c891a3b92)) +* **ci:** Remove the MUSLLinux wheels before testing ([20a35bf](https://github.com/FloatingArrayDesign/MoorDyn/commit/20a35bf0ad51f4500b84b03e266848f503665720)) +* **ci:** Removed unused env variables ([584bda5](https://github.com/FloatingArrayDesign/MoorDyn/commit/584bda5581864d779d467875ee2b1a459cab8b91)) +* **ci:** Setting the VTK version ([3be2478](https://github.com/FloatingArrayDesign/MoorDyn/commit/3be24786c21753f8aaba898ee4bdf551ca3196af)) +* **ci:** The VTK tar.gz can be directly extracted on MacOS ([9422fb2](https://github.com/FloatingArrayDesign/MoorDyn/commit/9422fb21063254dc3e943f5a8b0399341aed491b)) +* **ci:** Update to VTK-9.3.1 ([154ab66](https://github.com/FloatingArrayDesign/MoorDyn/commit/154ab66d5d7442ad15fd31a855577a848f91f5a9)) +* **ci:** Use directly the VTK version placeholders ([e528054](https://github.com/FloatingArrayDesign/MoorDyn/commit/e5280542245ae5e7617aafb011c0f0f7a85cf7f9)) +* **ci:** Wrong VTK URI ([6ef95f9](https://github.com/FloatingArrayDesign/MoorDyn/commit/6ef95f92ab826f8f4e09661728a54f7d6cb3d870)) +* **python-wheels:** Test the wheels ([f534b48](https://github.com/FloatingArrayDesign/MoorDyn/commit/f534b48bd9eb508b00e6ff102e62a7d84addea0a)) +* **python:** Avoid using brew on MacOS-13 statically linking VTK ([a521444](https://github.com/FloatingArrayDesign/MoorDyn/commit/a521444281e9117c09135640f49154c2d3d0a18a)) +* **python:** Enable MUSLLinux builds ([7f20dab](https://github.com/FloatingArrayDesign/MoorDyn/commit/7f20dab357b8863320d35bee1723f21099900023)) +* **python:** Enable pypy builds again ([224f8e4](https://github.com/FloatingArrayDesign/MoorDyn/commit/224f8e4f31271a96b6a4ef170d8337d252305cb7)) +* **python:** Set the install name id on MacOS ([32a9fca](https://github.com/FloatingArrayDesign/MoorDyn/commit/32a9fcae8a8aee0558c632fe236f92d9e6bfda8d)) +* **python:** Set the MACOSX_DEPLOYMENT_TARGET to 10.15 ([f44e9c4](https://github.com/FloatingArrayDesign/MoorDyn/commit/f44e9c4df1c1c9645d1a08255f16722baa519188)) +* **python:** Use the MUSLLinux VTK compilation when needed ([e5fe619](https://github.com/FloatingArrayDesign/MoorDyn/commit/e5fe6190d5fdc67f6bb48c3fc7133a6ed5c5a4ec)) +## [v2.3.5](https://github.com/FloatingArrayDesign/MoorDyn/compare/v2.3.3...v2.3.5) (2024-08-14) ### Bug Fixes -* **python-wheels:** {project} placeholder seems to be ignored/invalid ([0a97f4d](https://github.com/core-marine-dev/MoorDyn/commit/0a97f4dcff2bfa1f83c0b943f0c1695b71e33f69)) -* **python-wheels:** Add the DLL path to delvewheel ([9310754](https://github.com/core-marine-dev/MoorDyn/commit/9310754b965ee3602db579e22fd1f242970dff05)) -* **python-wheels:** Remove the useless folders after installing ([e6aa341](https://github.com/core-marine-dev/MoorDyn/commit/e6aa341be866183266afacd996accf0afde30837)) -* **python-wheels:** Temporary disable pypy3.10, which is not working on the CI ([49dd580](https://github.com/core-marine-dev/MoorDyn/commit/49dd5805db58c21a09a7012cdf6cce685ceeaf72)) -* **python-wheels:** Temporary disable pypy3.8, which is not working on the CI ([27166f6](https://github.com/core-marine-dev/MoorDyn/commit/27166f6575586727d2893bc9094eb3fb121aed05)) -* **python-wheels:** Temporary disable pypy3.9, which is not working on the CI ([b5b4003](https://github.com/core-marine-dev/MoorDyn/commit/b5b400327b9ec1debeab328c57a314715b0740d9)) -* **python-wheels:** Use delvewheel on Windows ([89b5ddc](https://github.com/core-marine-dev/MoorDyn/commit/89b5ddcbc5f64404ff902c8a536e304052ab580a)) -* **python-wheels:** Use the installed headers ([ad18025](https://github.com/core-marine-dev/MoorDyn/commit/ad18025c6ff5353f4c99fa7bd58a988c5016c9cd)) -* resolves typos and warnings thrown at compiling ([e4a8f08](https://github.com/core-marine-dev/MoorDyn/commit/e4a8f08195e031cbfecfd30574edaad08b15a4d0)) -## [](https://github.com/core-marine-dev/MoorDyn/compare/v2.3.3...v) (2024-08-07) +* **python-wheels:** {project} placeholder seems to be ignored/invalid ([0a97f4d](https://github.com/FloatingArrayDesign/MoorDyn/commit/0a97f4dcff2bfa1f83c0b943f0c1695b71e33f69)) +* **python-wheels:** Add the DLL path to delvewheel ([9310754](https://github.com/FloatingArrayDesign/MoorDyn/commit/9310754b965ee3602db579e22fd1f242970dff05)) +* **python-wheels:** Remove the useless folders after installing ([e6aa341](https://github.com/FloatingArrayDesign/MoorDyn/commit/e6aa341be866183266afacd996accf0afde30837)) +* **python-wheels:** Temporary disable pypy3.10, which is not working on the CI ([49dd580](https://github.com/FloatingArrayDesign/MoorDyn/commit/49dd5805db58c21a09a7012cdf6cce685ceeaf72)) +* **python-wheels:** Temporary disable pypy3.8, which is not working on the CI ([27166f6](https://github.com/FloatingArrayDesign/MoorDyn/commit/27166f6575586727d2893bc9094eb3fb121aed05)) +* **python-wheels:** Temporary disable pypy3.9, which is not working on the CI ([b5b4003](https://github.com/FloatingArrayDesign/MoorDyn/commit/b5b400327b9ec1debeab328c57a314715b0740d9)) +* **python-wheels:** Use delvewheel on Windows ([89b5ddc](https://github.com/FloatingArrayDesign/MoorDyn/commit/89b5ddcbc5f64404ff902c8a536e304052ab580a)) +* **python-wheels:** Use the installed headers ([ad18025](https://github.com/FloatingArrayDesign/MoorDyn/commit/ad18025c6ff5353f4c99fa7bd58a988c5016c9cd)) +* resolves typos and warnings thrown at compiling ([e4a8f08](https://github.com/FloatingArrayDesign/MoorDyn/commit/e4a8f08195e031cbfecfd30574edaad08b15a4d0)) +## v2.3.3 (2024-08-07) ### Features -* **body:** Add centripetal forces for rotating bodies ([f4f816c](https://github.com/core-marine-dev/MoorDyn/commit/f4f816cadb4116f4052f4a3cc36ca2c82f5cabd9)) +* **body:** Add centripetal forces for rotating bodies ([f4f816c](https://github.com/FloatingArrayDesign/MoorDyn/commit/f4f816cadb4116f4052f4a3cc36ca2c82f5cabd9)) ### Bug Fixes -* accelerations of Coupled/fixed bodies/rods when there are several isntances of them ([1a07a2d](https://github.com/core-marine-dev/MoorDyn/commit/1a07a2d39fe6ffb5f27b6e143830d18ce4f758f2)) -* Add a centripetal force to bodies with a excentric COG ([7a56b7c](https://github.com/core-marine-dev/MoorDyn/commit/7a56b7c941c0bfbddb37fab48423f1ad715270a7)) -* Centripetal force for parallel axes shall be null ([829c837](https://github.com/core-marine-dev/MoorDyn/commit/829c83711a98ed11178cc3b934b76ce515c61f82)) -* Drop the patch to move from extrinsic to intrinsic Euler angles ([6ff56ac](https://github.com/core-marine-dev/MoorDyn/commit/6ff56acc47d756634b1a8238898221ec016c8e0f)) -* EulerXYZ intrinsic angles instead of extrinsic ([1eec2e3](https://github.com/core-marine-dev/MoorDyn/commit/1eec2e3005239c9bd8e19f1ebddd05ead8f2f08f)) -* EulerZYX -> EulerXYZ on moordyn::Euler2Quat() ([5a5f7fd](https://github.com/core-marine-dev/MoorDyn/commit/5a5f7fdfa8bc161cd580c50b3dcedcca394919c6)) -* Freeze when writeLog is not the first option ([d4cce8e](https://github.com/core-marine-dev/MoorDyn/commit/d4cce8ecfb8e5af4819f3877e0f882d59ebb04c8)) -* make rod submergence calcs match what is in MDF (verified code) ([0ac0e92](https://github.com/core-marine-dev/MoorDyn/commit/0ac0e9207eec4c202bf6b85f4a6fbc5178a1fb13)) -* Odd treatment was meant for indexes from 1 to 3, not 0 to 2, and the matrix indexes were transposed ([0bb4ae2](https://github.com/core-marine-dev/MoorDyn/commit/0bb4ae27c8ed307a7a2382f0a53121ef8d73ebb7)) -* Read first the writelog option, and then anything else ([028a567](https://github.com/core-marine-dev/MoorDyn/commit/028a56742226aa27fa900272bf020924eec56b6d)) -* Rebranding to include centripetal forces on getNetForceAndMass ([f20a98a](https://github.com/core-marine-dev/MoorDyn/commit/f20a98aa23a584a0475f6055a33acfda30f39718)) -* The quaternions shall be renormalized to get the rotation matrix ([7256746](https://github.com/core-marine-dev/MoorDyn/commit/7256746793f0c48b6ec4bc8dd97407ad582a9ae2)) +* accelerations of Coupled/fixed bodies/rods when there are several isntances of them ([1a07a2d](https://github.com/FloatingArrayDesign/MoorDyn/commit/1a07a2d39fe6ffb5f27b6e143830d18ce4f758f2)) +* Add a centripetal force to bodies with a excentric COG ([7a56b7c](https://github.com/FloatingArrayDesign/MoorDyn/commit/7a56b7c941c0bfbddb37fab48423f1ad715270a7)) +* Centripetal force for parallel axes shall be null ([829c837](https://github.com/FloatingArrayDesign/MoorDyn/commit/829c83711a98ed11178cc3b934b76ce515c61f82)) +* Drop the patch to move from extrinsic to intrinsic Euler angles ([6ff56ac](https://github.com/FloatingArrayDesign/MoorDyn/commit/6ff56acc47d756634b1a8238898221ec016c8e0f)) +* EulerXYZ intrinsic angles instead of extrinsic ([1eec2e3](https://github.com/FloatingArrayDesign/MoorDyn/commit/1eec2e3005239c9bd8e19f1ebddd05ead8f2f08f)) +* EulerZYX -> EulerXYZ on moordyn::Euler2Quat() ([5a5f7fd](https://github.com/FloatingArrayDesign/MoorDyn/commit/5a5f7fdfa8bc161cd580c50b3dcedcca394919c6)) +* Freeze when writeLog is not the first option ([d4cce8e](https://github.com/FloatingArrayDesign/MoorDyn/commit/d4cce8ecfb8e5af4819f3877e0f882d59ebb04c8)) +* make rod submergence calcs match what is in MDF (verified code) ([0ac0e92](https://github.com/FloatingArrayDesign/MoorDyn/commit/0ac0e9207eec4c202bf6b85f4a6fbc5178a1fb13)) +* Odd treatment was meant for indexes from 1 to 3, not 0 to 2, and the matrix indexes were transposed ([0bb4ae2](https://github.com/FloatingArrayDesign/MoorDyn/commit/0bb4ae27c8ed307a7a2382f0a53121ef8d73ebb7)) +* Read first the writelog option, and then anything else ([028a567](https://github.com/FloatingArrayDesign/MoorDyn/commit/028a56742226aa27fa900272bf020924eec56b6d)) +* Rebranding to include centripetal forces on getNetForceAndMass ([f20a98a](https://github.com/FloatingArrayDesign/MoorDyn/commit/f20a98aa23a584a0475f6055a33acfda30f39718)) +* The quaternions shall be renormalized to get the rotation matrix ([7256746](https://github.com/FloatingArrayDesign/MoorDyn/commit/7256746793f0c48b6ec4bc8dd97407ad582a9ae2)) diff --git a/source/Body.cpp b/source/Body.cpp index b8a23a09..1a58f5cd 100644 --- a/source/Body.cpp +++ b/source/Body.cpp @@ -80,20 +80,21 @@ Body::setup(int number_in, bodyI = I_in; bodyCdA = CdA_in; bodyCa = Ca_in; - } else if (type == FIXED){ // fixed bodies have no need for these variables other than position... + } else if (type == FIXED) { // fixed bodies have no need for these variables + // other than position... bodyM = 0.0; bodyV = 0.0; bodyI = vec::Zero(); bodyCdA = vec6::Zero(); bodyCa = vec6::Zero(); - } else if (type == CPLDPIN){ + } else if (type == CPLDPIN) { bodyM = M_in; bodyV = V_in; body_rCG = rCG_in; bodyI = I_in; bodyCdA = CdA_in; bodyCa = Ca_in; - } else // coupled bodies have no need for these variables... + } else // coupled bodies have no need for these variables... { bodyM = 0.0; bodyV = 0.0; @@ -203,9 +204,10 @@ Body::initialize() // initialized) setDependentStates(); - if (type == FREE) { // Attached objects already initalized for coupled pinned body - // If any Rod is fixed to the body (not pinned), initialize it now because - // otherwise it won't be initialized + if (type == + FREE) { // Attached objects already initalized for coupled pinned body + // If any Rod is fixed to the body (not pinned), initialize it now + // because otherwise it won't be initialized for (auto attached : attachedR) if (attached->type == Rod::FIXED) attached->initialize(); @@ -273,7 +275,6 @@ Body::setDependentStates() rPoint, rdPoint); //<<< should double check this function - // pass above to the point and get it to calculate the forces try { attachedP[i]->setKinematics(rPoint, rdPoint); @@ -294,12 +295,8 @@ Body::setDependentStates() // do 3d details of Rod ref point vec tmpr, tmprd; // set first three entires (end A translation) of rRod and rdRod - transformKinematics(r6RodRel[i](Eigen::seqN(0, 3)), - OrMat, - r7.pos, - v6, - tmpr, - tmprd); + transformKinematics( + r6RodRel[i](Eigen::seqN(0, 3)), OrMat, r7.pos, v6, tmpr, tmprd); // does the above function need to take in all 6 elements of r6RodRel?? rRod(Eigen::seqN(0, 3)) = tmpr; rdRod(Eigen::seqN(0, 3)) = tmprd; @@ -331,9 +328,11 @@ Body::GetBodyOutput(OutChanProps outChan) vec3 rotations; vec6 Fout; - if ((outChan.QType == RX)||(outChan.QType == RY)||(outChan.QType == RZ)) + if ((outChan.QType == RX) || (outChan.QType == RY) || (outChan.QType == RZ)) rotations = rad2deg * Quat2Euler(r7.quat); - if ((outChan.QType == FX)||(outChan.QType == FY)||(outChan.QType == FZ)||(outChan.QType == MX)||(outChan.QType == MY)||(outChan.QType == MZ)) + if ((outChan.QType == FX) || (outChan.QType == FY) || + (outChan.QType == FZ) || (outChan.QType == MX) || + (outChan.QType == MY) || (outChan.QType == MZ)) Fout = getFnet(); if (outChan.QType == PosX) @@ -414,8 +413,10 @@ Body::initiateStep(vec6 r, vec6 rd, vec6 rdd) } if (type == FIXED) // if fixed body, set the BCs to stationary { - if (bodyId == 0) r_ves = vec6::Zero(); // special ground body case - else r_ves = r; + if (bodyId == 0) + r_ves = vec6::Zero(); // special ground body case + else + r_ves = r; rd_ves = vec6::Zero(); rdd_ves = vec6::Zero(); return; @@ -493,19 +494,24 @@ Body::getStateDeriv(InstanceStateVarView drdt) // Get contributions from attached points (and lines attached to // them) and store in FNet: doRHS(); - if (type == FREE){ + if (type == FREE) { // solve for accelerations in [M]{a}={f} a6 = solveMat6(M, F6net); - // NOTE; is the above still valid even though it includes rotational DOFs? + // NOTE; is the above still valid even though it includes rotational + // DOFs? u7.pos = v6.head<3>(); - // this assumes that the angular velocity is about the global coordinates - // which is true for bodies - u7.quat = 0.5 * (quaternion(0.0, v6[3], v6[4], v6[5]) * r7.quat).coeffs(); + // this assumes that the angular velocity is about the global + // coordinates which is true for bodies + u7.quat = + 0.5 * (quaternion(0.0, v6[3], v6[4], v6[5]) * r7.quat).coeffs(); } else { // Pinned body - // account for moment in response to acceleration due to inertial coupling (off-diagonal sub-matrix terms) - const vec Fnet_out3 = F6net(Eigen::seqN(3, 3)) - (M.bottomLeftCorner<3,3>() * a6(Eigen::seqN(0, 3))); + // account for moment in response to acceleration due to inertial + // coupling (off-diagonal sub-matrix terms) + const vec Fnet_out3 = + F6net(Eigen::seqN(3, 3)) - + (M.bottomLeftCorner<3, 3>() * a6(Eigen::seqN(0, 3))); // For small systems it is usually faster to compute the inverse // of the matrix. See @@ -515,7 +521,8 @@ Body::getStateDeriv(InstanceStateVarView drdt) // dxdt = V (velocities) u7.pos = vec::Zero(); - u7.quat = 0.5 * (quaternion(0.0, v6[3], v6[4], v6[5]) * r7.quat).coeffs(); + u7.quat = + 0.5 * (quaternion(0.0, v6[3], v6[4], v6[5]) * r7.quat).coeffs(); } drdt.row(0).head<7>() = u7.toVec7(); @@ -530,12 +537,15 @@ Body::getFnet() const // this assumes doRHS() has already been called if (type == COUPLED) { // if coupled rigidly - F6_iner = - M * a6; // Inertial terms + F6_iner = -M * a6; // Inertial terms Fnet_out = F6net + F6_iner; } else if (type == CPLDPIN) { // if coupled pinned - F6_iner(Eigen::seqN(0,3)) = (- M.topLeftCorner<3,3>() * a6(Eigen::seqN(0,3))) - (M.topRightCorner<3,3>() * a6(Eigen::seqN(3,3))); // Inertial term - Fnet_out(Eigen::seqN(0,3)) = F6net(Eigen::seqN(0,3)) + F6_iner(Eigen::seqN(0,3)); - Fnet_out(Eigen::seqN(3,3)) = vec3::Zero(); + F6_iner(Eigen::seqN(0, 3)) = + (-M.topLeftCorner<3, 3>() * a6(Eigen::seqN(0, 3))) - + (M.topRightCorner<3, 3>() * a6(Eigen::seqN(3, 3))); // Inertial term + Fnet_out(Eigen::seqN(0, 3)) = + F6net(Eigen::seqN(0, 3)) + F6_iner(Eigen::seqN(0, 3)); + Fnet_out(Eigen::seqN(3, 3)) = vec3::Zero(); } else { // LOGERR << "Invalid body type: " << TypeName(type) << endl; // throw moordyn::invalid_value_error("Invalid body type"); @@ -573,7 +583,7 @@ Body::doRHS() // Centrifugal force due to COM not being at body origin const vec w = v6.tail<3>(); F6net.head<3>() -= - M.topLeftCorner(3, 3) * (w.cross(w.cross(body_rCGrotated))); + M.topLeftCorner(3, 3) * (w.cross(w.cross(body_rCGrotated))); // --------------------------------- apply wave kinematics // ------------------------------------ @@ -594,10 +604,13 @@ Body::doRHS() // Rotational DOFs drag coefficients are also defined on bodyCdA vec6 cda; - cda(Eigen::seqN(0, 3)) = (OrMat * bodyCdA.head<3>().asDiagonal() * OrMat.transpose()) * vi.head<3>() * vi.head<3>().norm(); - cda(Eigen::seqN(3, 3)) = (OrMat * bodyCdA.tail<3>().asDiagonal() * OrMat.transpose()) * vi.tail<3>() * vi.tail<3>().norm(); - F6net += - 0.5 * env->rho_w * cda; + cda(Eigen::seqN(0, 3)) = + (OrMat * bodyCdA.head<3>().asDiagonal() * OrMat.transpose()) * + vi.head<3>() * vi.head<3>().norm(); + cda(Eigen::seqN(3, 3)) = + (OrMat * bodyCdA.tail<3>().asDiagonal() * OrMat.transpose()) * + vi.tail<3>() * vi.tail<3>().norm(); + F6net += 0.5 * env->rho_w * cda; // Get contributions from any points attached to the body for (auto attached : attachedP) { diff --git a/source/Body.h b/source/Body.h index 5679553f..762f757b 100644 --- a/source/Body.h +++ b/source/Body.h @@ -40,118 +40,129 @@ extern "C" { #endif - /** @addtogroup new_c_api - * @{ - */ - - /// A mooring line instance - typedef struct __MoorDynBody* MoorDynBody; - - /** @brief Get the body identifier - * @param b The Moordyn body - * @param id The output id - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetBodyID(MoorDynBody b, int* id); - - /** @brief Get the point type - * @param b The Moordyn body - * @param t The output type - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - * @see Point::types - */ - int DECLDIR MoorDyn_GetBodyType(MoorDynBody b, int* t); - - /** @brief Get the body state - * @param b The Moordyn body - * @param r The output position (6dof) - * @param rd The output velocity (6dof) - * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetBodyState(MoorDynBody b, double r[6], double rd[6]); - - /** @brief Get the body position - * @param b The Moordyn body - * @param r The output position (3dof) - * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetBodyPos(MoorDynBody b, double r[3]); - - /** @brief Get the body angle - * @param b The Moordyn body - * @param r The output angles (3dof) - * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetBodyAngle(MoorDynBody b, double r[3]); - - /** @brief Get the body velocity - * @param b The Moordyn body - * @param rd The output velocity (3dof) - * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetBodyVel(MoorDynBody b, double rd[3]); - - /** @brief Get the body angular velocity - * @param b The Moordyn body - * @param rd The output angular velocity (3dof) - * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetBodyAngVel(MoorDynBody b, double rd[3]); - - /** @brief Get the body angular velocity - * @param b The Moordyn body - * @param rd The output angular velocity (3dof) - * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetBodyForce(MoorDynBody b, double f[6]); - - /** @brief Get the body mass and intertia matrix - * @param b The Moordyn body - * @param m The output mass matrix - * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetBodyM(MoorDynBody b, double m[6][6]); - - /** @brief Save the point to a VTK (.vtp) file - * @param b The Moordyn body - * @param filename The output maximum tension module - * @return MOORDYN_SUCCESS if the file is correctly written, an error code - * otherwise - * @note If MoorDyn has been built without VTK support, this function will - * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available - * anyway - */ - int DECLDIR MoorDyn_SaveBodyVTK(MoorDynBody b, const char* filename); - - /** @brief Load the model that would represent the body - * - * The model can have one of the following formats: - * - * - VTK PolyData (.vtp) - * - Stereo Lithography (.stl) - * - * @param b The Moordyn body - * @param filename The output maximum tension module - * @return MOORDYN_SUCCESS if the file is correctly written, an error code - * otherwise - * @note If MoorDyn has been built without VTK support, this function will - * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available - * anyway - */ - int DECLDIR MoorDyn_UseBodyVTK(MoorDynBody b, const char* filename); - - /** - * @} - */ +/** @addtogroup new_c_api + * @{ + */ + +/// A mooring line instance +typedef struct __MoorDynBody* MoorDynBody; + +/** @brief Get the body identifier + * @param b The Moordyn body + * @param id The output id + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetBodyID(MoorDynBody b, int* id); + +/** @brief Get the point type + * @param b The Moordyn body + * @param t The output type + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + * @see Point::types + */ +int DECLDIR +MoorDyn_GetBodyType(MoorDynBody b, int* t); + +/** @brief Get the body state + * @param b The Moordyn body + * @param r The output position (6dof) + * @param rd The output velocity (6dof) + * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetBodyState(MoorDynBody b, double r[6], double rd[6]); + +/** @brief Get the body position + * @param b The Moordyn body + * @param r The output position (3dof) + * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetBodyPos(MoorDynBody b, double r[3]); + +/** @brief Get the body angle + * @param b The Moordyn body + * @param r The output angles (3dof) + * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetBodyAngle(MoorDynBody b, double r[3]); + +/** @brief Get the body velocity + * @param b The Moordyn body + * @param rd The output velocity (3dof) + * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetBodyVel(MoorDynBody b, double rd[3]); + +/** @brief Get the body angular velocity + * @param b The Moordyn body + * @param rd The output angular velocity (3dof) + * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetBodyAngVel(MoorDynBody b, double rd[3]); + +/** @brief Get the body angular velocity + * @param b The Moordyn body + * @param rd The output angular velocity (3dof) + * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetBodyForce(MoorDynBody b, double f[6]); + +/** @brief Get the body mass and intertia matrix + * @param b The Moordyn body + * @param m The output mass matrix + * @return MOORDYN_INVALID_VALUE if a NULL body is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetBodyM(MoorDynBody b, double m[6][6]); + +/** @brief Save the point to a VTK (.vtp) file + * @param b The Moordyn body + * @param filename The output maximum tension module + * @return MOORDYN_SUCCESS if the file is correctly written, an error code + * otherwise + * @note If MoorDyn has been built without VTK support, this function will + * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available + * anyway + */ +int DECLDIR +MoorDyn_SaveBodyVTK(MoorDynBody b, const char* filename); + +/** @brief Load the model that would represent the body + * + * The model can have one of the following formats: + * + * - VTK PolyData (.vtp) + * - Stereo Lithography (.stl) + * + * @param b The Moordyn body + * @param filename The output maximum tension module + * @return MOORDYN_SUCCESS if the file is correctly written, an error code + * otherwise + * @note If MoorDyn has been built without VTK support, this function will + * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available + * anyway + */ +int DECLDIR +MoorDyn_UseBodyVTK(MoorDynBody b, const char* filename); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/source/Body.hpp b/source/Body.hpp index dec05f1f..fa83a3f1 100644 --- a/source/Body.hpp +++ b/source/Body.hpp @@ -70,7 +70,9 @@ class Rod; * * Name/ID, X0, Y0, Z0, Xcg, Ycg, Zcg, M, V, IX, IY, IZ, CdA-x,y,z Ca-x,y,z */ -class DECLDIR Body final : public Instance, public SuperCFL +class DECLDIR Body final + : public Instance + , public SuperCFL { public: /** @brief Costructor @@ -176,7 +178,7 @@ class DECLDIR Body final : public Instance, public SuperCFL case COUPLED: return "COUPLED"; case CPLDPIN: - return "CPLDPIN"; + return "CPLDPIN"; case FREE: return "FREE"; case FIXED: @@ -337,7 +339,10 @@ class DECLDIR Body final : public Instance, public SuperCFL /** @brief Get the body angular velocity * @return The body angular velocity */ - inline const vec getAngularVelocity() const { return v6(Eigen::seqN(3, 3)); } + inline const vec getAngularVelocity() const + { + return v6(Eigen::seqN(3, 3)); + } /** @brief Get the forces and moments exerted over the body * @return The net force @@ -388,7 +393,6 @@ class DECLDIR Body final : public Instance, public SuperCFL */ void setState(const InstanceStateVarView r); - /** @brief calculate the forces and state derivatives of the body * * This function is only meant for free bodies diff --git a/source/IO.cpp b/source/IO.cpp index cc9f2779..d0a5189e 100644 --- a/source/IO.cpp +++ b/source/IO.cpp @@ -311,7 +311,7 @@ IO::LoadFile(const std::string filepath) const f.read((char*)data, size); f.close(); - return {length, data}; + return { length, data }; } uint64_t diff --git a/source/IO.hpp b/source/IO.hpp index 1490daee..41752550 100644 --- a/source/IO.hpp +++ b/source/IO.hpp @@ -212,7 +212,7 @@ class DECLDIR IO : public LogUser * @return The packed list */ inline std::vector Serialize( - const Eigen::Matrix& l) + const Eigen::Matrix& l) { std::vector data; const uint64_t n = l.rows(); @@ -350,8 +350,8 @@ class DECLDIR IO : public LogUser * @return The new pointer to the remaining data to be read */ uint64_t* Deserialize( - const uint64_t* in, - Eigen::Matrix& out) + const uint64_t* in, + Eigen::Matrix& out) { uint64_t* remaining; uint64_t n, m; diff --git a/source/Instance.cpp b/source/Instance.cpp index eacd4cd9..a66742f0 100644 --- a/source/Instance.cpp +++ b/source/Instance.cpp @@ -28,9 +28,10 @@ Instance::Instance(moordyn::Log* log) _id = __instances_counter++; } -void reset_instance_ids() +void +reset_instance_ids() { __instances_counter = 0; } -} // ::moordyn +} // ::moordyn diff --git a/source/Instance.hpp b/source/Instance.hpp index ee3a93ad..bc0d47c2 100644 --- a/source/Instance.hpp +++ b/source/Instance.hpp @@ -106,6 +106,7 @@ class DECLDIR Instance : public io::IO * @return The dimension of the state variable */ virtual inline const size_t stateDims() const { return 6; } + private: /// Unique identifier of this instance size_t _id; @@ -114,6 +115,7 @@ class DECLDIR Instance : public io::IO /** @brief Reset the instances Ids, so they will be assigned again starting * from 0 */ -void reset_instance_ids(); +void +reset_instance_ids(); } // ::moordyn diff --git a/source/Line.cpp b/source/Line.cpp index 47883848..2e738d0f 100644 --- a/source/Line.cpp +++ b/source/Line.cpp @@ -130,7 +130,7 @@ Line::setup(int number_in, EnvCondRef env_in, shared_ptr outfile_pointer, string channels_in, - real dtM0) + real dtM0) { env = env_in; // set pointer to environment settings object number = number_in; @@ -201,21 +201,22 @@ Line::setup(int number_in, // ------------------------- size vectors ------------------------- - pin.assign(N + 1, 0.0); // Internal pressure at node points (Pa) + pin.assign(N + 1, 0.0); // Internal pressure at node points (Pa) - r.assign(N + 1, vec::Zero()); // node positions [i][x/y/z] - rd.assign(N + 1, vec::Zero()); // node velocities [i][x/y/z] - rdd_old.assign(N + 1, vec::Zero()); // node accelerations previous iteration [i][x/y/z] - q.assign(N + 1, vec::Zero()); // unit tangent vectors for each node - pvec.assign(N + 1, vec::Zero()); // unit normal vectors for each node - qs.assign(N, vec::Zero()); // unit tangent vectors for each segment - l.assign(N, 0.0); // line unstretched segment lengths - lstr.assign(N, 0.0); // stretched lengths - ldstr.assign(N, 0.0); // rate of stretch - Kurv.assign(N + 1, 0.0); // curvatures at node points (1/m) + r.assign(N + 1, vec::Zero()); // node positions [i][x/y/z] + rd.assign(N + 1, vec::Zero()); // node velocities [i][x/y/z] + rdd_old.assign( + N + 1, vec::Zero()); // node accelerations previous iteration [i][x/y/z] + q.assign(N + 1, vec::Zero()); // unit tangent vectors for each node + pvec.assign(N + 1, vec::Zero()); // unit normal vectors for each node + qs.assign(N, vec::Zero()); // unit tangent vectors for each segment + l.assign(N, 0.0); // line unstretched segment lengths + lstr.assign(N, 0.0); // stretched lengths + ldstr.assign(N, 0.0); // rate of stretch + Kurv.assign(N + 1, 0.0); // curvatures at node points (1/m) - M.assign(N + 1, mat::Zero()); // mass matrices (3x3) for each node - V.assign(N, 0.0); // segment volume? + M.assign(N + 1, mat::Zero()); // mass matrices (3x3) for each node + V.assign(N, 0.0); // segment volume? // forces T.assign(N, vec::Zero()); // segment tensions @@ -228,23 +229,27 @@ Line::setup(int number_in, Ap.assign(N + 1, vec::Zero()); // node added mass forcing (transverse) Aq.assign(N + 1, vec::Zero()); // node added mass forcing (axial) B.assign(N + 1, vec::Zero()); // node bottom contact force - Lf.assign(N + 1, vec::Zero()); // viv crossflow lift force + Lf.assign(N + 1, vec::Zero()); // viv crossflow lift force Fnet.assign(N + 1, vec::Zero()); // total force on node // wave things F.assign(N + 1, 0.0); // VOF scaler for each NODE (mean of two half adjacent // segments) (1 = fully submerged, 0 = out of water) - // viscoelastic things + // viscoelastic things if (ElasticMod > 1) { - dl_1.assign(N, 0.0); // segment stretch attributed to static stiffness portion [m] - ld_1.assign(N, 0.0); // rate of change of static stiffness portion [m/s] (Ldot_1) + dl_1.assign( + N, + 0.0); // segment stretch attributed to static stiffness portion [m] + ld_1.assign( + N, + 0.0); // rate of change of static stiffness portion [m/s] (Ldot_1) } // VIV things if (Cl > 0) { phi.assign(N + 1, 0.0); // synch model phase - phi_dot.assign(N + 1, 0.0); // synch model frequency + phi_dot.assign(N + 1, 0.0); // synch model frequency yd_rms_old.assign(N + 1, 0.0); // node old yd_rms ydd_rms_old.assign(N + 1, 0.0); // node old ydd_rms } @@ -273,19 +278,19 @@ Line::initialize() << " N : " << N << endl << " d : " << d << endl << " rho : " << rho << endl - << " EAMod : " << ElasticMod << endl + << " EAMod : " << ElasticMod << endl << " EA : " << EA << endl - << " BA : " << BAin << endl + << " BA : " << BAin << endl << " EI : " << EI << endl << " Can : " << Can << endl << " Cat : " << Cat << endl << " Cdn : " << Cdn << endl << " Cdt : " << Cdt << endl - << " Cl : " << Cl << endl - << " dF : " << dF << endl - << " cF : " << cF << endl - << " ww_l : " << ((rho - env->rho_w) * (pi / 4. * d * d)) * 9.81 - << endl; + << " Cl : " << Cl << endl + << " dF : " << dF << endl + << " cF : " << cF << endl + << " ww_l : " + << ((rho - env->rho_w) * (pi / 4. * d * d)) * 9.81 << endl; if (outfile) { if (!outfile->is_open()) { @@ -487,10 +492,13 @@ Line::initialize() if (BAin < 0) { // automatic internal damping option (if negative BA provided (stored as // BAin), then -BAin indicates desired damping ratio [unitless]) - BA = -BAin * UnstrLen / N * sqrt(EA * rho * A); // rho = w/A. Units: no unit * m * sqrt(kg-m/s^2 *kg/m) = Ns + BA = + -BAin * UnstrLen / N * + sqrt( + EA * rho * + A); // rho = w/A. Units: no unit * m * sqrt(kg-m/s^2 *kg/m) = Ns LOGMSG << "Line " << number << " damping set to " << BA / A - << " Pa-s = " << BA << " Ns, based on input of " << BAin - << endl; + << " Pa-s = " << BA << " Ns, based on input of " << BAin << endl; } else { // otherwise it's the regular internal damping coefficient, which should // be divided by area to get a material coefficient @@ -498,8 +506,10 @@ Line::initialize() } if (BA_D < 0) { - LOGERR << "Line dynamic damping cannot be a ratio for Line " << number << endl; - throw moordyn::invalid_value_error("Line dynamic damping cannot be a ratio"); + LOGERR << "Line dynamic damping cannot be a ratio for Line " << number + << endl; + throw moordyn::invalid_value_error( + "Line dynamic damping cannot be a ratio"); } // initialize line node positions as distributed linearly between the @@ -512,14 +522,15 @@ Line::initialize() // catenary routine (from FAST v.7) real XF = dir(Eigen::seqN(0, 2)).norm(); // horizontal spread - if (XF > 0.0001) { // tolerance for calculation of XF when points are not along x or y axis + if (XF > 0.0001) { // tolerance for calculation of XF when points are not + // along x or y axis // Check if the line touches the seabed, so we are modelling it. Just // the end points are checked const real Tol = 1e-5; real CB = -1.0; for (unsigned int i = 0; i <= N; i += N) { const real waterDepth = getWaterDepth(r[i][0], r[i][1]); - if(r[i][2] <= waterDepth * (1.0 - Tol)) + if (r[i][2] <= waterDepth * (1.0 - Tol)) CB = 0.0; } const real ZF = dir[2]; @@ -554,17 +565,17 @@ Line::initialize() &VF, &HA, &VA, - N+1, + N + 1, snodes, Xl, Zl, Te); if (success >= 0) { - + // the catenary solve is successful, update the node positions - LOGDBG << "Catenary initial profile available for Line " - << number << endl; + LOGDBG << "Catenary initial profile available for Line " << number + << endl; for (unsigned int i = 1; i < N; i++) { vec l(Xl[i] * COSPhi, Xl[i] * SINPhi, Zl[i]); r[i] = r[0] + l; @@ -577,23 +588,28 @@ Line::initialize() LOGDBG << "Vertical linear initial profile for Line " << number << endl; } - // If using the viscoelastic model, initalize the deltaL_1 to the delta L of the segment. - // This is required here to initalize the state as non-zero, which avoids an initial - // transient where the segment goes from unstretched to stretched in one time step. + // If using the viscoelastic model, initalize the deltaL_1 to the delta L of + // the segment. This is required here to initalize the state as non-zero, + // which avoids an initial transient where the segment goes from unstretched + // to stretched in one time step. if (ElasticMod > 1) { for (unsigned int i = 0; i < N; i++) { - lstr[i] = unitvector(qs[i], r[i], r[i + 1]); + lstr[i] = unitvector(qs[i], r[i], r[i + 1]); dl_1[i] = lstr[i] - l[i]; // delta l of the segment } } - // If using the VIV model, initalize as a distribution between 0 and 2pi for inital phase of lift force to avoid initial transient + // If using the VIV model, initalize as a distribution between 0 and 2pi for + // inital phase of lift force to avoid initial transient if (Cl > 0) - for (unsigned int i = 1; i < N; i++) phi[i] = (i/moordyn::real(N))*2*pi; // internal nodes only. Change if end node viv included + for (unsigned int i = 1; i < N; i++) + phi[i] = (i / moordyn::real(N)) * 2 * + pi; // internal nodes only. Change if end node viv included LOGMSG << "Initialized Line " << number << endl; - // NOTE: becasue Line.hpp is the only user of this function, no need to return any state information + // NOTE: becasue Line.hpp is the only user of this function, no need to + // return any state information } real @@ -615,8 +631,7 @@ Line::GetLineOutput(OutChanProps outChan) if ((outChan.NodeID == 0) || (outChan.NodeID == (int)N)) return getNodeForce(outChan.NodeID).norm(); return getNodeTen(outChan.NodeID).norm(); - } - else if (outChan.QType == TenA) + } else if (outChan.QType == TenA) return getNodeForce(0).norm(); else if (outChan.QType == TenB) return getNodeForce(N).norm(); @@ -730,9 +745,10 @@ Line::setState(const InstanceStateVarView state) { // ----- State Instance Structure for Line ----- - // Each row corresponds to an internal node. When the viscoelastic case is - // activated the last column corresponds to the viscoelastic state for each segment. - // This means indexing the rows for the viscoelastic state is shifted by one. + // Each row corresponds to an internal node. When the viscoelastic case is + // activated the last column corresponds to the viscoelastic state for each + // segment. This means indexing the rows for the viscoelastic state is + // shifted by one. // // Normal case: // - N-1 rows @@ -749,35 +765,53 @@ Line::setState(const InstanceStateVarView state) // - row[i] = [rix, riy, riz, rdix, rdiy, rdiz, phii, ldot_1i] // - note there will be 7 unused values in the last row - - // Error check for number of columns (if VIV and Visco need row.size() = 8, if VIV xor Visco need row.size() = 7, if not VIV need row.size() = 6) - if ( (state.row(0).size() != 8 && Cl > 0 && ElasticMod > 1) || (state.row(0).size() != 7 && ((Cl > 0) ^ (ElasticMod > 1))) || (state.row(0).size() != 6 && Cl == 0 && ElasticMod == 1)) { + // Error check for number of columns (if VIV and Visco need row.size() = 8, + // if VIV xor Visco need row.size() = 7, if not VIV need row.size() = 6) + if ((state.row(0).size() != 8 && Cl > 0 && ElasticMod > 1) || + (state.row(0).size() != 7 && ((Cl > 0) ^ (ElasticMod > 1))) || + (state.row(0).size() != 6 && Cl == 0 && ElasticMod == 1)) { LOGERR << "Invalid state.row size for Line " << number << endl; throw moordyn::mem_error("Invalid state.row size"); } - // Error check for number of rows (if visco need N rows, if normal need N-1 rows) - if ((state.rows() != N && ElasticMod > 1) || (state.rows() != N-1 && ElasticMod == 1)) { - LOGERR << "Invalid number of rows in state matrix for Line " << number << endl; + // Error check for number of rows (if visco need N rows, if normal need N-1 + // rows) + if ((state.rows() != N && ElasticMod > 1) || + (state.rows() != N - 1 && ElasticMod == 1)) { + LOGERR << "Invalid number of rows in state matrix for Line " << number + << endl; throw moordyn::mem_error("Invalid number of rows in state matrix"); } // If using the viscoelastic model, interate N rows, else iterate N-1 rows. - for (unsigned int i = 0; i < (ElasticMod > 1 ? N : N-1); i++) { + for (unsigned int i = 0; i < (ElasticMod > 1 ? N : N - 1); i++) { // node number is i+1 // segment number is i - if (i < N-1) { // only assign the internal nodes - r[i+1] = state.row(i).head<3>(); - rd[i+1] = state.row(i).segment<3>(3); + if (i < N - 1) { // only assign the internal nodes + r[i + 1] = state.row(i).head<3>(); + rd[i + 1] = state.row(i).segment<3>(3); } - if (ElasticMod > 1) dl_1[i] = state.row(i).tail<1>()[0]; // [0] needed becasue tail<1> returns a one element vector. Viscoelastic state is always the last element in the row - - if (Cl > 0 && !(IC_gen)) { // not needed in IC_gen. Initializes as distribution on 0-2pi. State is initialized by init function in this code, which sets phi to range 0-2pi - if (ElasticMod > 1) phi[i+1] = state.row(i).tail<2>()[0]; // if both VIV and viscoelastic second to last element in the row - else phi[i+1] = state.row(i).tail<1>()[0]; // else last element in the row - } - + if (ElasticMod > 1) + dl_1[i] = + state.row(i) + .tail<1>()[0]; // [0] needed becasue tail<1> returns a one + // element vector. Viscoelastic state is + // always the last element in the row + + if (Cl > 0 && + !(IC_gen)) { // not needed in IC_gen. Initializes as distribution on + // 0-2pi. State is initialized by init function in this + // code, which sets phi to range 0-2pi + if (ElasticMod > 1) + phi[i + 1] = + state.row(i) + .tail<2>()[0]; // if both VIV and viscoelastic second to + // last element in the row + else + phi[i + 1] = + state.row(i).tail<1>()[0]; // else last element in the row + } } } @@ -876,9 +910,10 @@ Line::getStateDeriv(InstanceStateVarView drdt) { // ----- State Instance Structure for Line ----- - // Each row corresponds to an internal node. When the viscoelastic case is - // activated the last column corresponds to the viscoelastic state for each segment. - // This means indexing the rows for the viscoelastic state is shifted by one. + // Each row corresponds to an internal node. When the viscoelastic case is + // activated the last column corresponds to the viscoelastic state for each + // segment. This means indexing the rows for the viscoelastic state is + // shifted by one. // // Normal case: // - N-1 rows @@ -915,7 +950,8 @@ Line::getStateDeriv(InstanceStateVarView drdt) // dt is possibly used for stability tricks... - // ======= calculate various kinematic quantities and stiffness forces ======= + // ======= calculate various kinematic quantities and stiffness forces + // ======= // calculate unit tangent vectors (q) for each internal node. note: I've // reversed these from pointing toward 0 rather than N. Check sign of wave @@ -938,9 +974,13 @@ Line::getStateDeriv(InstanceStateVarView drdt) // loop through the segments for stiffness forces and segment lengths for (unsigned int i = 0; i < N; i++) { // calculate current (Stretched) segment lengths and unit tangent - // vectors (qs) for each segment (this is used for bending and stiffness calculations) + // vectors (qs) for each segment (this is used for bending and stiffness + // calculations) - lstr[i] = unitvector(qs[i], r[i], r[i + 1]); // if using the viscoelastic model this is redundant for the first time step, as it is also called by Line::initalize + lstr[i] = unitvector( + qs[i], r[i], r[i + 1]); // if using the viscoelastic model this is + // redundant for the first time step, as it + // is also called by Line::initalize ldstr[i] = qs[i].dot(rd[i + 1] - rd[i]); // strain rate of segment @@ -965,46 +1005,82 @@ Line::getStateDeriv(InstanceStateVarView drdt) BA = getNonlinearBA(ldstr[i], l[i]); Td[i] = BA * ldstr[i] / l[i] * qs[i]; - } else if (ElasticMod > 1){ // viscoelastic model from https://asmedigitalcollection.asme.org/OMAE/proceedings/IOWTC2023/87578/V001T01A029/1195018 - // note that dl_1[i] is the same as Line%dl_1 in MD-F. This is the deltaL of the first static spring k1. - + } else if ( + ElasticMod > + 1) { // viscoelastic model from + // https://asmedigitalcollection.asme.org/OMAE/proceedings/IOWTC2023/87578/V001T01A029/1195018 + // note that dl_1[i] is the same as Line%dl_1 in MD-F. This is the + // deltaL of the first static spring k1. + if (ElasticMod == 2) { - // constant dynamic stiffness - EA_2 = EA_D; - - } else if (ElasticMod == 3){ - if (dl_1[i] >= 0.0) // spring k1 is in tension - // Mean load dependent dynamic stiffness: from combining eqn. 2 and eqn. 10 from original MD viscoelastic paper, taking mean load = k1 delta_L1 / MBL, and solving for k_D using WolframAlpha with following conditions: k_D > k_s, (MBL,alpha,beta,unstrLen,delta_L1) > 0 - EA_2 = 0.5 * ((alphaMBL) + (vbeta*dl_1[i]*(EA / l[i])) + EA + sqrt((alphaMBL * alphaMBL) + (2*alphaMBL*(EA / l[i]) * (vbeta*dl_1[i] - l[i])) + ((EA / l[i])*(EA / l[i]) * (vbeta*dl_1[i] + l[i])*(vbeta*dl_1[i] + l[i])))); - - else // spring k1 is in compression - EA_2 = alphaMBL; // mean load is considered to be 0 in this case. The second term in the above equation is not valid for delta_L1 < 0. - } - - if (EA_2 == 0.0) { // Make sure EA_2 != 0 or else nans, also make sure EA != EA_D or else nans. - LOGERR << "Viscoelastic model: Dynamic stiffness cannot equal zero" << endl; - throw moordyn::invalid_value_error("Viscoelastic model: Dynamic stiffness cannot equal zero"); + // constant dynamic stiffness + EA_2 = EA_D; + + } else if (ElasticMod == 3) { + if (dl_1[i] >= 0.0) // spring k1 is in tension + // Mean load dependent dynamic stiffness: from combining + // eqn. 2 and eqn. 10 from original MD viscoelastic paper, + // taking mean load = k1 delta_L1 / MBL, and solving for k_D + // using WolframAlpha with following conditions: k_D > k_s, + // (MBL,alpha,beta,unstrLen,delta_L1) > 0 + EA_2 = 0.5 * + ((alphaMBL) + (vbeta * dl_1[i] * (EA / l[i])) + EA + + sqrt((alphaMBL * alphaMBL) + + (2 * alphaMBL * (EA / l[i]) * + (vbeta * dl_1[i] - l[i])) + + ((EA / l[i]) * (EA / l[i]) * + (vbeta * dl_1[i] + l[i]) * + (vbeta * dl_1[i] + l[i])))); + + else // spring k1 is in compression + EA_2 = alphaMBL; // mean load is considered to be 0 in this + // case. The second term in the above + // equation is not valid for delta_L1 < 0. + } + + if (EA_2 == 0.0) { // Make sure EA_2 != 0 or else nans, also make + // sure EA != EA_D or else nans. + LOGERR + << "Viscoelastic model: Dynamic stiffness cannot equal zero" + << endl; + throw moordyn::invalid_value_error( + "Viscoelastic model: Dynamic stiffness cannot equal zero"); } else if (EA_2 == EA) { - LOGERR << "Viscoelastic model: Dynamic stiffness cannot equal static stiffness" << endl; - throw moordyn::invalid_value_error("Viscoelastic model: Dynamic stiffness cannot equal static stiffness"); + LOGERR << "Viscoelastic model: Dynamic stiffness cannot equal " + "static stiffness" + << endl; + throw moordyn::invalid_value_error( + "Viscoelastic model: Dynamic stiffness cannot equal static " + "stiffness"); } - - const real EA_1 = EA_2*EA/(EA_2 - EA); // calculated EA_1 which is the stiffness in series with EA_D that will result in the desired static stiffness of EA_S. - - const real dl = lstr[i] - l[i]; // delta l of this segment - + + const real EA_1 = + EA_2 * EA / + (EA_2 - EA); // calculated EA_1 which is the stiffness in series + // with EA_D that will result in the desired static + // stiffness of EA_S. + + const real dl = lstr[i] - l[i]; // delta l of this segment + // update state derivative for static stiffness stretch - ld_1[i] = (EA_2*dl - (EA_2 + EA_1)*dl_1[i] + BA_D*ldstr[i]) /( BA_D + BA); // rate of change of static stiffness portion [m/s] + ld_1[i] = + (EA_2 * dl - (EA_2 + EA_1) * dl_1[i] + BA_D * ldstr[i]) / + (BA_D + BA); // rate of change of static stiffness portion [m/s] + + if (dl >= 0.0) // if both spring 1 (the spring dashpot in parallel) + // and the whole segment are not in compression + T[i] = + (EA_1 * dl_1[i] / l[i]) * + qs[i]; // compute tension based on static portion (dynamic + // portion would give same). See eqn. 14 in paper + else + T[i] = vec::Zero(); // cable can't "push" - if (dl >= 0.0) // if both spring 1 (the spring dashpot in parallel) and the whole segment are not in compression - T[i] = (EA_1*dl_1[i] / l[i]) * qs[i]; // compute tension based on static portion (dynamic portion would give same). See eqn. 14 in paper - else - T[i] = vec::Zero(); // cable can't "push" + Td[i] = BA * ld_1[i] / l[i] * qs[i]; - Td[i] = BA*ld_1[i] / l[i] * qs[i]; - - // update state derivative for static stiffness stretch. The visco state is always the last element in the row. - drdt.row(i).tail<1>()[0] = ld_1[i]; + // update state derivative for static stiffness stretch. The visco + // state is always the last element in the row. + drdt.row(i).tail<1>()[0] = ld_1[i]; } } @@ -1014,13 +1090,15 @@ Line::getStateDeriv(InstanceStateVarView drdt) if (i == 0) { // end node A case (only if attached to a Rod, i.e. a // cantilever rather than pinned point) - Kurv[i] = (endTypeA == CANTILEVERED) ? - GetCurvature(lstr[0], q[0], qs[0]) : 0.0; + Kurv[i] = (endTypeA == CANTILEVERED) + ? GetCurvature(lstr[0], q[0], qs[0]) + : 0.0; } else if (i == N) { // end node B case (only if attached to a Rod, i.e. a // cantilever rather than pinned point) - Kurv[i] = (endTypeB == CANTILEVERED) ? - GetCurvature(lstr[i - 1], qs[i - 1], q[i]) : 0.0; + Kurv[i] = (endTypeB == CANTILEVERED) + ? GetCurvature(lstr[i - 1], qs[i - 1], q[i]) + : 0.0; } else { // internal node // curvature <<< remember to check sign, or just take abs @@ -1062,7 +1140,8 @@ Line::getStateDeriv(InstanceStateVarView drdt) } //============================================================================================ - // ============ CALCULATE FORCES ON EACH NODE =============================== + // ============ CALCULATE FORCES ON EACH NODE + // =============================== // Bending loads // first zero out the forces from last run @@ -1084,8 +1163,7 @@ Line::getStateDeriv(InstanceStateVarView drdt) if (i == 0) { // end node A case (only if attached to a Rod, i.e. a // cantilever rather than pinned point) - if (endTypeA == CANTILEVERED) - { + if (endTypeA == CANTILEVERED) { if (nEIpoints > 0) EI = getNonlinearEI(Kurvi); @@ -1212,7 +1290,7 @@ Line::getStateDeriv(InstanceStateVarView drdt) } */ } // for i=0,N (looping through nodes) - } // if EI > 0 + } // if EI > 0 if (isPb) { // loop through all nodes to calculate bending forces @@ -1271,7 +1349,6 @@ Line::getStateDeriv(InstanceStateVarView drdt) W[i][0] = W[i][1] = 0.0; W[i][2] = -g * (m_i - v_i * rho_w); - // magnitude of current const real Ui_mag = U[i].norm(); // Unit vector of current flow @@ -1296,52 +1373,85 @@ Line::getStateDeriv(InstanceStateVarView drdt) // Vortex Induced Vibration (VIV) cross-flow lift force Lf[i] = vec::Zero(); - if (Cl > 0 && !IC_gen && i != 0 && i != N) { // If non-zero lift coefficient and not during IC_gen and internal node then VIV to be calculated - - // Note: This logic is slightly different than MD-F, but equivalent. MD-F runs the VIV model for all nodes - // (including end nodes), and then zeros the lift force for the end nodes. That means in MD-F the state vector - // has N+1 extra states when using the VIV model. That approach means in the future if we can get the end node - // accelerations, we can easily add those into the VIV model. This approach does not do that, and only computes - // the lift force for internal nodes. We do that here becasue the state matrix approach introduced in PR#291 - // means we have N-1 states with 7 elements for internal nodes. If we did the MD-F approach, we would end up - // with a N+1 x 7 state matrix, which would have unused states. In the future, if we get the end node - // accelerations, we will need to change to the bigger state matrix in this code. + if (Cl > 0 && !IC_gen && i != 0 && + i != N) { // If non-zero lift coefficient and not during IC_gen and + // internal node then VIV to be calculated + + // Note: This logic is slightly different than MD-F, but equivalent. + // MD-F runs the VIV model for all nodes (including end nodes), and + // then zeros the lift force for the end nodes. That means in MD-F + // the state vector has N+1 extra states when using the VIV model. + // That approach means in the future if we can get the end node + // accelerations, we can easily add those into the VIV model. This + // approach does not do that, and only computes the lift force for + // internal nodes. We do that here becasue the state matrix approach + // introduced in PR#291 means we have N-1 states with 7 elements for + // internal nodes. If we did the MD-F approach, we would end up with + // a N+1 x 7 state matrix, which would have unused states. In the + // future, if we get the end node accelerations, we will need to + // change to the bigger state matrix in this code. // ----- The Synchronization Model ------ // Crossflow velocity const real yd = rd[i].dot(q[i].cross(vp.normalized())); - const real ydd = rdd_old[i].dot(q[i].cross(vp.normalized())); // note: rdd_old initializes as 0's. End nodes don't ever get updated, thus stay at zero + const real ydd = rdd_old[i].dot( + q[i].cross(vp.normalized())); // note: rdd_old initializes as + // 0's. End nodes don't ever get + // updated, thus stay at zero // Rolling RMS calculation - const real yd_rms = sqrt((((n_m-1)*yd_rms_old[i]*yd_rms_old[i])+(yd*yd))/n_m); // RMS approximation from Thorsen - const real ydd_rms = sqrt((((n_m-1)*ydd_rms_old[i]*ydd_rms_old[i])+(ydd*ydd))/n_m); - - if ((t >= t_old + dtm0) || (t == 0.0)) { // Update the stormed RMS vaues - // update back indexing one moordyn time step (regardless of time integration scheme). T_old is handled at end of getStateDeriv when rdd_old is updated. - yd_rms_old[i] = yd_rms; // for rms back indexing (one moordyn timestep back) - ydd_rms_old[i] = ydd_rms; // for rms back indexing (one moordyn timestep back) + const real yd_rms = + sqrt((((n_m - 1) * yd_rms_old[i] * yd_rms_old[i]) + (yd * yd)) / + n_m); // RMS approximation from Thorsen + const real ydd_rms = sqrt( + (((n_m - 1) * ydd_rms_old[i] * ydd_rms_old[i]) + (ydd * ydd)) / + n_m); + + if ((t >= t_old + dtm0) || + (t == 0.0)) { // Update the stormed RMS vaues + // update back indexing one moordyn time step (regardless of + // time integration scheme). T_old is handled at end of + // getStateDeriv when rdd_old is updated. + yd_rms_old[i] = + yd_rms; // for rms back indexing (one moordyn timestep back) + ydd_rms_old[i] = ydd_rms; // for rms back indexing (one moordyn + // timestep back) } - if ((yd_rms==0.0) || (ydd_rms == 0.0)) phi_yd = atan2(-ydd, yd); // To avoid divide by zero - else phi_yd = atan2(-ydd/ydd_rms, yd/yd_rms); - - if (phi_yd < 0) phi_yd = 2*pi + phi_yd; // atan2 to 0-2Pi range + if ((yd_rms == 0.0) || (ydd_rms == 0.0)) + phi_yd = atan2(-ydd, yd); // To avoid divide by zero + else + phi_yd = atan2(-ydd / ydd_rms, yd / yd_rms); + + if (phi_yd < 0) + phi_yd = 2 * pi + phi_yd; // atan2 to 0-2Pi range + + // Map integrated phase to 0-2Pi range. Is this necessary? sin (a-b) + // is the same if b is 100 pi or 2pi + phi[i] = phi[i] - (2 * pi * floor(phi[i] / (2 * pi))); - // Map integrated phase to 0-2Pi range. Is this necessary? sin (a-b) is the same if b is 100 pi or 2pi - phi[i] = phi[i] - (2 * pi * floor(phi[i] / (2*pi))); - // non-dimensional frequency - const real f_hat = cF + dF *sin(phi_yd - phi[i]); // phi is integrated from state deriv phi_dot + const real f_hat = + cF + + dF * sin(phi_yd - + phi[i]); // phi is integrated from state deriv phi_dot // frequency of lift force (rad/s) - phi_dot[i] = 2*pi*f_hat*vp_mag / d;// to be added to state + phi_dot[i] = 2 * pi * f_hat * vp_mag / d; // to be added to state // The Lift force - Lf[i] = 0.5 * env->rho_w * d * vp_mag * Cl * cos(phi[i]) * q[i].cross(vp) * submerged_length; - - // Update state derivative for VIV. i-1 indexing because this is only called for internal nodes (i.e. node 1 maps to row 0 in the state deriv matrix). - if (ElasticMod > 1) drdt.row(i-1).tail<2>()[0] = phi_dot[i]; // second to last element if visco model - else drdt.row(i-1).tail<1>()[0] = phi_dot[i]; // last element if not visco model - } + Lf[i] = 0.5 * env->rho_w * d * vp_mag * Cl * cos(phi[i]) * + q[i].cross(vp) * submerged_length; + + // Update state derivative for VIV. i-1 indexing because this is + // only called for internal nodes (i.e. node 1 maps to row 0 in the + // state deriv matrix). + if (ElasticMod > 1) + drdt.row(i - 1).tail<2>()[0] = + phi_dot[i]; // second to last element if visco model + else + drdt.row(i - 1).tail<1>()[0] = + phi_dot[i]; // last element if not visco model + } // tangential component of fluid acceleration // <<<<<<< check sign since I've reversed q @@ -1400,8 +1510,8 @@ Line::getStateDeriv(InstanceStateVarView drdt) Fnet[i] = -T[i - 1] - Td[i - 1]; else Fnet[i] = T[i] - T[i - 1] + Td[i] - Td[i - 1]; - Fnet[i] += W[i] + (Dp[i] + Dq[i] + Ap[i] + Aq[i]) + B[i] + - Bs[i] + Lf[i] + Pb[i]; + Fnet[i] += W[i] + (Dp[i] + Dq[i] + Ap[i] + Aq[i]) + B[i] + Bs[i] + + Lf[i] + Pb[i]; } // loop through internal nodes and compute the accelerations @@ -1412,18 +1522,25 @@ Line::getStateDeriv(InstanceStateVarView drdt) drdt.row(i - 1).head<3>() = rd[i]; drdt.row(i - 1).segment<3>(3) = M[i].inverse() * Fnet[i]; - if (Cl > 0) rdd_old[i] = drdt.row(i - 1).segment<3>(3); // saving the acceleration for VIV RMS calculation. End nodes are left at zero, VIV disabled for end nodes + if (Cl > 0) + rdd_old[i] = drdt.row(i - 1).segment<3>( + 3); // saving the acceleration for VIV RMS calculation. End + // nodes are left at zero, VIV disabled for end nodes } - if ((t >= t_old + dtm0) || (t == 0.0)) { // update back indexing one moordyn time step (regardless of time integration scheme) - t_old = t; // for updating back indexing if statements + if ((t >= t_old + dtm0) || + (t == 0.0)) { // update back indexing one moordyn time step (regardless + // of time integration scheme) + t_old = t; // for updating back indexing if statements } // if (t <0.5+dtm && t >0.5-dtm && not IC_gen) { // cout << "rdd_old at t = " << t << endl; - // for (int i = 0; i < 4; i++) cout << "I = " << i << " rdd_old = " << rdd_old[i][0] << ", " << rdd_old[i][1] << ", " << rdd_old[i][2] < WavesRef; * The integration time step (moordyn::MoorDyn.dtM0) should be smaller than * this natural period to avoid numerical instabilities */ -class DECLDIR Line final : public Instance, public NatFreqCFL +class DECLDIR Line final + : public Instance + , public NatFreqCFL { public: /** @brief Constructor @@ -140,18 +142,24 @@ class DECLDIR Line final : public Instance, public NatFreqCFL moordyn::real d; /// line density (kg/m^3) moordyn::real rho; - /// Elasticity model flag (1: constant EA, 2: viscoelastic model with constant dynamic stiffness, 3: mean load depenedent dynamic stiffness) + /// Elasticity model flag (1: constant EA, 2: viscoelastic model with + /// constant dynamic stiffness, 3: mean load depenedent dynamic stiffness) unsigned int ElasticMod; /// line normal/static elasticity modulus * crosssectional area [N] moordyn::real EA; - /// constant line dynamic stiffness modulus * area for viscoelastic stuff [N] + /// constant line dynamic stiffness modulus * area for viscoelastic stuff + /// [N] moordyn::real EA_D; - /// Alpha * MBL in load dependent dynamic stiffness equation Kd = Alpha * MBL + vbeta * Lm for viscoelastic model - moordyn::real alphaMBL; - /// beta in load dependent dynamic stiffness equation Kd = Alpha * MBL + vbeta * Lm for viscoelastic model + /// Alpha * MBL in load dependent dynamic stiffness equation Kd = Alpha * + /// MBL + vbeta * Lm for viscoelastic model + moordyn::real alphaMBL; + /// beta in load dependent dynamic stiffness equation Kd = Alpha * MBL + + /// vbeta * Lm for viscoelastic model moordyn::real vbeta; - /// stiffness of spring 2 in viscoelastic model (dynamic stiffness). This is the spring in series with the parallel spring-dashpot. - /// if ElasticMod = 2, EA_2 = EA_D. If ElasticMod = 3, EA_2 is load dependent dynamic stiffness. + /// stiffness of spring 2 in viscoelastic model (dynamic stiffness). This is + /// the spring in series with the parallel spring-dashpot. if ElasticMod = + /// 2, EA_2 = EA_D. If ElasticMod = 3, EA_2 is load dependent dynamic + /// stiffness. moordyn::real EA_2; /// segment stretch attributed to static stiffness portion [m] (deltaL_1) std::vector dl_1; @@ -168,7 +176,8 @@ class DECLDIR Line final : public Instance, public NatFreqCFL * \f$ C_{crit} = \frac{l}{n} \sqrt{\rho E} \f$ */ moordyn::real BA; - /// Line axial damping coefficient corresponding to the dynamic spring in the viscoelastic model + /// Line axial damping coefficient corresponding to the dynamic spring in + /// the viscoelastic model moordyn::real BA_D; /// normal added mass coefficient [-] /// with respect to line displacement @@ -217,7 +226,8 @@ class DECLDIR Line final : public Instance, public NatFreqCFL // Externally provided data /** true if pressure bending forces shall be considered, false otherwise - * @see https://cds.cern.ch/record/1224245/files/PH-EP-Tech-Note-2009-004.pdf?version=1 + * @see + * https://cds.cern.ch/record/1224245/files/PH-EP-Tech-Note-2009-004.pdf?version=1 */ bool isPb; /// internal pipe pressure at the nodes (Pa) @@ -283,7 +293,7 @@ class DECLDIR Line final : public Instance, public NatFreqCFL moordyn::real t; /// MoorDyn internal time step moordyn::real dtm0; - + // VIV stuff // /// VIV amplitude updated every zero crossing of crossflow velcoity // std::vector Amp; @@ -387,7 +397,7 @@ class DECLDIR Line final : public Instance, public NatFreqCFL EnvCondRef env_in, shared_ptr outfile, string channels, - real dtM0); + real dtM0); /** @brief Set the environmental data * @param waves_in Global Waves object @@ -402,7 +412,7 @@ class DECLDIR Line final : public Instance, public NatFreqCFL } /** @brief Initialize the line object - * @note Becasue Line.hpp is the only function that calls this, no state + * @note Becasue Line.hpp is the only function that calls this, no state * vectors need to be returned. This is different from the structure of * the other objects initialize functions. * @throws moordyn::output_file_error If an outfile has been provided, but @@ -412,7 +422,8 @@ class DECLDIR Line final : public Instance, public NatFreqCFL void initialize(); /** @brief Sets the initial line state - * @param state The line state for initializing (see Line::setState for the state structure0) + * @param state The line state for initializing (see Line::setState for the + * state structure0) * @note This calls Line::Initialize() */ inline void initialize(InstanceStateVarView state) @@ -420,32 +431,49 @@ class DECLDIR Line final : public Instance, public NatFreqCFL // ------ Initialize the line ------ initialize(); - // ------ Assign the intialized values to the state (bascially Line::setState but flipped) ------ - // Error check for number of columns (if VIV and Visco need row.size() = 8, if VIV xor Visco need row.size() = 7, if not VIV need row.size() = 6) - if ( (state.row(0).size() != 8 && Cl > 0 && ElasticMod > 1) || (state.row(0).size() != 7 && ((Cl > 0) ^ (ElasticMod > 1))) || (state.row(0).size() != 6 && Cl == 0 && ElasticMod == 1)) { + // ------ Assign the intialized values to the state (bascially + // Line::setState but flipped) ------ Error check for number of columns + // (if VIV and Visco need row.size() = 8, if VIV xor Visco need + // row.size() = 7, if not VIV need row.size() = 6) + if ((state.row(0).size() != 8 && Cl > 0 && ElasticMod > 1) || + (state.row(0).size() != 7 && ((Cl > 0) ^ (ElasticMod > 1))) || + (state.row(0).size() != 6 && Cl == 0 && ElasticMod == 1)) { LOGERR << "Invalid state.row size for Line " << number << endl; throw moordyn::mem_error("Invalid state.row size"); } - // Error check for number of rows (if visco need N rows, if normal need N-1 rows) - if ((state.rows() != N && ElasticMod > 1) || (state.rows() != N-1 && ElasticMod == 1)) { - LOGERR << "Invalid number of rows in state matrix for Line " << number << endl; + // Error check for number of rows (if visco need N rows, if normal need + // N-1 rows) + if ((state.rows() != N && ElasticMod > 1) || + (state.rows() != N - 1 && ElasticMod == 1)) { + LOGERR << "Invalid number of rows in state matrix for Line " + << number << endl; throw moordyn::mem_error("Invalid number of rows in state matrix"); } - - // If using the viscoelastic model, iterate N rows, else iterate N-1 rows. - for (unsigned int i = 0; i < (ElasticMod > 1 ? N : N-1); i++) { + + // If using the viscoelastic model, iterate N rows, else iterate N-1 + // rows. + for (unsigned int i = 0; i < (ElasticMod > 1 ? N : N - 1); i++) { // node number is i+1 // segment number is i - state.row(i).head<3>() = r[i+1]; - state.row(i).segment<3>(3) = rd[i+1]; - - if (ElasticMod > 1) state.row(i).tail<1>()[0] = dl_1[i]; // [0] needed becasue tail<1> returns a one element vector. Viscoelastic state is always the last element in the row + state.row(i).head<3>() = r[i + 1]; + state.row(i).segment<3>(3) = rd[i + 1]; + + if (ElasticMod > 1) + state.row(i).tail<1>()[0] = + dl_1[i]; // [0] needed becasue tail<1> returns a one element + // vector. Viscoelastic state is always the last + // element in the row if (Cl > 0) { - if (ElasticMod > 1) state.row(i).tail<2>()[0] = phi[i+1]; // if both VIV and viscoelastic second to last element in the row - else state.row(i).tail<1>()[0] = phi[i+1]; // else last element in the row - } + if (ElasticMod > 1) + state.row(i).tail<2>()[0] = + phi[i + 1]; // if both VIV and viscoelastic second to + // last element in the row + else + state.row(i).tail<1>()[0] = + phi[i + 1]; // else last element in the row + } } } /** @@ -531,12 +559,14 @@ class DECLDIR Line final : public Instance, public NatFreqCFL * @param EA The constant axial stiffness EA value (N) * @see ::IsConstantEA() */ - inline void setConstantEA(moordyn::real EA_in) { + inline void setConstantEA(moordyn::real EA_in) + { if (ElasticMod > 1) { LOGERR << "Cannot set constant EA for viscoelastic model" << endl; - throw moordyn::invalid_value_error("Cannot set constant EA for viscoelastic model"); + throw moordyn::invalid_value_error( + "Cannot set constant EA for viscoelastic model"); } else { - EA = EA_in; + EA = EA_in; } } @@ -591,7 +621,7 @@ class DECLDIR Line final : public Instance, public NatFreqCFL /** @brief Get the net force on a node * * The net force is the total force acting over a line node. - * + * * To get the different components of the force use ::getNodeTen() , * ::getNodeBendStiff() , ::getNodeWeight() , ::getNodeDrag() , * ::getNodeFroudeKrilov() and ::getNodeSeaBedForce() @@ -615,10 +645,10 @@ class DECLDIR Line final : public Instance, public NatFreqCFL }; /** @brief Get the tension on a node, including the internal line damping - * + * * If it is an inner node, the average of the * tension at the surrounding segments is provided. If the node is a - * line-end, the associated ending segment tension is provided. This + * line-end, the associated ending segment tension is provided. This * does not account for the direction of pull. In the calculation of * Fnet for the node, the direction of pull is accounted for. * @param i The line node index @@ -637,12 +667,12 @@ class DECLDIR Line final : public Instance, public NatFreqCFL return T[0] + Td[0]; else if (i == N) // top node, return ten and damping of top section return T[N - 1] + Td[N - 1]; - // internal node, take average of tension in adjacent segments. + // internal node, take average of tension in adjacent segments. return (0.5 * (T[i] + T[i - 1] + Td[i] + Td[i - 1])); }; /** @brief Get the tension on a node, including the internal line damping - * + * * If it is an inner node, the average of the * tension at the surrounding segments is provided. If the node is a * line-end, the associated ending segment tension is provided @@ -920,7 +950,8 @@ class DECLDIR Line final : public Instance, public NatFreqCFL inline void setTime(real time) { t = time; } /** @brief Set the line state - * @param r The line state matrix. See Line::setState in Line.cpp for structure + * @param r The line state matrix. See Line::setState in Line.cpp for + * structure * @note End node kinematics are not handled here * @see moordyn::Line::setEndState * @{ @@ -965,7 +996,7 @@ class DECLDIR Line final : public Instance, public NatFreqCFL vec getEndSegmentMoment(EndPoints end_point, EndPoints rod_end_point) const; /** @brief Calculate forces and get the derivative of the line's states - * @param drdt Output state derivatives + * @param drdt Output state derivatives * @throws nan_error If nan values are detected in any node position */ void getStateDeriv(InstanceStateVarView drdt); @@ -981,26 +1012,35 @@ class DECLDIR Line final : public Instance, public NatFreqCFL * @note See comments in Line::setState to see the line state structure * @warning This function shall be called after ::setup() */ - inline const size_t stateN() const { - if (ElasticMod > 1) return getN(); // N rows for viscoelastic case - else return getN() - 1; // N-1 rows for other cases - } + inline const size_t stateN() const + { + if (ElasticMod > 1) + return getN(); // N rows for viscoelastic case + else + return getN() - 1; // N-1 rows for other cases + } /** @brief Get the dimension of the state variable * @return 3 components for positions and 3 components for velocities, i.e. - * 6 components. An additional component is returned if the VIV model or - * viscoelastic model is activated. + * 6 components. An additional component is returned if the VIV model or + * viscoelastic model is activated. * @note If VIV and vsicoelastic, return 8 * if VIV xor viscoelastic, return 7 * if normal, return 6 * See comments in Line::setState to see the line state structure * @warning This function shall be called after ::setup() */ - inline const size_t stateDims() const { - if (Cl > 0 && ElasticMod > 1) return 8; // 3 for position, 3 for velocity, 1 for VIV phase, 1 for viscoelasticity - else if ((Cl > 0) ^ (ElasticMod > 1)) return 7; // 3 for position, 3 for velocity, 1 for VIV phase or viscoelasticity - else return 6; - } + inline const size_t stateDims() const + { + if (Cl > 0 && ElasticMod > 1) + return 8; // 3 for position, 3 for velocity, 1 for VIV phase, 1 for + // viscoelasticity + else if ((Cl > 0) ^ (ElasticMod > 1)) + return 7; // 3 for position, 3 for velocity, 1 for VIV phase or + // viscoelasticity + else + return 6; + } /** @brief Produce the packed data to be saved * diff --git a/source/Misc.cpp b/source/Misc.cpp index c09826da..11a323d8 100644 --- a/source/Misc.cpp +++ b/source/Misc.cpp @@ -78,10 +78,11 @@ split(const string& str, const char sep) string token; vector words; while (std::getline(spliter, token, sep)) { - if (token.find("#") == string::npos){ + if (token.find("#") == string::npos) { if (token.size()) // # is a comment in input files words.push_back(token); - } else break; + } else + break; } return words; } @@ -369,8 +370,8 @@ GetCurvature(moordyn::real length, const vec& q1, const vec& q2) } // ::moordyn -moordyn::quaternion operator*(const moordyn::real& k, - const moordyn::quaternion& v) +moordyn::quaternion +operator*(const moordyn::real& k, const moordyn::quaternion& v) { return moordyn::quaternion(k * v.coeffs()); } diff --git a/source/Misc.hpp b/source/Misc.hpp index 30cb2f8b..b8178363 100644 --- a/source/Misc.hpp +++ b/source/Misc.hpp @@ -734,8 +734,11 @@ inline vector split(const string& s) { vector sout = split(s, ' '); - if (sout.size() == 1) return split(sout[0], ' '); // if space didnt split it, try again with tab - else return sout; + if (sout.size() == 1) + return split(sout[0], + ' '); // if space didnt split it, try again with tab + else + return sout; } /** @@ -1070,8 +1073,8 @@ typedef struct _FailProps } // ::moordyn -moordyn::quaternion operator*(const moordyn::real& k, - const moordyn::quaternion& v); +moordyn::quaternion +operator*(const moordyn::real& k, const moordyn::quaternion& v); const int nCoef = 30; // maximum number of entries to allow in nonlinear // coefficient lookup tables @@ -1136,16 +1139,16 @@ typedef struct _LineProps // (matching Line Dictionary inputs) double Cat; double Cdn; double Cdt; - double Cl; // VIV lift coefficient. If 0, VIV turned off. - double dF; // +- range around cF for VIV synchronization model - double cF; // center non-dim frequency for VIV synch model + double Cl; // VIV lift coefficient. If 0, VIV turned off. + double dF; // +- range around cF for VIV synchronization model + double cF; // center non-dim frequency for VIV synch model int nEApoints; // number of values in stress-strain lookup table (0 means // using constant E) double stiffXs[nCoef]; // x array for stress-strain lookup table (up to nCoef) double stiffYs[nCoef]; // y array for stress-strain lookup table - int nBApoints; // number of values in stress-strainrate lookup table (0 means - // using constant c) + int nBApoints; // number of values in stress-strainrate lookup table (0 + // means using constant c) double dampXs[nCoef]; // x array for stress-strainrate lookup table (up to // nCoef) double dampYs[nCoef]; // y array for stress-strainrate lookup table diff --git a/source/MoorDyn.cpp b/source/MoorDyn.cpp index 1fd6d07d..5a43b045 100644 --- a/source/MoorDyn.cpp +++ b/source/MoorDyn.cpp @@ -287,5 +287,8 @@ AllOutput(double t, double dt) { if (!md_singleton) return; - MoorDyn_Log(md_singleton, MOORDYN_MSG_LEVEL, "In version 2, AllOutput is automatically called by MoorDynInit and MoorDynStep"); + MoorDyn_Log(md_singleton, + MOORDYN_MSG_LEVEL, + "In version 2, AllOutput is automatically called by " + "MoorDynInit and MoorDynStep"); } \ No newline at end of file diff --git a/source/MoorDyn.h b/source/MoorDyn.h index a490e356..7742ff5b 100644 --- a/source/MoorDyn.h +++ b/source/MoorDyn.h @@ -48,105 +48,113 @@ extern "C" { #endif - /** @defgroup old_c_api The old API - * - * The old API is based on a singleton, i.e. just one MoorDyn instance can - * be hold per process - * @{ - */ - - /** @brief initializes MoorDyn - * - * Including reading the input file, creating the mooring system data - * structures, and calculating the initial conditions - * - * @param x Position vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @param xd Velocity vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @param infilename The input file, if either NULL or "", then - * "Mooring/lines.txt" will be considered - * @return 0 If the mooring system is correctly initialized, an error code - * otherwise (see @ref moordyn_errors) - * @warning Just one instance of MoorDyn per process is allowed. Thus, if - * several mooring systems shall be handled, please spawn additional - * processes - */ - int DECLDIR MoorDynInit(const double x[], - const double xd[], - const char* infilename); - - /** @brief Runs a time step of the MoorDyn system - * @param x Position vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @param xd Velocity vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @param f Output forces (6 components per coupled body or cantilevered rod - * and 3 components per pinned rod or coupled point) - * @param t Simulation time - * @param dt Time step - * @return 0 if the mooring system has correctly evolved, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDynInit - */ - int DECLDIR MoorDynStep(const double x[], - const double xd[], - double f[], - double* t, - double* dt); - - /** @brief Releases MoorDyn allocated resources - * @return 0 If the mooring system is correctly destroyed, an error code - * otherwise (see @ref moordyn_errors) - * @note Call this function even if the initialization failed - */ - int DECLDIR MoorDynClose(void); - - /** @brief Initializes the external Wave kinetics - * - * This is useless unless WaveKin option is set in the input file. If that - * is the case, remember calling this function after MoorDyn_Init() - * @return The number of points where the wave kinematics shall be provided. - * 0 if errors are detected - */ - int DECLDIR externalWaveKinInit(); - - /** @brief Get the points where the waves kinematics shall be provided - * @param r_out The output coordinates (3 components per point) - * @see externalWaveKinInit() - */ - void DECLDIR getWaveKinCoordinates(double r_out[]); - - /** @brief Set the kinematics of the waves - * - * Use this function if WaveKin option is set in the input file - * @param U_in The velocities at the points (3 components per point) - * @param Ud_in The accelerations at the points (3 components per point) - * @param t_in Simulation time - * @see externalWaveKinInit() - * @see getWaveKinCoordinates() - */ - void DECLDIR setWaveKin(const double U_in[], - const double Ud_in[], - double t_in); - - double DECLDIR GetFairTen(int); - - int DECLDIR GetFASTtens(int* numLines, - float FairHTen[], - float FairVTen[], - float AnchHTen[], - float AnchVTen[]); - - int DECLDIR GetPointPos(int l, double pos[3]); - int DECLDIR GetPointForce(int l, double force[3]); - int DECLDIR GetNodePos(int LineNum, int NodeNum, double pos[3]); - - void DECLDIR AllOutput(double, double); - - /** - * @} - */ +/** @defgroup old_c_api The old API + * + * The old API is based on a singleton, i.e. just one MoorDyn instance can + * be hold per process + * @{ + */ + +/** @brief initializes MoorDyn + * + * Including reading the input file, creating the mooring system data + * structures, and calculating the initial conditions + * + * @param x Position vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @param xd Velocity vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @param infilename The input file, if either NULL or "", then + * "Mooring/lines.txt" will be considered + * @return 0 If the mooring system is correctly initialized, an error code + * otherwise (see @ref moordyn_errors) + * @warning Just one instance of MoorDyn per process is allowed. Thus, if + * several mooring systems shall be handled, please spawn additional + * processes + */ +int DECLDIR +MoorDynInit(const double x[], const double xd[], const char* infilename); + +/** @brief Runs a time step of the MoorDyn system + * @param x Position vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @param xd Velocity vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @param f Output forces (6 components per coupled body or cantilevered rod + * and 3 components per pinned rod or coupled point) + * @param t Simulation time + * @param dt Time step + * @return 0 if the mooring system has correctly evolved, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDynInit + */ +int DECLDIR +MoorDynStep(const double x[], + const double xd[], + double f[], + double* t, + double* dt); + +/** @brief Releases MoorDyn allocated resources + * @return 0 If the mooring system is correctly destroyed, an error code + * otherwise (see @ref moordyn_errors) + * @note Call this function even if the initialization failed + */ +int DECLDIR +MoorDynClose(void); + +/** @brief Initializes the external Wave kinetics + * + * This is useless unless WaveKin option is set in the input file. If that + * is the case, remember calling this function after MoorDyn_Init() + * @return The number of points where the wave kinematics shall be provided. + * 0 if errors are detected + */ +int DECLDIR +externalWaveKinInit(); + +/** @brief Get the points where the waves kinematics shall be provided + * @param r_out The output coordinates (3 components per point) + * @see externalWaveKinInit() + */ +void DECLDIR +getWaveKinCoordinates(double r_out[]); + +/** @brief Set the kinematics of the waves + * + * Use this function if WaveKin option is set in the input file + * @param U_in The velocities at the points (3 components per point) + * @param Ud_in The accelerations at the points (3 components per point) + * @param t_in Simulation time + * @see externalWaveKinInit() + * @see getWaveKinCoordinates() + */ +void DECLDIR +setWaveKin(const double U_in[], const double Ud_in[], double t_in); + +double DECLDIR +GetFairTen(int); + +int DECLDIR +GetFASTtens(int* numLines, + float FairHTen[], + float FairVTen[], + float AnchHTen[], + float AnchVTen[]); + +int DECLDIR +GetPointPos(int l, double pos[3]); +int DECLDIR +GetPointForce(int l, double force[3]); +int DECLDIR +GetNodePos(int LineNum, int NodeNum, double pos[3]); + +void DECLDIR +AllOutput(double, double); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/source/MoorDyn2.cpp b/source/MoorDyn2.cpp index 09ab594a..38430a6a 100644 --- a/source/MoorDyn2.cpp +++ b/source/MoorDyn2.cpp @@ -112,9 +112,9 @@ moordyn::MoorDyn::MoorDyn(const char* infilename, int log_level) _basepath = _filepath.substr(0, lastSlash + 1); } - LOGMSG << "\n Running MoorDyn (v" - << MOORDYN_MAJOR_VERSION << "." << MOORDYN_MINOR_VERSION << "." - << MOORDYN_PATCH_VERSION << ")" << endl + LOGMSG << "\n Running MoorDyn (v" << MOORDYN_MAJOR_VERSION << "." + << MOORDYN_MINOR_VERSION << "." << MOORDYN_PATCH_VERSION << ")" + << endl << " MoorDyn v2 has significant ongoing input file changes " "from v1." << endl @@ -190,9 +190,10 @@ moordyn::MoorDyn::icLegacy() { moordyn::error_id err = MOORDYN_SUCCESS; string err_msg; - // dtIC set to fraction of input so convergence is over dtIC (as described in docs) + // dtIC set to fraction of input so convergence is over dtIC (as described + // in docs) const unsigned int convergence_iters = 9; // 10 iterations, indexed 0-9 - ICdt = ICdt / (convergence_iters+1); + ICdt = ICdt / (convergence_iters + 1); _t_integrator->Init(); if (ICfile != "") { @@ -232,7 +233,7 @@ moordyn::MoorDyn::icLegacy() real best_score_t = 0.0; unsigned int best_score_line = 0; - ICdt = ICdt / (convergence_iters+1); + ICdt = ICdt / (convergence_iters + 1); while ((ICTmax - t) > (std::numeric_limits::min)()) { // Integrate one ICD timestep (ICdt) real t_target = ICdt; @@ -263,7 +264,7 @@ moordyn::MoorDyn::icLegacy() // go through points to get fairlead forces for (unsigned int lf = 0; lf < LineList.size(); lf++) FairTens[lf] = - LineList[lf]->getNodeTen(LineList[lf]->getN()).norm(); + LineList[lf]->getNodeTen(LineList[lf]->getN()).norm(); // check for convergence (compare current tension at each fairlead with // previous convergence_iters-1 values) @@ -275,7 +276,7 @@ moordyn::MoorDyn::icLegacy() for (unsigned int lf = 0; lf < LineList.size(); lf++) { for (unsigned int pt = 0; pt < convergence_iters; pt++) { const real error = - abs(FairTens[lf] / FairTensLast[lf][pt] - 1.0); + abs(FairTens[lf] / FairTensLast[lf][pt] - 1.0); if (error > max_error) { max_error = error; max_error_line = LineList[lf]->number; @@ -290,8 +291,8 @@ moordyn::MoorDyn::icLegacy() if (max_error > ICthresh) { converged = false; LOGDBG << "Dynamic relaxation t = " << t << "s (time step " - << iic << "), error = " << 100.0 * max_error - << "% on line " << max_error_line << " \r"; + << iic << "), error = " << 100.0 * max_error + << "% on line " << max_error_line << " \r"; } if (converged) @@ -307,14 +308,13 @@ moordyn::MoorDyn::icLegacy() LOGWRN << "Fairlead tensions did not converge" << endl; } LOGMSG << "Remaining error after " << t << " s = " << 100.0 * max_error - << "% on line " << max_error_line << endl; + << "% on line " << max_error_line << endl; if (!converged) { LOGMSG << "Best score at " << best_score_t - << " s = " << 100.0 * best_score << "% on line " - << best_score_line << endl; + << " s = " << 100.0 * best_score << "% on line " + << best_score_line << endl; } - // We are setting the timer again later, but better doing it here as well, // so no regressions might happens on the subinstances setTime() callings _t_integrator->SetTime(0.0); @@ -352,7 +352,9 @@ moordyn::MoorDyn::icStationary() time::StationaryScheme t_integrator(_log, waves); t_integrator.SetGround(GroundBody); - for (auto obj : BodyList) // TODO: make these lists only iterate over the free lines. Check other places where this is called + for (auto obj : + BodyList) // TODO: make these lists only iterate over the free lines. + // Check other places where this is called t_integrator.AddBody(obj); for (auto obj : RodList) t_integrator.AddRod(obj); @@ -407,15 +409,15 @@ moordyn::MoorDyn::icStationary() error_prev = error; LOGDBG << "Stationary solution t = " << t << "s, " - << "error avg = " << error / n_states << " m/s2, " - << "error change = " << 100.0 * error_deriv << "% \r"; + << "error avg = " << error / n_states << " m/s2, " + << "error change = " << 100.0 * error_deriv << "% \r"; } _t_integrator->SetState(t_integrator.GetState()); - LOGMSG << "Remaining error after " << t << " s = " - << error / n_states << " m/s2" << endl; + LOGMSG << "Remaining error after " << t << " s = " << error / n_states + << " m/s2" << endl; LOGMSG << "Best score at " << best_score_t - << " s = " << best_score / n_states << " m/s2" << endl; + << " s = " << best_score / n_states << " m/s2" << endl; return MOORDYN_SUCCESS; } @@ -440,7 +442,7 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) GroundBody->initializeUnfreeBody(); // initialize fixed bodies and attached objects - for (auto l : FixedBodyIs){ + for (auto l : FixedBodyIs) { BodyList[l]->initializeUnfreeBody(BodyList[l]->body_r6, vec6::Zero()); } @@ -448,12 +450,12 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) int ix = 0; for (auto l : CpldBodyIs) { - LOGMSG << "Initializing coupled Body " << l+1 << " at " << x[ix] << ", " - << x[ix + 1] << ", " << x[ix + 2] << "..." << endl; + LOGMSG << "Initializing coupled Body " << l + 1 << " at " << x[ix] + << ", " << x[ix + 1] << ", " << x[ix + 2] << "..." << endl; // BUG: These conversions will not be needed in the future vec6 r, rd; - if (BodyList[l]->type == Body::COUPLED){ + if (BodyList[l]->type == Body::COUPLED) { moordyn::array2vec6(x + ix, r); moordyn::array2vec6(xd + ix, rd); ix += 6; @@ -470,8 +472,8 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) } for (auto l : CpldRodIs) { - LOGMSG << "Initializing coupled Rod " << l+1 << " at " << x[ix] << ", " - << x[ix + 1] << ", " << x[ix + 2] << "..." << endl; + LOGMSG << "Initializing coupled Rod " << l + 1 << " at " << x[ix] + << ", " << x[ix + 1] << ", " << x[ix + 2] << "..." << endl; vec6 r, rd, rdd; if (RodList[l]->type == Rod::COUPLED) { // for cantilevered rods 6 entries will be taken @@ -494,8 +496,8 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) } for (auto l : CpldPointIs) { - LOGMSG << "Initializing coupled Point " << l+1 << " at " << x[ix] << ", " - << x[ix + 1] << ", " << x[ix + 2] << endl; + LOGMSG << "Initializing coupled Point " << l + 1 << " at " << x[ix] + << ", " << x[ix + 1] << ", " << x[ix + 2] << endl; vec r, rd; moordyn::array2vec(x + ix, r); moordyn::array2vec(xd + ix, rd); @@ -517,7 +519,8 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) } if (dtM0 < (0.9 * (std::numeric_limits::max)())) - cfl = (std::numeric_limits::max)(); // Is 90% of max sufficient tolerance for this check? + cfl = (std::numeric_limits::max)(); // Is 90% of max sufficient + // tolerance for this check? // Compute the timestep for (auto obj : LineList) @@ -546,7 +549,7 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) // ------------------ do IC gen -------------------- if (!skip_ic) { - for (unsigned int l = 0; l < LineList.size(); l++){ + for (unsigned int l = 0; l < LineList.size(); l++) { LineList[l]->IC_gen = true; // turn on IC_gen flag } @@ -557,8 +560,8 @@ moordyn::MoorDyn::Init(const double* x, const double* xd, bool skip_ic) err = icStationary(); if (err != MOORDYN_SUCCESS) return err; - - for (unsigned int l = 0; l < LineList.size(); l++){ + + for (unsigned int l = 0; l < LineList.size(); l++) { LineList[l]->IC_gen = false; // turn off IC_gen flag } @@ -651,7 +654,8 @@ moordyn::MoorDyn::Step(const double* x, LOGDBG << "t = " << t << "s \r"; std::cout << std::defaultfloat << setprecision(default_precision); - if (!disableOutTime) cout << "\rt = " << t << " " << flush; + if (!disableOutTime) + cout << "\rt = " << t << " " << flush; } if (dt <= 0) { @@ -676,10 +680,10 @@ moordyn::MoorDyn::Step(const double* x, // BUG: These conversions will not be needed in the future vec6 r, rd, rdd; const vec6 rd_b = BodyList[l]->getUnfreeVel(); - if (BodyList[l]->type == Body::COUPLED){ + if (BodyList[l]->type == Body::COUPLED) { moordyn::array2vec6(x + ix, r); moordyn::array2vec6(xd + ix, rd); - // determine acceleration + // determine acceleration rdd = (rd - rd_b) / dt; ix += 6; } else { @@ -689,8 +693,8 @@ moordyn::MoorDyn::Step(const double* x, r(Eigen::seqN(0, 3)) = r3; moordyn::array2vec(xd + ix, rd3); rd(Eigen::seqN(0, 3)) = rd3; - // determine acceleration - rdd(Eigen::seqN(0, 3)) = (rd3 - rd_b.head<3>()) / dt; + // determine acceleration + rdd(Eigen::seqN(0, 3)) = (rd3 - rd_b.head<3>()) / dt; ix += 3; } // acceleration required for inertial terms @@ -703,8 +707,8 @@ moordyn::MoorDyn::Step(const double* x, // for cantilevered rods 6 entries will be taken moordyn::array2vec6(x + ix, r); moordyn::array2vec6(xd + ix, rd); - // determine acceleration - rdd = (rd - rd_r) / dt; + // determine acceleration + rdd = (rd - rd_r) / dt; ix += 6; } else { // for pinned rods 3 entries will be taken @@ -713,8 +717,8 @@ moordyn::MoorDyn::Step(const double* x, r(Eigen::seqN(0, 3)) = r3; moordyn::array2vec(xd + ix, rd3); rd(Eigen::seqN(0, 3)) = rd3; - // determine acceleration - rdd(Eigen::seqN(0, 3)) = (rd3 - rd_r.head<3>()) / dt; + // determine acceleration + rdd(Eigen::seqN(0, 3)) = (rd3 - rd_r.head<3>()) / dt; ix += 3; } // acceleration required for inertial terms @@ -895,7 +899,8 @@ moordyn::MoorDyn::ReadInFile() if ((i = findStartOfSection(in_txt, { "OPTIONS" })) != -1) { LOGDBG << " Reading options:" << endl; // Parse options until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { vector entries = moordyn::str::split(in_txt[i], ' '); if (entries.size() < 2) { i++; @@ -918,7 +923,8 @@ moordyn::MoorDyn::ReadInFile() if ((i = findStartOfSection(in_txt, { "OPTIONS" })) != -1) { LOGDBG << " Reading options:" << endl; // Parse options until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { vector entries = moordyn::str::split(in_txt[i], ' '); if (entries.size() < 2) { i++; @@ -958,7 +964,8 @@ moordyn::MoorDyn::ReadInFile() LOGDBG << " Reading line types:" << endl; // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { LineProps* obj = readLineProps(in_txt[i], i); if (obj) LinePropList.push_back(obj); @@ -975,7 +982,8 @@ moordyn::MoorDyn::ReadInFile() LOGDBG << " Reading rod types:" << endl; // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { RodProps* obj = readRodProps(in_txt[i], i); if (obj) @@ -993,7 +1001,8 @@ moordyn::MoorDyn::ReadInFile() LOGDBG << " Reading body list:" << endl; // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { Body* obj = readBody(in_txt[i], i); if (obj) { @@ -1015,11 +1024,12 @@ moordyn::MoorDyn::ReadInFile() LOGDBG << " Reading point list:" << endl; // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { vector entries = moordyn::str::split(in_txt[i], ' '); if (entries.size() < 9) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "9 fields are required, but just " << entries.size() << " are provided" << endl; @@ -1062,8 +1072,8 @@ moordyn::MoorDyn::ReadInFile() } else if (let1 == "BODY") { type = Point::FIXED; if (num1.empty()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "no number provided for Rod " << number << " Body attachment" << endl; @@ -1071,8 +1081,8 @@ moordyn::MoorDyn::ReadInFile() } unsigned int bodyID = atoi(num1.c_str()); if (!bodyID || (bodyID > BodyList.size())) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "There is not " << bodyID << " bodies" << endl; return MOORDYN_INVALID_INPUT; @@ -1092,8 +1102,8 @@ moordyn::MoorDyn::ReadInFile() type = Point::FREE; FreePointIs.push_back(ui_size(PointList)); } else { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "Unrecognized point type '" << let1 << "'" << endl; return MOORDYN_INVALID_INPUT; @@ -1105,7 +1115,10 @@ moordyn::MoorDyn::ReadInFile() // Note - this is not in MD-F if (r0[2] < -env->WtrDpth) { env->WtrDpth = -r0[2]; - LOGWRN << "\t Water depth set to point " << PointList.size()+1 << " z position because point was specified below the seabed" << endl; + LOGWRN << "\t Water depth set to point " << PointList.size() + 1 + << " z position because point was specified below the " + "seabed" + << endl; } LOGDBG << "\t'" << number << "'" @@ -1136,7 +1149,8 @@ moordyn::MoorDyn::ReadInFile() LOGDBG << " Reading rod list:" << endl; // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { Rod* obj = readRod(in_txt[i], i); RodList.push_back(obj); @@ -1154,11 +1168,12 @@ moordyn::MoorDyn::ReadInFile() } // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { vector entries = moordyn::str::split(in_txt[i], ' '); if (entries.size() < 7) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "7 fields are required, but only " << entries.size() << " are provided" << endl; @@ -1177,8 +1192,8 @@ moordyn::MoorDyn::ReadInFile() TypeNum = J; } if (TypeNum == -1) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "Unrecognized line type " << type << endl; return MOORDYN_INVALID_INPUT; @@ -1212,7 +1227,7 @@ moordyn::MoorDyn::ReadInFile() env, outfiles.back(), outchannels, - dtM0); + dtM0); LineList.push_back(obj); for (unsigned int I = 0; I < 2; I++) { @@ -1223,8 +1238,8 @@ moordyn::MoorDyn::ReadInFile() entries[2 + I], let1, num1, let2, num2, let3); if (num1.empty()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "No number provided for the 1st point index" << endl; @@ -1234,8 +1249,8 @@ moordyn::MoorDyn::ReadInFile() if (str::isOneOf(let1, { "R", "ROD" })) { if (!id || id > RodList.size()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " + << i + 1 << ":" << endl << "'" << in_txt[i] << "'" << endl << "There are not " << id << " rods" << endl; return MOORDYN_INVALID_INPUT; @@ -1245,8 +1260,8 @@ moordyn::MoorDyn::ReadInFile() else if (let2 == "B") RodList[id - 1]->addLine(obj, end_point, ENDPOINT_B); else { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " + << i + 1 << ":" << endl << "'" << in_txt[i] << "'" << endl << "Rod end (A or B) must be specified" << endl; return MOORDYN_INVALID_INPUT; @@ -1254,16 +1269,16 @@ moordyn::MoorDyn::ReadInFile() } else if (let1.empty() || str::isOneOf(let1, { "C", "CON", "P", "POINT" })) { if (!id || id > PointList.size()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " + << i + 1 << ":" << endl << "'" << in_txt[i] << "'" << endl << "There are not " << id << " points" << endl; return MOORDYN_INVALID_INPUT; } PointList[id - 1]->addLine(obj, end_point); } else { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "Unrecognized point type " << let1 << endl; return MOORDYN_INVALID_INPUT; @@ -1278,11 +1293,12 @@ moordyn::MoorDyn::ReadInFile() if ((i = findStartOfSection(in_txt, { "FAILURE" })) != -1) { LOGDBG << " Reading failure conditions:" << endl; // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { vector entries = moordyn::str::split(in_txt[i], ' '); if (entries.size() < 4) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "4 fields are required, but just " << entries.size() << " are provided" << endl; @@ -1300,8 +1316,8 @@ moordyn::MoorDyn::ReadInFile() str::decomposeString(entries[1], let1, num1, let2, num2, let3); if (num1.empty()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "No number provided for Node Failure" << endl; return MOORDYN_INVALID_INPUT; @@ -1310,8 +1326,8 @@ moordyn::MoorDyn::ReadInFile() const unsigned int id = atoi(num1.c_str()); if (str::isOneOf(let1, { "R", "ROD" })) { if (!id || id > RodList.size()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "There are not " << id << " rods" << endl; return MOORDYN_INVALID_INPUT; @@ -1322,8 +1338,8 @@ moordyn::MoorDyn::ReadInFile() else if (let2 == "B") obj->rod_end_point = ENDPOINT_B; else { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "Failure end (A or B) must be specified" << endl; return MOORDYN_INVALID_INPUT; @@ -1331,8 +1347,8 @@ moordyn::MoorDyn::ReadInFile() } else if (let1.empty() || str::isOneOf(let1, { "C", "CON", "P", "POINT" })) { if (!id || id > PointList.size()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "There are not " << id << " points" << endl; return MOORDYN_INVALID_INPUT; @@ -1340,8 +1356,8 @@ moordyn::MoorDyn::ReadInFile() obj->point = PointList[id - 1]; ; } else { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "Unrecognized point type " << let1 << endl; return MOORDYN_INVALID_INPUT; @@ -1353,8 +1369,8 @@ moordyn::MoorDyn::ReadInFile() for (unsigned int il = 0; il < lineNums.size(); il++) { const unsigned int line_id = atoi(lineNums[il].c_str()); if (!line_id || line_id > LineList.size()) { - LOGERR << "Error in " << _filepath << " at line " << i +1 << ":" - << endl + LOGERR << "Error in " << _filepath << " at line " << i + 1 + << ":" << endl << "'" << in_txt[i] << "'" << endl << "There are not " << line_id << " lines" << endl; return MOORDYN_INVALID_INPUT; @@ -1378,7 +1394,8 @@ moordyn::MoorDyn::ReadInFile() if ((i = findStartOfSection(in_txt, { "OUTPUT" })) != -1) { LOGDBG << " Reading output options:" << endl; // parse until the next header or the end of the file - while ((in_txt[i].find("---") == string::npos) && (i < (int)in_txt.size())) { + while ((in_txt[i].find("---") == string::npos) && + (i < (int)in_txt.size())) { vector entries = moordyn::str::split(in_txt[i], ' '); for (unsigned int j = 0; j < entries.size(); @@ -1761,56 +1778,68 @@ moordyn::MoorDyn::readLineProps(string inputText, int lineNum) obj->Cdt = atof(entries[8].c_str()); obj->Cat = atof(entries[9].c_str()); if (entries.size() == 10) { - obj->Cl = 0.0; // If no lift coefficient, disable VIV. For backwards compatability. + obj->Cl = 0.0; // If no lift coefficient, disable VIV. For backwards + // compatability. obj->dF = 0.0; obj->cF = 0.0; } else if (entries.size() == 11) { obj->Cl = atof(entries[10].c_str()); - obj->dF = 0.08; // set to default Thorsen synchronization range if not provided - obj->cF = 0.18; // set to default Thorsen synchronization centering if not provided + obj->dF = 0.08; // set to default Thorsen synchronization range if not + // provided + obj->cF = 0.18; // set to default Thorsen synchronization centering if + // not provided } else if (entries.size() == 13) { obj->Cl = atof(entries[10].c_str()); obj->dF = atof(entries[11].c_str()); obj->cF = atof(entries[12].c_str()); - } else return nullptr; + } else + return nullptr; moordyn::error_id err; - vector EA_stuff = moordyn::str::split(entries[3],'|'); + vector EA_stuff = moordyn::str::split(entries[3], '|'); const int EA_N = EA_stuff.size(); if (EA_N == 1) { obj->ElasticMod = 1; // normal case - } - else if (EA_N==2){ + } else if (EA_N == 2) { obj->ElasticMod = 2; // viscoelastic model, constant dynamic stiffness obj->EA_D = atof(EA_stuff[1].c_str()); - } else if (EA_N==3){ - obj->ElasticMod = 3; // viscoelastic model load dependent dynamic stiffness + } else if (EA_N == 3) { + obj->ElasticMod = + 3; // viscoelastic model load dependent dynamic stiffness obj->alphaMBL = atof(EA_stuff[1].c_str()); obj->vbeta = atof(EA_stuff[2].c_str()); } else { - LOGERR << "A line type EA entry can have at most 3 (bar-separated) values." << endl; + LOGERR + << "A line type EA entry can have at most 3 (bar-separated) values." + << endl; return nullptr; } err = read_curve(EA_stuff[0].c_str(), - &(obj->EA), - &(obj->nEApoints), - obj->stiffXs, - obj->stiffYs); + &(obj->EA), + &(obj->nEApoints), + obj->stiffXs, + obj->stiffYs); if (err) return nullptr; - vector BA_stuff = moordyn::str::split(entries[4],'|'); + vector BA_stuff = moordyn::str::split(entries[4], '|'); unsigned int BA_N = BA_stuff.size(); if (BA_N > EA_N) { - LOGERR << "A line type BA entry cannot have more (bar-separated) values than its EA entry." << endl; + LOGERR << "A line type BA entry cannot have more (bar-separated) " + "values than its EA entry." + << endl; return nullptr; - } else if (BA_N == 2){ + } else if (BA_N == 2) { obj->BA_D = atof(BA_stuff[1].c_str()); - } else if (obj->ElasticMod>1){ - LOGMSG << "Message: viscoelastic model being used with zero damping on the dynamic stiffness." << endl; + } else if (obj->ElasticMod > 1) { + LOGMSG << "Message: viscoelastic model being used with zero damping on " + "the dynamic stiffness." + << endl; obj->BA_D = 0.0; } else if (BA_N > 2) { - LOGERR << "A line type BA entry can have at most 2 (bar-separated) values." << endl; + LOGERR + << "A line type BA entry can have at most 2 (bar-separated) values." + << endl; return nullptr; } err = read_curve(BA_stuff[0].c_str(), @@ -1836,7 +1865,7 @@ moordyn::MoorDyn::readLineProps(string inputText, int lineNum) << "\t\tCan : " << obj->Can << endl << "\t\tCdt : " << obj->Cdt << endl << "\t\tCat : " << obj->Cat << endl - << "\t\tCl : " << obj->Cat << endl; + << "\t\tCl : " << obj->Cat << endl; return obj; } @@ -1856,8 +1885,10 @@ moordyn::MoorDyn::readRodProps(string inputText, int lineNum) obj->Can = atof(entries[4].c_str()); obj->CdEnd = atof(entries[5].c_str()); obj->CaEnd = atof(entries[6].c_str()); - obj->Cdt = 0.0; // No end effects from internal segments. CdEnd captures end effects. - obj->Cat = 0.0; // No end effects from internal segments. CaEnd captures end effects. + obj->Cdt = 0.0; // No end effects from internal segments. CdEnd captures end + // effects. + obj->Cat = 0.0; // No end effects from internal segments. CaEnd captures end + // effects. LOGDBG << "\t'" << obj->type << "'" << " - with id " << RodPropList.size() << endl @@ -1875,7 +1906,8 @@ moordyn::MoorDyn::readBody(string inputText, int lineNum) { vector entries = moordyn::str::split(inputText, ' '); if (!checkNumberOfEntriesInLine(entries, 14, lineNum)) { - LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":\n"; + LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 + << ":\n"; return nullptr; } @@ -1902,7 +1934,8 @@ moordyn::MoorDyn::readBody(string inputText, int lineNum) rCG[1] = atof(entries_rCG[1].c_str()); rCG[2] = atof(entries_rCG[2].c_str()); } else { - LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":" << endl + LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":" + << endl << "'" << inputText << "'" << endl << "CG entry (col 10) must have 1 or 3 numbers" << endl; return nullptr; @@ -1985,14 +2018,16 @@ moordyn::MoorDyn::readBody(string inputText, int lineNum) // it is coupled - controlled from outside type = Body::COUPLED; CpldBodyIs.push_back(ui_size(BodyList)); - } else if (str::isOneOf(let1, { "VESSELPINNED", "VESPIN", "CPLDPIN", "COUPLEDPINNED" })) { + } else if (str::isOneOf( + let1, + { "VESSELPINNED", "VESPIN", "CPLDPIN", "COUPLEDPINNED" })) { // if a pinned fairlead, add to list and add type = Body::CPLDPIN; CpldBodyIs.push_back( ui_size(BodyList)); // index of fairlead in BodyList vector FreeBodyIs.push_back( - ui_size(BodyList)); // also add this pinned body to the free - // list because it is half free + ui_size(BodyList)); // also add this pinned body to the free + // list because it is half free } else { // it is free - controlled by MoorDyn type = Body::FREE; @@ -2046,11 +2081,12 @@ moordyn::MoorDyn::readRod(string inputText, int lineNum) // it is pinned type = Rod::PINNED; FreeRodIs.push_back( - ui_size(RodList)); // add this pinned rod to the free - // list because it is half free + ui_size(RodList)); // add this pinned rod to the free + // list because it is half free } else if (let1 == "BODY") { if (num1.empty()) { - LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":" + LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 + << ":" << "'" << inputText << "'" << endl << "no number provided for Rod " << number << " Body attachment" << endl; @@ -2058,7 +2094,8 @@ moordyn::MoorDyn::readRod(string inputText, int lineNum) } unsigned int bodyID = atoi(num1.c_str()); if (!bodyID || (bodyID > BodyList.size())) { - LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":" + LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 + << ":" << "'" << inputText << "'" << endl << "There is not " << bodyID << " bodies" << endl; return nullptr; @@ -2068,8 +2105,8 @@ moordyn::MoorDyn::readRod(string inputText, int lineNum) // it is pinned type = Rod::PINNED; FreeRodIs.push_back( - ui_size(RodList)); // add this pinned rod to the free - // list because it is half free + ui_size(RodList)); // add this pinned rod to the free + // list because it is half free } else { type = Rod::FIXED; } @@ -2078,18 +2115,20 @@ moordyn::MoorDyn::readRod(string inputText, int lineNum) type = Rod::COUPLED; CpldRodIs.push_back( ui_size(RodList)); // index of fairlead in RodList vector - } else if (str::isOneOf(let1, { "VESSELPINNED", "VESPIN", "CPLDPIN", "COUPLEDPINNED" })) { + } else if (str::isOneOf( + let1, + { "VESSELPINNED", "VESPIN", "CPLDPIN", "COUPLEDPINNED" })) { // if a pinned fairlead, add to list and add type = Rod::CPLDPIN; CpldRodIs.push_back( ui_size(RodList)); // index of fairlead in RodList vector FreeRodIs.push_back( - ui_size(RodList)); // also add this pinned rod to the free - // list because it is half free + ui_size(RodList)); // also add this pinned rod to the free + // list because it is half free } else if (str::isOneOf(let1, { "POINT", "CON", "FREE" })) { type = Rod::FREE; FreeRodIs.push_back( - ui_size(RodList)); // add this free rod to the free list + ui_size(RodList)); // add this free rod to the free list } else { LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":" << "'" << inputText << "'" << endl @@ -2248,23 +2287,23 @@ moordyn::MoorDyn::readOptionsLine(vector& in_txt, int i) this->seafloor = make_shared(_log); std::string filepath = value; this->seafloor->setup(env, filepath); - } else if (name == "disableoutput"){ + } else if (name == "disableoutput") { if (value == "1") { disableOutput = true; } else if (value == "0") { disableOutput = false; } else { - LOGWRN << "Unrecognized disableOutput value " - << std::quoted(value) << ". Should be 0 or 1" << endl; + LOGWRN << "Unrecognized disableOutput value " << std::quoted(value) + << ". Should be 0 or 1" << endl; } - } else if (name == "disableouttime"){ + } else if (name == "disableouttime") { if (value == "1") { disableOutTime = true; } else if (value == "0") { disableOutTime = false; } else { - LOGWRN << "Unrecognized disableOutTime value " - << std::quoted(value) << ". Should be 0 or 1" << endl; + LOGWRN << "Unrecognized disableOutTime value " << std::quoted(value) + << ". Should be 0 or 1" << endl; } } else LOGWRN << "Warning: Unrecognized option '" << name << "'" << endl; @@ -2272,12 +2311,15 @@ moordyn::MoorDyn::readOptionsLine(vector& in_txt, int i) bool moordyn::MoorDyn::checkNumberOfEntriesInLine(vector entries, - int supposedNumberOfEntries, int lineNum) + int supposedNumberOfEntries, + int lineNum) { if ((int)entries.size() < supposedNumberOfEntries) { - LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":" << endl - << supposedNumberOfEntries << " fields minimum are required, but just " - << entries.size() << " are provided" << endl; + LOGERR << "Error in " << _filepath << " at line " << lineNum + 1 << ":" + << endl + << supposedNumberOfEntries + << " fields minimum are required, but just " << entries.size() + << " are provided" << endl; return false; } @@ -2768,7 +2810,7 @@ MoorDyn_SetTimeScheme(MoorDyn system, const char* name) moordyn::time::Scheme* tscheme; try { tscheme = moordyn::time::create_time_scheme( - name, sys->GetLogger(), sys->GetWaves()); + name, sys->GetLogger(), sys->GetWaves()); } MOORDYN_CATCHER(err, err_msg); if (err != MOORDYN_SUCCESS) { diff --git a/source/MoorDyn2.h b/source/MoorDyn2.h index 800e641e..8d1f20e7 100644 --- a/source/MoorDyn2.h +++ b/source/MoorDyn2.h @@ -54,519 +54,550 @@ extern "C" #include #endif - /** @defgroup new_c_api The C API - * @{ - */ - - /// A mooring system instance - typedef struct __MoorDyn* MoorDyn; - - /** @brief Creates a MoorDyn instance - * - * At the time of creating a new MoorDyn instance, the input file is read - * and all the objects and structures are created. You must call afterwards - * MoorDyn_Init() to compute the initial conditions - * - * @param infilename The input file, if either NULL or "", then - * "Mooring/lines.txt" will be considered - * @return The mooring instance, NULL if errors happened - */ - MoorDyn DECLDIR MoorDyn_Create(const char* infilename); - - /** @brief Get the number of coupled Degrees Of Freedom (DOFs) - * - * The number of components for some parameters in MoorDyn_Init() and - * MoorDyn_Step() can be known using this function - * @return MOORDYN_INVALID_VALUE if @p system is NULL, MOORDYN_SUCESS - * otherwise - */ - int DECLDIR MoorDyn_NCoupledDOF(MoorDyn system, unsigned int* n); - - /** @brief Set the instance verbosity level - * @param system The Moordyn system - * @param verbosity The verbosity level. It can take the following values - * - MOORDYN_DBG_LEVEL Every single message will be printed - * - MOORDYN_MSG_LEVEL Messages specially designed to help debugging the - * code will be omitted - * - MOORDYN_WRN_LEVEL Just errors and warnings will be reported - * - MOORDYN_ERR_LEVEL Just errors will be reported - * - MOORDYN_NO_OUTPUT No info will be reported - * @return MOORDYN_SUCESS If the verbosity level is correctly set, an error - * code otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_SetVerbosity(MoorDyn system, int verbosity); - - /** @brief Set the instance log file - * @param system The Moordyn system - * @param log_path The file path to print the log file - * @return MOORDYN_SUCESS If the log file is correctly set, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_SetLogFile(MoorDyn system, const char* log_path); - - /** @brief Set the instance log file printing level - * @param system The Moordyn system - * @param verbosity The log file print level. It can take the following - * values - * - MOORDYN_DBG_LEVEL Every single message will be printed - * - MOORDYN_MSG_LEVEL Messages specially designed to help debugging the - * code will be omitted - * - MOORDYN_WRN_LEVEL Just errors and warnings will be reported - * - MOORDYN_ERR_LEVEL Just errors will be reported - * - MOORDYN_NO_OUTPUT No info will be reported - * @return MOORDYN_SUCESS If the printing level is correctly set, an error - * code otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_SetLogLevel(MoorDyn system, int verbosity); - - /** @brief Log a message - * @param system The Moordyn system - * @param level The message level. It can take the following values - * - MOORDYN_DBG_LEVEL for debugging messages - * - MOORDYN_MSG_LEVEL for regular information messages - * - MOORDYN_WRN_LEVEL for warnings - * - MOORDYN_ERR_LEVEL for errors - * @param msg The message to log - * @return MOORDYN_SUCESS If the printing level is correctly set, an error - * code otherwise (see @ref moordyn_errors) - * @note This messages are subjected to the same rules than the inner - * messages, i.e. if @p level is lower than the threshold levels set with - * MoorDyn_SetVerbosity() and MoorDyn_SetLogLevel(), the message will not be - * logged in the terminal and the log file respectively - * @note This function will not log the file, line and function where it is - * called from, not even in case of warnings or errors - */ - int DECLDIR MoorDyn_Log(MoorDyn system, int level, const char* msg); - - /** @brief Compute the initial condition of a MoorDyn system - * - * At the time of creating a new MoorDyn instance, the input file is read - * and all the objects and structures are created. You must call afterwards - * MoorDyn_Init() to compute the initial conditions - * - * @param system The Moordyn system - * @param x Position vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @param xd Velocity vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @return MOORDYN_SUCESS If the mooring system is correctly initialized, - * an error code otherwise (see @ref moordyn_errors) - * @note MoorDyn_NCoupledDOF() can be used to know the number of components - * required for \p x and \p xd - */ - int DECLDIR MoorDyn_Init(MoorDyn system, const double* x, const double* xd); - - /** @brief The same than MoorDyn_Init(), but the initial condition is not - * computed at all. - * - * This is of use when you are loading a state file afterwards with - * Moordyn_Load() - * - * @param system The Moordyn system - * @param x Position vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @param xd Velocity vector (6 components per coupled body or cantilevered - * rod and 3 components per pinned rod or coupled point) - * @return MOORDYN_SUCESS If the mooring system is correctly initialized, - * an error code otherwise (see @ref moordyn_errors) - * @note MoorDyn_NCoupledDOF() can be used to know the number of components - * required for \p x and \p xd - */ - int DECLDIR MoorDyn_Init_NoIC(MoorDyn system, - const double* x, - const double* xd); - - /** @brief Runs a time step of the MoorDyn system - * @param system The Moordyn system - * @param x Position vector - * @param xd Velocity vector - * @param f Output forces - * @param t Simulation time - * @param dt Time step - * @return MOORDYN_SUCESS if the mooring system has correctly evolved, an - * error code otherwise (see @ref moordyn_errors) - * @note MoorDyn_NCoupledDOF() can be used to know the number of components - * required for \p x, \p xd and \p f - */ - int DECLDIR MoorDyn_Step(MoorDyn system, - const double* x, - const double* xd, - double* f, - double* t, - double* dt); - - /** @brief Releases MoorDyn allocated resources - * @param system The Moordyn system - * @return MOORDYN_SUCESS If the mooring system is correctly destroyed, an - * error code otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_Close(MoorDyn system); - - /** @brief Get the wave kinematics instance - * - * The wave kinematics instance is only useful if WaveKin option is set to 2 - * in the input file. - * @param system The Moordyn system - * @return The waves instance, NULL if errors happened - */ - MoorDynWaves DECLDIR MoorDyn_GetWaves(MoorDyn system); - - /** @brief Get the 3D seafloor instance - * - * The seafloor instance is only not null if a SeafloorPath was given as an - * option. - * @param system The Moordyn system - * @return The Seafloor instance, NULL if errors happened or there is no 3D - * seafloor - */ - MoorDynSeafloor DECLDIR MoorDyn_GetSeafloor(MoorDyn system); - - /** - * @name External Wave Kinematics - * The functions for setting external wave kinematics. - */ - /// @{ - - /** @brief Initializes the external Wave kinematics - * - * This is useless unless the WaveKin option is set to 1 in the input file. - * If that is the case, remember to call this function after MoorDyn_Init() - * @param system The Moordyn system - * @param n The number of points where the wave kinematics shall be provided - * @return MOORDYN_SUCESS If the external waves are correctly initialized, - * an error code otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_ExternalWaveKinInit(MoorDyn system, unsigned int* n); - - /** @brief Get the number of points where the waves kinematics shall be - * provided - * - * This is useless unless WaveKin option is set to 1 in the input file - * @param system The Moordyn system - * @param n The output number of points where the wave kinematics shall - * be provided - * @return MOORDYN_SUCESS - * @see MoorDyn_ExternalWaveKinInit() - */ - int DECLDIR MoorDyn_ExternalWaveKinGetN(MoorDyn system, unsigned int* n); - - /** @brief Get the points where the waves kinematics shall be provided - * - * The kinematics on those points shall be provided just if WaveKin is set - * to 1 in the input file. The pointer r should be to an array with enough - * space for 3 * N doubles, where N is the value from - * MoorDyn_ExternalWaveKinGetN or MoorDyn_ExternalWaveKinInit. - * @param system The Moordyn system - * @param r The output coordinates (3 components per point) - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDyn_ExternalWaveKinInit() - */ - int DECLDIR MoorDyn_ExternalWaveKinGetCoordinates(MoorDyn system, - double* r); - - /** @brief Get the points where the waves kinematics shall be provided - * - * The kinematics on those points shall be provided just if WaveKin is set - * to 1 in the input file - * @param system The Moordyn system - * @param r The output coordinates (3 components per point) - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @deprecated This function has been renamed as - * MoorDyn_ExternalWaveKinGetCoordinates() - * @see MoorDyn_ExternalWaveKinInit() - */ - inline int DECLDIR DEPRECATED MoorDyn_GetWaveKinCoordinates(MoorDyn system, - double* r) - { - return MoorDyn_ExternalWaveKinGetCoordinates(system, r); - } - - /** @brief Set the kinematics of the waves - * - * Use this function if the WaveKin option is set to 1 in the input file - * @param system The Moordyn system - * @param U The velocities at the points (3 components per point) - * @param Ud The accelerations at the points (3 components per point) - * @param t Simulation time - * @return MOORDYN_SUCCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDyn_ExternalWaveKinInit() - * @see MoorDyn_ExternalWaveKinGetCoordinates() - */ - int DECLDIR MoorDyn_ExternalWaveKinSet(MoorDyn system, - const double* U, - const double* Ud, - double t); - - /** @brief Set the kinematics of the waves - * - * Use this function if WaveKin option is set to 1 in the input file - * @param system The Moordyn system - * @param U The velocities at the points (3 components per point) - * @param Ud The accelerations at the points (3 components per point) - * @param t Simulation time - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @deprecated This function has been renamed as - * MoorDyn_ExternalWaveKinSet() - * @see MoorDyn_ExternalWaveKinInit() - * @see MoorDyn_ExternalWaveKinGetCoordinates() - */ - inline int DECLDIR DEPRECATED MoorDyn_SetWaveKin(MoorDyn system, - const double* U, - const double* Ud, - double t) - { - return MoorDyn_ExternalWaveKinSet(system, U, Ud, t); - } - - /// @} - - /** @brief Get the number of bodies - * - * Remember that the first body index is 1 - * @param system The Moordyn system - * @param n The output number of bodies - * @return MOORDYN_SUCESS If the number is successfully got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetNumberBodies(MoorDyn system, unsigned int* n); - - /** @brief Get a rigid body - * - * Remember that the first body index is 1 - * @param system The Moordyn system - * @param b The body index - * @return The body instance, NULL if errors happened - */ - MoorDynBody DECLDIR MoorDyn_GetBody(MoorDyn system, unsigned int b); - - /** @brief Get the number of rods - * - * Remember that the first rod index is 1 - * @param system The Moordyn system - * @param n The output number of rods - * @return MOORDYN_SUCESS If the number is successfully got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetNumberRods(MoorDyn system, unsigned int* n); - - /** @brief Get a rod - * @param system The Moordyn system - * @param r The rod - * @return The rod instance, NULL if errors happened - */ - MoorDynRod DECLDIR MoorDyn_GetRod(MoorDyn system, unsigned int r); - - /** @brief Get the number of points - * - * Remember that the first point index is 1 - * @param system The Moordyn system - * @param n The output number of points - * @return MOORDYN_SUCESS If the number is successfully got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetNumberPoints(MoorDyn system, unsigned int* n); - - /** @brief Get a point - * @param system The Moordyn system - * @param c The point - * @return The point instance, NULL if errors happened - */ - MoorDynPoint DECLDIR MoorDyn_GetPoint(MoorDyn system, unsigned int c); - - /** @brief Get the number of lines - * - * Remember that the first line index is 1 - * @param system The Moordyn system - * @param n The output number of lines - * @return MOORDYN_SUCESS If the number is successfully got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetNumberLines(MoorDyn system, unsigned int* n); - - /** @brief Get a line instance - * @param system The Moordyn system - * @param l The line identifier (from 1 to the number of lines) - * @return The line instance, NULL if errors happened - */ - MoorDynLine DECLDIR MoorDyn_GetLine(MoorDyn system, unsigned int l); - - /** @brief Function for providing FASTv7 customary line tension quantities - * @param system The Moordyn system - * @param numLines The number of lines - * @param FairHTen Allocated memory for the \p numLines horizontal forces at - * the fairlead - * @param FairVTen Allocated memory for the \p numLines vertical forces at - * the fairlead - * @param AnchHTen Allocated memory for the \p numLines horizontal forces at - * the anchor - * @param AnchVTen Allocated memory for the \p numLines vertical forces at - * the anchor - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetFASTtens(MoorDyn system, - const int* numLines, - float FairHTen[], - float FairVTen[], - float AnchHTen[], - float AnchVTen[]); - - /** @brief Get the current model time step - * @param system The Moordyn system - * @param dt The output time step - * @return MOORDYN_SUCESS if the data is correctly got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetDt(MoorDyn system, double* dt); - - /** @brief Set the model time step - * @param system The Moordyn system - * @param dt The new time step - * @return MOORDYN_SUCESS if the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_SetDt(MoorDyn system, double dt); - - /** @brief Get the current model Courant–Friedrichs–Lewy factor - * @param system The Moordyn system - * @param cfl The output Courant–Friedrichs–Lewy factor - * @return MOORDYN_SUCESS if the data is correctly got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetCFL(MoorDyn system, double* cfl); - - /** @brief Set the model Courant–Friedrichs–Lewy factor - * @param system The Moordyn system - * @param cfl The new Courant–Friedrichs–Lewy factor - * @return MOORDYN_SUCESS if the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_SetCFL(MoorDyn system, double cfl); - - /** @brief Get the current time scheme name - * @param system The Moordyn system - * @param name The output name. Can be NULL. - * @param name_len The output number of bytes written. Can be NULL. - * @return MOORDYN_SUCESS if the data is correctly got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetTimeScheme(MoorDyn system, - char* name, - size_t* name_len); - - /** @brief Set the time scheme by its name - * @param system The Moordyn system - * @param name The new time scheme name. - * @return MOORDYN_SUCESS if the data is correctly got, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_SetTimeScheme(MoorDyn system, const char* name); - - /** @brief Save the system state, so it can be loaded afterwards - * - * The system state contains the system position and velocity. - * @param system The Moordyn system - * @param filepath The path of the file to write - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDyn_LoadState - * @see MoorDyn_Init_NoIC - * @note This function can be used to load the state exported by MoorPy - */ - int DECLDIR MoorDyn_SaveState(MoorDyn system, const char* filepath); - - /** @brief Load and set a system state - * - * The system state contains the system position and velocity. - * @param system The Moordyn system - * @param filepath The path of the MoorDyn saved system - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDyn_SaveState - * @see MoorDyn_Init_NoIC - * @note This function can be used to load the state exported by MoorPy - */ - int DECLDIR MoorDyn_LoadState(MoorDyn system, const char* filepath); - - /** @brief Serialize the system to bytes - * - * Typically you want to call this function twice. A first call to know the - * amount of memory to be allocated for the bytes array and a second one - * to actually get the bytes array - * - * The returned bytes can be used afterwards to restore the model calling - * to MoorDyn_Deserialize() - * @param system The Moordyn system - * @param size Output size of the bytes array. It can be null - * @param data Allocated memory for the output bytes array. It can be null - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_Serialize(MoorDyn system, size_t* size, uint64_t* data); - - /** @brief Load the system from the serialized data before - * - * You can restore the system to a previous state retrieved calling - * MoorDyn_Serialize() - * @param system The Moordyn system - * @param data Bytes array - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDyn_Save - * @see MoorDyn_Init_NoIC - */ - int DECLDIR MoorDyn_Deserialize(MoorDyn system, const uint64_t* data); - - /** @brief Save the system so it can be loaded afterwards - * - * At the time of loading the system, it is still required to create the - * system reading the same definition file and calling MoorDyn_Init_NoIC() - * @param system The Moordyn system - * @param filepath The path of the file to write - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDyn_Load - * @see MoorDyn_Init_NoIC - */ - int DECLDIR MoorDyn_Save(MoorDyn system, const char* filepath); - - /** @brief Load the system saved before - * - * You must still call MoorDyn_Create() and MoorDyn_Init_NoIC() before - * calling this function - * @param system The Moordyn system - * @param filepath The path of the MoorDyn saved system - * @return MOORDYN_SUCESS If the data is correctly set, an error code - * otherwise (see @ref moordyn_errors) - * @see MoorDyn_Save - * @see MoorDyn_Init_NoIC - */ - int DECLDIR MoorDyn_Load(MoorDyn system, const char* filepath); - - /** @brief Save the whole system to a VTK (.vtm) file - * - * In general it is more convenient to handle each object independently, - * using MoorDyn_SaveLineVTK() and MoorDyn_SaveRodVTK() functions. However, - * if the number of subinstances is large, that would not be an option - * anymore. In that case you can use this function to pack everything - * together in a single file - * @param system The Moordyn system - * @param filename The output maximum tension module - * @return MOORDYN_SUCCESS if the file is correctly written, an error code - * otherwise - * @note If MoorDyn has been built without VTK support, this function will - * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available - * anyway - */ - int DECLDIR MoorDyn_SaveVTK(MoorDyn system, const char* filename); - - /** - * @} - */ +/** @defgroup new_c_api The C API + * @{ + */ + +/// A mooring system instance +typedef struct __MoorDyn* MoorDyn; + +/** @brief Creates a MoorDyn instance + * + * At the time of creating a new MoorDyn instance, the input file is read + * and all the objects and structures are created. You must call afterwards + * MoorDyn_Init() to compute the initial conditions + * + * @param infilename The input file, if either NULL or "", then + * "Mooring/lines.txt" will be considered + * @return The mooring instance, NULL if errors happened + */ +MoorDyn DECLDIR +MoorDyn_Create(const char* infilename); + +/** @brief Get the number of coupled Degrees Of Freedom (DOFs) + * + * The number of components for some parameters in MoorDyn_Init() and + * MoorDyn_Step() can be known using this function + * @return MOORDYN_INVALID_VALUE if @p system is NULL, MOORDYN_SUCESS + * otherwise + */ +int DECLDIR +MoorDyn_NCoupledDOF(MoorDyn system, unsigned int* n); + +/** @brief Set the instance verbosity level + * @param system The Moordyn system + * @param verbosity The verbosity level. It can take the following values + * - MOORDYN_DBG_LEVEL Every single message will be printed + * - MOORDYN_MSG_LEVEL Messages specially designed to help debugging the + * code will be omitted + * - MOORDYN_WRN_LEVEL Just errors and warnings will be reported + * - MOORDYN_ERR_LEVEL Just errors will be reported + * - MOORDYN_NO_OUTPUT No info will be reported + * @return MOORDYN_SUCESS If the verbosity level is correctly set, an error + * code otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_SetVerbosity(MoorDyn system, int verbosity); + +/** @brief Set the instance log file + * @param system The Moordyn system + * @param log_path The file path to print the log file + * @return MOORDYN_SUCESS If the log file is correctly set, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_SetLogFile(MoorDyn system, const char* log_path); + +/** @brief Set the instance log file printing level + * @param system The Moordyn system + * @param verbosity The log file print level. It can take the following + * values + * - MOORDYN_DBG_LEVEL Every single message will be printed + * - MOORDYN_MSG_LEVEL Messages specially designed to help debugging the + * code will be omitted + * - MOORDYN_WRN_LEVEL Just errors and warnings will be reported + * - MOORDYN_ERR_LEVEL Just errors will be reported + * - MOORDYN_NO_OUTPUT No info will be reported + * @return MOORDYN_SUCESS If the printing level is correctly set, an error + * code otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_SetLogLevel(MoorDyn system, int verbosity); + +/** @brief Log a message + * @param system The Moordyn system + * @param level The message level. It can take the following values + * - MOORDYN_DBG_LEVEL for debugging messages + * - MOORDYN_MSG_LEVEL for regular information messages + * - MOORDYN_WRN_LEVEL for warnings + * - MOORDYN_ERR_LEVEL for errors + * @param msg The message to log + * @return MOORDYN_SUCESS If the printing level is correctly set, an error + * code otherwise (see @ref moordyn_errors) + * @note This messages are subjected to the same rules than the inner + * messages, i.e. if @p level is lower than the threshold levels set with + * MoorDyn_SetVerbosity() and MoorDyn_SetLogLevel(), the message will not be + * logged in the terminal and the log file respectively + * @note This function will not log the file, line and function where it is + * called from, not even in case of warnings or errors + */ +int DECLDIR +MoorDyn_Log(MoorDyn system, int level, const char* msg); + +/** @brief Compute the initial condition of a MoorDyn system + * + * At the time of creating a new MoorDyn instance, the input file is read + * and all the objects and structures are created. You must call afterwards + * MoorDyn_Init() to compute the initial conditions + * + * @param system The Moordyn system + * @param x Position vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @param xd Velocity vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @return MOORDYN_SUCESS If the mooring system is correctly initialized, + * an error code otherwise (see @ref moordyn_errors) + * @note MoorDyn_NCoupledDOF() can be used to know the number of components + * required for \p x and \p xd + */ +int DECLDIR +MoorDyn_Init(MoorDyn system, const double* x, const double* xd); + +/** @brief The same than MoorDyn_Init(), but the initial condition is not + * computed at all. + * + * This is of use when you are loading a state file afterwards with + * Moordyn_Load() + * + * @param system The Moordyn system + * @param x Position vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @param xd Velocity vector (6 components per coupled body or cantilevered + * rod and 3 components per pinned rod or coupled point) + * @return MOORDYN_SUCESS If the mooring system is correctly initialized, + * an error code otherwise (see @ref moordyn_errors) + * @note MoorDyn_NCoupledDOF() can be used to know the number of components + * required for \p x and \p xd + */ +int DECLDIR +MoorDyn_Init_NoIC(MoorDyn system, const double* x, const double* xd); + +/** @brief Runs a time step of the MoorDyn system + * @param system The Moordyn system + * @param x Position vector + * @param xd Velocity vector + * @param f Output forces + * @param t Simulation time + * @param dt Time step + * @return MOORDYN_SUCESS if the mooring system has correctly evolved, an + * error code otherwise (see @ref moordyn_errors) + * @note MoorDyn_NCoupledDOF() can be used to know the number of components + * required for \p x, \p xd and \p f + */ +int DECLDIR +MoorDyn_Step(MoorDyn system, + const double* x, + const double* xd, + double* f, + double* t, + double* dt); + +/** @brief Releases MoorDyn allocated resources + * @param system The Moordyn system + * @return MOORDYN_SUCESS If the mooring system is correctly destroyed, an + * error code otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_Close(MoorDyn system); + +/** @brief Get the wave kinematics instance + * + * The wave kinematics instance is only useful if WaveKin option is set to 2 + * in the input file. + * @param system The Moordyn system + * @return The waves instance, NULL if errors happened + */ +MoorDynWaves DECLDIR +MoorDyn_GetWaves(MoorDyn system); + +/** @brief Get the 3D seafloor instance + * + * The seafloor instance is only not null if a SeafloorPath was given as an + * option. + * @param system The Moordyn system + * @return The Seafloor instance, NULL if errors happened or there is no 3D + * seafloor + */ +MoorDynSeafloor DECLDIR +MoorDyn_GetSeafloor(MoorDyn system); + +/** + * @name External Wave Kinematics + * The functions for setting external wave kinematics. + */ +/// @{ + +/** @brief Initializes the external Wave kinematics + * + * This is useless unless the WaveKin option is set to 1 in the input file. + * If that is the case, remember to call this function after MoorDyn_Init() + * @param system The Moordyn system + * @param n The number of points where the wave kinematics shall be provided + * @return MOORDYN_SUCESS If the external waves are correctly initialized, + * an error code otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_ExternalWaveKinInit(MoorDyn system, unsigned int* n); + +/** @brief Get the number of points where the waves kinematics shall be + * provided + * + * This is useless unless WaveKin option is set to 1 in the input file + * @param system The Moordyn system + * @param n The output number of points where the wave kinematics shall + * be provided + * @return MOORDYN_SUCESS + * @see MoorDyn_ExternalWaveKinInit() + */ +int DECLDIR +MoorDyn_ExternalWaveKinGetN(MoorDyn system, unsigned int* n); + +/** @brief Get the points where the waves kinematics shall be provided + * + * The kinematics on those points shall be provided just if WaveKin is set + * to 1 in the input file. The pointer r should be to an array with enough + * space for 3 * N doubles, where N is the value from + * MoorDyn_ExternalWaveKinGetN or MoorDyn_ExternalWaveKinInit. + * @param system The Moordyn system + * @param r The output coordinates (3 components per point) + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDyn_ExternalWaveKinInit() + */ +int DECLDIR +MoorDyn_ExternalWaveKinGetCoordinates(MoorDyn system, double* r); + +/** @brief Get the points where the waves kinematics shall be provided + * + * The kinematics on those points shall be provided just if WaveKin is set + * to 1 in the input file + * @param system The Moordyn system + * @param r The output coordinates (3 components per point) + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @deprecated This function has been renamed as + * MoorDyn_ExternalWaveKinGetCoordinates() + * @see MoorDyn_ExternalWaveKinInit() + */ +inline int DECLDIR DEPRECATED +MoorDyn_GetWaveKinCoordinates(MoorDyn system, double* r) +{ + return MoorDyn_ExternalWaveKinGetCoordinates(system, r); +} + +/** @brief Set the kinematics of the waves + * + * Use this function if the WaveKin option is set to 1 in the input file + * @param system The Moordyn system + * @param U The velocities at the points (3 components per point) + * @param Ud The accelerations at the points (3 components per point) + * @param t Simulation time + * @return MOORDYN_SUCCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDyn_ExternalWaveKinInit() + * @see MoorDyn_ExternalWaveKinGetCoordinates() + */ +int DECLDIR +MoorDyn_ExternalWaveKinSet(MoorDyn system, + const double* U, + const double* Ud, + double t); + +/** @brief Set the kinematics of the waves + * + * Use this function if WaveKin option is set to 1 in the input file + * @param system The Moordyn system + * @param U The velocities at the points (3 components per point) + * @param Ud The accelerations at the points (3 components per point) + * @param t Simulation time + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @deprecated This function has been renamed as + * MoorDyn_ExternalWaveKinSet() + * @see MoorDyn_ExternalWaveKinInit() + * @see MoorDyn_ExternalWaveKinGetCoordinates() + */ +inline int DECLDIR DEPRECATED +MoorDyn_SetWaveKin(MoorDyn system, const double* U, const double* Ud, double t) +{ + return MoorDyn_ExternalWaveKinSet(system, U, Ud, t); +} + +/// @} + +/** @brief Get the number of bodies + * + * Remember that the first body index is 1 + * @param system The Moordyn system + * @param n The output number of bodies + * @return MOORDYN_SUCESS If the number is successfully got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetNumberBodies(MoorDyn system, unsigned int* n); + +/** @brief Get a rigid body + * + * Remember that the first body index is 1 + * @param system The Moordyn system + * @param b The body index + * @return The body instance, NULL if errors happened + */ +MoorDynBody DECLDIR +MoorDyn_GetBody(MoorDyn system, unsigned int b); + +/** @brief Get the number of rods + * + * Remember that the first rod index is 1 + * @param system The Moordyn system + * @param n The output number of rods + * @return MOORDYN_SUCESS If the number is successfully got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetNumberRods(MoorDyn system, unsigned int* n); + +/** @brief Get a rod + * @param system The Moordyn system + * @param r The rod + * @return The rod instance, NULL if errors happened + */ +MoorDynRod DECLDIR +MoorDyn_GetRod(MoorDyn system, unsigned int r); + +/** @brief Get the number of points + * + * Remember that the first point index is 1 + * @param system The Moordyn system + * @param n The output number of points + * @return MOORDYN_SUCESS If the number is successfully got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetNumberPoints(MoorDyn system, unsigned int* n); + +/** @brief Get a point + * @param system The Moordyn system + * @param c The point + * @return The point instance, NULL if errors happened + */ +MoorDynPoint DECLDIR +MoorDyn_GetPoint(MoorDyn system, unsigned int c); + +/** @brief Get the number of lines + * + * Remember that the first line index is 1 + * @param system The Moordyn system + * @param n The output number of lines + * @return MOORDYN_SUCESS If the number is successfully got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetNumberLines(MoorDyn system, unsigned int* n); + +/** @brief Get a line instance + * @param system The Moordyn system + * @param l The line identifier (from 1 to the number of lines) + * @return The line instance, NULL if errors happened + */ +MoorDynLine DECLDIR +MoorDyn_GetLine(MoorDyn system, unsigned int l); + +/** @brief Function for providing FASTv7 customary line tension quantities + * @param system The Moordyn system + * @param numLines The number of lines + * @param FairHTen Allocated memory for the \p numLines horizontal forces at + * the fairlead + * @param FairVTen Allocated memory for the \p numLines vertical forces at + * the fairlead + * @param AnchHTen Allocated memory for the \p numLines horizontal forces at + * the anchor + * @param AnchVTen Allocated memory for the \p numLines vertical forces at + * the anchor + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetFASTtens(MoorDyn system, + const int* numLines, + float FairHTen[], + float FairVTen[], + float AnchHTen[], + float AnchVTen[]); + +/** @brief Get the current model time step + * @param system The Moordyn system + * @param dt The output time step + * @return MOORDYN_SUCESS if the data is correctly got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetDt(MoorDyn system, double* dt); + +/** @brief Set the model time step + * @param system The Moordyn system + * @param dt The new time step + * @return MOORDYN_SUCESS if the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_SetDt(MoorDyn system, double dt); + +/** @brief Get the current model Courant–Friedrichs–Lewy factor + * @param system The Moordyn system + * @param cfl The output Courant–Friedrichs–Lewy factor + * @return MOORDYN_SUCESS if the data is correctly got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetCFL(MoorDyn system, double* cfl); + +/** @brief Set the model Courant–Friedrichs–Lewy factor + * @param system The Moordyn system + * @param cfl The new Courant–Friedrichs–Lewy factor + * @return MOORDYN_SUCESS if the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_SetCFL(MoorDyn system, double cfl); + +/** @brief Get the current time scheme name + * @param system The Moordyn system + * @param name The output name. Can be NULL. + * @param name_len The output number of bytes written. Can be NULL. + * @return MOORDYN_SUCESS if the data is correctly got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetTimeScheme(MoorDyn system, char* name, size_t* name_len); + +/** @brief Set the time scheme by its name + * @param system The Moordyn system + * @param name The new time scheme name. + * @return MOORDYN_SUCESS if the data is correctly got, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_SetTimeScheme(MoorDyn system, const char* name); + +/** @brief Save the system state, so it can be loaded afterwards + * + * The system state contains the system position and velocity. + * @param system The Moordyn system + * @param filepath The path of the file to write + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDyn_LoadState + * @see MoorDyn_Init_NoIC + * @note This function can be used to load the state exported by MoorPy + */ +int DECLDIR +MoorDyn_SaveState(MoorDyn system, const char* filepath); + +/** @brief Load and set a system state + * + * The system state contains the system position and velocity. + * @param system The Moordyn system + * @param filepath The path of the MoorDyn saved system + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDyn_SaveState + * @see MoorDyn_Init_NoIC + * @note This function can be used to load the state exported by MoorPy + */ +int DECLDIR +MoorDyn_LoadState(MoorDyn system, const char* filepath); + +/** @brief Serialize the system to bytes + * + * Typically you want to call this function twice. A first call to know the + * amount of memory to be allocated for the bytes array and a second one + * to actually get the bytes array + * + * The returned bytes can be used afterwards to restore the model calling + * to MoorDyn_Deserialize() + * @param system The Moordyn system + * @param size Output size of the bytes array. It can be null + * @param data Allocated memory for the output bytes array. It can be null + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_Serialize(MoorDyn system, size_t* size, uint64_t* data); + +/** @brief Load the system from the serialized data before + * + * You can restore the system to a previous state retrieved calling + * MoorDyn_Serialize() + * @param system The Moordyn system + * @param data Bytes array + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDyn_Save + * @see MoorDyn_Init_NoIC + */ +int DECLDIR +MoorDyn_Deserialize(MoorDyn system, const uint64_t* data); + +/** @brief Save the system so it can be loaded afterwards + * + * At the time of loading the system, it is still required to create the + * system reading the same definition file and calling MoorDyn_Init_NoIC() + * @param system The Moordyn system + * @param filepath The path of the file to write + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDyn_Load + * @see MoorDyn_Init_NoIC + */ +int DECLDIR +MoorDyn_Save(MoorDyn system, const char* filepath); + +/** @brief Load the system saved before + * + * You must still call MoorDyn_Create() and MoorDyn_Init_NoIC() before + * calling this function + * @param system The Moordyn system + * @param filepath The path of the MoorDyn saved system + * @return MOORDYN_SUCESS If the data is correctly set, an error code + * otherwise (see @ref moordyn_errors) + * @see MoorDyn_Save + * @see MoorDyn_Init_NoIC + */ +int DECLDIR +MoorDyn_Load(MoorDyn system, const char* filepath); + +/** @brief Save the whole system to a VTK (.vtm) file + * + * In general it is more convenient to handle each object independently, + * using MoorDyn_SaveLineVTK() and MoorDyn_SaveRodVTK() functions. However, + * if the number of subinstances is large, that would not be an option + * anymore. In that case you can use this function to pack everything + * together in a single file + * @param system The Moordyn system + * @param filename The output maximum tension module + * @return MOORDYN_SUCCESS if the file is correctly written, an error code + * otherwise + * @note If MoorDyn has been built without VTK support, this function will + * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available + * anyway + */ +int DECLDIR +MoorDyn_SaveVTK(MoorDyn system, const char* filename); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/source/MoorDyn2.hpp b/source/MoorDyn2.hpp index c6c0fbeb..4f3506df 100644 --- a/source/MoorDyn2.hpp +++ b/source/MoorDyn2.hpp @@ -128,8 +128,8 @@ class MoorDyn final : public io::IO /** * @brief Set whether console and file output is disabled. - * - * @param disable + * + * @param disable */ inline void SetDisableOutput(bool disable) { disableOutput = disable; } @@ -332,7 +332,8 @@ class MoorDyn final : public io::IO * @param dt The model time step * @note The CFL will be changed accordingly */ - inline void SetDt(real dt) { + inline void SetDt(real dt) + { this->dtM0 = dt; this->cfl = 0.0; for (auto obj : LineList) @@ -354,7 +355,8 @@ class MoorDyn final : public io::IO * @param cfl The CFL * @note The time step will be changed accordingly */ - inline void SetCFL(real cfl) { + inline void SetCFL(real cfl) + { this->cfl = cfl; this->dtM0 = (std::numeric_limits::max)(); for (auto obj : LineList) @@ -375,8 +377,10 @@ class MoorDyn final : public io::IO /** @brief Set the current time integrator * @return The time integrator */ - inline void SetTimeScheme(time::Scheme* tscheme) { - if (_t_integrator) delete _t_integrator; + inline void SetTimeScheme(time::Scheme* tscheme) + { + if (_t_integrator) + delete _t_integrator; _t_integrator = tscheme; _t_integrator->SetGround(GroundBody); for (auto obj : BodyList) @@ -475,7 +479,8 @@ class MoorDyn final : public io::IO * @param lineNum the file line number for error messages */ bool checkNumberOfEntriesInLine(vector entries, - int supposedNumberOfEntries, int lineNum); + int supposedNumberOfEntries, + int lineNum); /** @brief Compute an initial condition using the stationary solver * @see ::ICgenDynamic @@ -722,7 +727,7 @@ class MoorDyn final : public io::IO while (f.good()) { string fline; getline(f, fline); - if (i>2) { // skip first three lines as headers + if (i > 2) { // skip first three lines as headers moordyn::str::rtrim(fline); flines.push_back(fline); } @@ -749,7 +754,7 @@ class MoorDyn final : public io::IO LOGDBG << "(" << x.back() << ", " << y.back() << ")" << std::endl; } - LOGMSG << (i-3) << " lines of curve successfully loaded" << std::endl; + LOGMSG << (i - 3) << " lines of curve successfully loaded" << std::endl; return MOORDYN_SUCCESS; } diff --git a/source/Point.h b/source/Point.h index 477119c0..a3800df2 100644 --- a/source/Point.h +++ b/source/Point.h @@ -42,103 +42,112 @@ extern "C" { #endif - /** @addtogroup new_c_api - * @{ - */ - - /// A mooring point instance - typedef struct __MoorDynPoint* MoorDynPoint; - - /** @brief Get the point identifier - * @param point The Moordyn point - * @param id The output id - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetPointID(MoorDynPoint point, int* id); - - /** @brief Get the point type - * @param point The Moordyn point - * @param t The output type - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - * @see Point::types - */ - int DECLDIR MoorDyn_GetPointType(MoorDynPoint point, int* t); - - /** @brief Get the position of a point - * @param point The Moordyn point - * @param pos The output position - * @return MOORDYN_SUCCESS If the data is correctly set, an error code - * otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetPointPos(MoorDynPoint point, double pos[3]); - - /** @brief Get the velocity of a point - * @param point The Moordyn point - * @param v The output velocity - * @return MOORDYN_SUCCESS If the data is correctly set, an error code - * otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetPointVel(MoorDynPoint point, double v[3]); - - /** @brief Get the force at a point - * @param point The Moordyn point - * @param f The output force - * @return MOORDYN_SUCCESS If the data is correctly set, an error code - * otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetPointForce(MoorDynPoint point, double f[3]); - - /** @brief Get the point mass matrix - * @param point The Moordyn point - * @param f The output force - * @return MOORDYN_SUCCESS If the data is correctly set, an error code - * otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetPointM(MoorDynPoint point, double m[3][3]); - - /** @brief Get the number of connected lines - * @param point The Moordyn point - * @param n The output number of connected lines - * @return MOORDYN_SUCCESS If the data is correctly set, an error code - * otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetPointNAttached(MoorDynPoint point, unsigned int* n); - - /** @brief Get the number of connected lines - * @param point The Moordyn point - * @param i The index of the attached line - * @param l The output attached line - * @param e The output endpoint, see moordyn::EndPoints - * @return MOORDYN_SUCCESS If the data is correctly set, an error code - * otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetPointAttached(MoorDynPoint point, - unsigned int i, - MoorDynLine* l, - int* e); - - /** @brief Save the point to a VTK (.vtp) file - * @param point The Moordyn point - * @param filename The output maximum tension module - * @return MOORDYN_SUCCESS if the file is correctly written, an error code - * otherwise - * @note If MoorDyn has been built without VTK support, this function will - * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available - * anyway - */ - int DECLDIR MoorDyn_SavePointVTK(MoorDynPoint point, const char* filename); - - /** - * @} - */ +/** @addtogroup new_c_api + * @{ + */ + +/// A mooring point instance +typedef struct __MoorDynPoint* MoorDynPoint; + +/** @brief Get the point identifier + * @param point The Moordyn point + * @param id The output id + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetPointID(MoorDynPoint point, int* id); + +/** @brief Get the point type + * @param point The Moordyn point + * @param t The output type + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + * @see Point::types + */ +int DECLDIR +MoorDyn_GetPointType(MoorDynPoint point, int* t); + +/** @brief Get the position of a point + * @param point The Moordyn point + * @param pos The output position + * @return MOORDYN_SUCCESS If the data is correctly set, an error code + * otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetPointPos(MoorDynPoint point, double pos[3]); + +/** @brief Get the velocity of a point + * @param point The Moordyn point + * @param v The output velocity + * @return MOORDYN_SUCCESS If the data is correctly set, an error code + * otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetPointVel(MoorDynPoint point, double v[3]); + +/** @brief Get the force at a point + * @param point The Moordyn point + * @param f The output force + * @return MOORDYN_SUCCESS If the data is correctly set, an error code + * otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetPointForce(MoorDynPoint point, double f[3]); + +/** @brief Get the point mass matrix + * @param point The Moordyn point + * @param f The output force + * @return MOORDYN_SUCCESS If the data is correctly set, an error code + * otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetPointM(MoorDynPoint point, double m[3][3]); + +/** @brief Get the number of connected lines + * @param point The Moordyn point + * @param n The output number of connected lines + * @return MOORDYN_SUCCESS If the data is correctly set, an error code + * otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetPointNAttached(MoorDynPoint point, unsigned int* n); + +/** @brief Get the number of connected lines + * @param point The Moordyn point + * @param i The index of the attached line + * @param l The output attached line + * @param e The output endpoint, see moordyn::EndPoints + * @return MOORDYN_SUCCESS If the data is correctly set, an error code + * otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetPointAttached(MoorDynPoint point, + unsigned int i, + MoorDynLine* l, + int* e); + +/** @brief Save the point to a VTK (.vtp) file + * @param point The Moordyn point + * @param filename The output maximum tension module + * @return MOORDYN_SUCCESS if the file is correctly written, an error code + * otherwise + * @note If MoorDyn has been built without VTK support, this function will + * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available + * anyway + */ +int DECLDIR +MoorDyn_SavePointVTK(MoorDynPoint point, const char* filename); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/source/Point.hpp b/source/Point.hpp index 194850b1..a1877a90 100644 --- a/source/Point.hpp +++ b/source/Point.hpp @@ -67,7 +67,9 @@ typedef std::shared_ptr WavesRef; * weight or float via the point's mass and volume parameters * - Coupled: The point position and velocity is externally imposed */ -class DECLDIR Point final : public Instance, public SuperCFL +class DECLDIR Point final + : public Instance + , public SuperCFL { public: /** @brief Constructor @@ -359,8 +361,8 @@ class DECLDIR Point final : public Instance, public SuperCFL /** @brief Set the state variables * - * sets Point position and velocity and ends of attached lines ONLY if this Point - * is free, i.e. type = FREE (otherwise shouldn't be called) + * sets Point position and velocity and ends of attached lines ONLY if this + * Point is free, i.e. type = FREE (otherwise shouldn't be called) * @param pos Position * @param vel Velocity * @throws moordyn::invalid_value_error If it is not a FREE point @@ -378,7 +380,10 @@ class DECLDIR Point final : public Instance, public SuperCFL */ inline void setState(const InstanceStateVarView r) { - setState(r.row(0).head<3>(), r.row(0).tail<3>()); // TODO: when working on line failures, make this setState call match rods, bodies, and lines structure + setState(r.row(0).head<3>(), + r.row(0).tail<3>()); // TODO: when working on line failures, + // make this setState call match rods, + // bodies, and lines structure } /** @brief Calculate the forces and state derivatives of the point @@ -469,7 +474,6 @@ class DECLDIR Point final : public Instance, public SuperCFL { return -M * (w.cross(w.cross(this->r - r))); } - }; } // ::moordyn diff --git a/source/QSlines.hpp b/source/QSlines.hpp index f7946506..b1d37c11 100644 --- a/source/QSlines.hpp +++ b/source/QSlines.hpp @@ -111,13 +111,14 @@ Catenary(T XF, // Checking inverted points at line ends: from catenary.py in MoorPy bool reverseFlag; - if ( ZF < 0.0 ){ // True if the fairlead has passed below its anchor - ZF = -ZF; - reverseFlag = true; + if (ZF < 0.0) { // True if the fairlead has passed below its anchor + ZF = -ZF; + reverseFlag = true; if (longwinded == 1) - cout << " Warning from catenary: " - << "Anchor point is above the fairlead point" << endl; - } else reverseFlag = false; + cout << " Warning from catenary: " + << "Anchor point is above the fairlead point" << endl; + } else + reverseFlag = false; // Maximum stretched length of the line with seabed interaction beyond which // the line would have to double-back on itself; here the line forms an "L" @@ -585,7 +586,7 @@ Catenary(T XF, reverse(X.begin(), X.end()); reverse(Z.begin(), Z.end()); reverse(Te.begin(), Te.end()); - for (unsigned int I = 0; I < Nnodes; I++){ + for (unsigned int I = 0; I < Nnodes; I++) { s[I] = L - s[I]; X[I] = XF - X[I]; Z[I] = Z[I] - ZF; diff --git a/source/Rod.cpp b/source/Rod.cpp index 5eb92423..de5b8f3e 100644 --- a/source/Rod.cpp +++ b/source/Rod.cpp @@ -154,9 +154,10 @@ Rod::setup(int number_in, v6 = vec6::Zero(); } else if ((type == PINNED) || (type == CPLDPIN)) { // for a pinned rod, just set the orientation (position will be set - // later by parent object) - r7.pos = vec3::Zero(); - r7.quat = quaternion::FromTwoVectors(q0, endCoords.tail<3>()); // TODO: Check this is right + // later by parent object) + r7.pos = vec3::Zero(); + r7.quat = quaternion::FromTwoVectors( + q0, endCoords.tail<3>()); // TODO: Check this is right v6(Eigen::seqN(3, 3)) = vec::Zero(); } // otherwise (for a fixed rod) the positions will be set by the parent body @@ -342,12 +343,13 @@ Rod::initialize() real Rod::GetRodOutput(OutChanProps outChan) { - + vec6 Fout; - if ((outChan.QType == FX)||(outChan.QType == FY)||(outChan.QType == FZ)||(outChan.QType == MX)||(outChan.QType == MY)||(outChan.QType == MZ)) + if ((outChan.QType == FX) || (outChan.QType == FY) || + (outChan.QType == FZ) || (outChan.QType == MX) || + (outChan.QType == MY) || (outChan.QType == MZ)) Fout = getFnet(); - if (outChan.NodeID == -1) { if (outChan.QType == PosX) return r7.pos.x(); @@ -525,7 +527,8 @@ Rod::setKinematics(vec6 r_in, vec6 rd_in) // since this rod has no states and all DOFs have been set, pass its // kinematics to dependent Lines setDependentStates(); - } else if ((type == PINNED) || (type == CPLDPIN))// rod end A pinned to a body + } else if ((type == PINNED) || + (type == CPLDPIN)) // rod end A pinned to a body { // set Rod *end A only* kinematics based on BCs (linear model for now) r7.pos = r_in(Eigen::seqN(0, 3)); @@ -672,8 +675,11 @@ Rod::getStateDeriv(InstanceStateVarView drdt) } else { // Pinned rod - // account for moment in response to end A acceleration due to inertial coupling (off-diagonal sub-matrix terms) - const vec Fnet_out3 = Fnet_out(Eigen::seqN(3, 3)) - (M_out6.bottomLeftCorner<3,3>() * acc6(Eigen::seqN(0, 3))); + // account for moment in response to end A acceleration due to inertial + // coupling (off-diagonal sub-matrix terms) + const vec Fnet_out3 = + Fnet_out(Eigen::seqN(3, 3)) - + (M_out6.bottomLeftCorner<3, 3>() * acc6(Eigen::seqN(0, 3))); // For small systems it is usually faster to compute the inverse // of the matrix. See @@ -696,24 +702,30 @@ const vec6 Rod::getFnet() const { // return F6net; - // // >>>>>>>>>>>>> do I want to leverage getNetForceAndMass or a saved global + // // >>>>>>>>>>>>> do I want to leverage getNetForceAndMass or a saved + // global // // to save comp time and code? >>>>>>>> this function likely not used // // >>>>>>>>>>> - // // Fnet_out is assumed to point to a size-3 array if the rod is pinned and + // // Fnet_out is assumed to point to a size-3 array if the rod is pinned + // and // // size-6 array if the rod is fixed vec6 F6_iner = vec6::Zero(); vec6 Fnet_out = vec6::Zero(); // this assumes doRHS() has already been called - if (type == COUPLED) { // if coupled rigidly - F6_iner = - M6net * acc6; // Inertial terms + if (type == COUPLED) { // if coupled rigidly + F6_iner = -M6net * acc6; // Inertial terms Fnet_out = F6net + F6_iner; } else if (type == CPLDPIN) { // if coupled pinned - F6_iner(Eigen::seqN(0,3)) = (- M6net.topLeftCorner<3,3>() * acc6(Eigen::seqN(0,3))) - (M6net.topRightCorner<3,3>() * acc6(Eigen::seqN(3,3))); // Inertial term - Fnet_out(Eigen::seqN(0,3)) = F6net(Eigen::seqN(0,3)) + F6_iner(Eigen::seqN(0,3)); - Fnet_out(Eigen::seqN(3,3)) = vec3::Zero(); + F6_iner(Eigen::seqN(0, 3)) = + (-M6net.topLeftCorner<3, 3>() * acc6(Eigen::seqN(0, 3))) - + (M6net.topRightCorner<3, 3>() * + acc6(Eigen::seqN(3, 3))); // Inertial term + Fnet_out(Eigen::seqN(0, 3)) = + F6net(Eigen::seqN(0, 3)) + F6_iner(Eigen::seqN(0, 3)); + Fnet_out(Eigen::seqN(3, 3)) = vec3::Zero(); } else { // LOGERR << "Invalid rod type: " << TypeName(type) << endl; // throw moordyn::invalid_value_error("Invalid rod type"); @@ -721,7 +733,8 @@ Rod::getFnet() const Fnet_out = F6net; } - // // now go through each node's contributions, put them in body ref frame, and + // // now go through each node's contributions, put them in body ref frame, + // and // // sum them // for (unsigned int i = 0; i <= N; i++) { // // position of a given node relative to the body reference point (global @@ -925,15 +938,25 @@ Rod::doRHS() // now real zeta_i = zeta[N]; - // get approximate location of waterline crossing along Rod axis (note: negative h0 indicates end A is above end B, and measures -distance from end A to waterline crossing) - if ((r[0][2] < zeta_i) && (r[N][2] < zeta_i)) // fully submerged case - h0 = UnstrLen; - else if ((r[0][2] < zeta_i) && (r[N][2] > zeta_i)) // check if it's crossing the water plane (should also add some limits to avoid near-horizontals at some point) - h0 = (zeta_i - r[0][2])/q[2]; // distance along rod centerline from end A to the waterplane - else if ((r[N][2] < zeta_i) && (r[0][2] > zeta_i)) // check if it's crossing the water plane but upside down - h0 = -(zeta_i - r[0][2])/q[2]; // negative distance along rod centerline from end A to the waterplane - else - h0 = 0.0; // fully unsubmerged case (ever applicable?) + // get approximate location of waterline crossing along Rod axis (note: + // negative h0 indicates end A is above end B, and measures -distance from + // end A to waterline crossing) + if ((r[0][2] < zeta_i) && (r[N][2] < zeta_i)) // fully submerged case + h0 = UnstrLen; + else if ((r[0][2] < zeta_i) && + (r[N][2] > zeta_i)) // check if it's crossing the water plane + // (should also add some limits to avoid + // near-horizontals at some point) + h0 = (zeta_i - r[0][2]) / + q[2]; // distance along rod centerline from end A to the waterplane + else if ((r[N][2] < zeta_i) && + (r[0][2] > + zeta_i)) // check if it's crossing the water plane but upside down + h0 = -(zeta_i - r[0][2]) / + q[2]; // negative distance along rod centerline from end A to the + // waterplane + else + h0 = 0.0; // fully unsubmerged case (ever applicable?) Mext = vec::Zero(); @@ -964,15 +987,14 @@ Rod::doRHS() // get scalar for submerged portion - if (h0 < 0.0) { // Upside down case + if (h0 < 0.0) { // Upside down case if (Lsum + dL >= h0) // if fully submerged VOF0 = 1.0; else if (Lsum > h0) // if partially below waterline VOF0 = (h0 - Lsum) / dL; else // must be out of water VOF0 = 0.0; - } - else { + } else { if (Lsum + dL <= h0) // if fully submerged VOF0 = 1.0; else if (Lsum < h0) // if partially below waterline @@ -1320,11 +1342,11 @@ Rod::doRHS() // 0.25 * mass * r * r + (1.0 / 3.0) * mass * UnstrLen * UnstrLen; // // From Hydrodyn theory paper per segment I_r real I_r_correction = - mass * ((r * r) / 4 - (UnstrLen * UnstrLen) / (6 * N * N)); + mass * ((r * r) / 4 - (UnstrLen * UnstrLen) / (6 * N * N)); - Imat_l(0, 0) = I_r_correction; - Imat_l(1, 1) = I_r_correction; - Imat_l(2, 2) = I_l; + Imat_l(0, 0) = I_r_correction; + Imat_l(1, 1) = I_r_correction; + Imat_l(2, 2) = I_l; } // get rotation matrix to put things in global rather than rod-axis diff --git a/source/Rod.h b/source/Rod.h index 75a5e198..ac99f9db 100644 --- a/source/Rod.h +++ b/source/Rod.h @@ -40,101 +40,106 @@ extern "C" { #endif - /** @addtogroup new_c_api - * @{ - */ - - /// A mooring line instance - typedef struct __MoorDynRod* MoorDynRod; - - /** @brief Get the line identifier - * @param l The Moordyn rod - * @param id The output id - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetRodID(MoorDynRod l, int* id); - - /** @brief Get the line type - * @param l The Moordyn rod - * @param t The output type - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetRodType(MoorDynRod l, int* t); - - /** @brief Get the net force acting on the rod, as well as the moment at - * end point A if the node is not pinned - * @param l The Moordyn rod - * @param f The output force - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetRodForce(MoorDynRod l, double f[6]); - - /** @brief Get the total rod mass matrix - * @param l The Moordyn rod - * @param m The output mass matrix - * @return MOORDYN_INVALID_VALUE if a NULL point is provided, - * MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetRodM(MoorDynRod l, double m[6][6]); - - /** @brief Get the line number of segments - * - * The number of nodes is equal to this value plus 1 - * @param l The Moordyn rod - * @param n The output number of nodes - * @return MOORDYN_INVALID_VALUE if a NULL line is provided, MOORDYN_SUCCESS - * otherwise - */ - int DECLDIR MoorDyn_GetRodN(MoorDynRod l, unsigned int* n); - - /** @brief Get the line number of nodes - * @param l The Moordyn rod - * @param n The output number of nodes - * @return MOORDYN_INVALID_VALUE if a NULL line is provided, MOORDYN_SUCCESS - * otherwise - * @see MoorDyn_GetRodN() - */ - int DECLDIR MoorDyn_GetRodNumberNodes(MoorDynRod l, unsigned int* n); - - /** @brief Get a rod node position - * @param l The Moordyn rod - * @param i The node index - * @param pos The output node position - * @return MOORDYN_INVALID_VALUE if a NULL line is provided or if the node - * index is bigger than the number of segments, MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetRodNodePos(MoorDynRod l, - unsigned int i, - double pos[3]); - - /** @brief Get a rod node velocity - * @param l The Moordyn rod - * @param i The node index - * @param vel The output node velocity - * @return MOORDYN_INVALID_VALUE if a NULL line is provided or if the node - * index is bigger than the number of segments, MOORDYN_SUCCESS otherwise - */ - int DECLDIR MoorDyn_GetRodNodeVel(MoorDynRod l, - unsigned int i, - double vel[3]); - - /** @brief Save the line to a VTK (.vtp) file - * @param l The Moordyn rod - * @param filename The output maximum tension module - * @return MOORDYN_SUCCESS if the file is correctly written, an error code - * otherwise - * @note If MoorDyn has been built without VTK support, this function will - * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available - * anyway - */ - int DECLDIR MoorDyn_SaveRodVTK(MoorDynRod l, const char* filename); - - /** - * @} - */ +/** @addtogroup new_c_api + * @{ + */ + +/// A mooring line instance +typedef struct __MoorDynRod* MoorDynRod; + +/** @brief Get the line identifier + * @param l The Moordyn rod + * @param id The output id + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetRodID(MoorDynRod l, int* id); + +/** @brief Get the line type + * @param l The Moordyn rod + * @param t The output type + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetRodType(MoorDynRod l, int* t); + +/** @brief Get the net force acting on the rod, as well as the moment at + * end point A if the node is not pinned + * @param l The Moordyn rod + * @param f The output force + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetRodForce(MoorDynRod l, double f[6]); + +/** @brief Get the total rod mass matrix + * @param l The Moordyn rod + * @param m The output mass matrix + * @return MOORDYN_INVALID_VALUE if a NULL point is provided, + * MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetRodM(MoorDynRod l, double m[6][6]); + +/** @brief Get the line number of segments + * + * The number of nodes is equal to this value plus 1 + * @param l The Moordyn rod + * @param n The output number of nodes + * @return MOORDYN_INVALID_VALUE if a NULL line is provided, MOORDYN_SUCCESS + * otherwise + */ +int DECLDIR +MoorDyn_GetRodN(MoorDynRod l, unsigned int* n); + +/** @brief Get the line number of nodes + * @param l The Moordyn rod + * @param n The output number of nodes + * @return MOORDYN_INVALID_VALUE if a NULL line is provided, MOORDYN_SUCCESS + * otherwise + * @see MoorDyn_GetRodN() + */ +int DECLDIR +MoorDyn_GetRodNumberNodes(MoorDynRod l, unsigned int* n); + +/** @brief Get a rod node position + * @param l The Moordyn rod + * @param i The node index + * @param pos The output node position + * @return MOORDYN_INVALID_VALUE if a NULL line is provided or if the node + * index is bigger than the number of segments, MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetRodNodePos(MoorDynRod l, unsigned int i, double pos[3]); + +/** @brief Get a rod node velocity + * @param l The Moordyn rod + * @param i The node index + * @param vel The output node velocity + * @return MOORDYN_INVALID_VALUE if a NULL line is provided or if the node + * index is bigger than the number of segments, MOORDYN_SUCCESS otherwise + */ +int DECLDIR +MoorDyn_GetRodNodeVel(MoorDynRod l, unsigned int i, double vel[3]); + +/** @brief Save the line to a VTK (.vtp) file + * @param l The Moordyn rod + * @param filename The output maximum tension module + * @return MOORDYN_SUCCESS if the file is correctly written, an error code + * otherwise + * @note If MoorDyn has been built without VTK support, this function will + * return a MOORDYN_NON_IMPLEMENTED error, but it will be still available + * anyway + */ +int DECLDIR +MoorDyn_SaveRodVTK(MoorDynRod l, const char* filename); + +/** + * @} + */ #ifdef __cplusplus } diff --git a/source/Rod.hpp b/source/Rod.hpp index a9c40edf..9094aa55 100644 --- a/source/Rod.hpp +++ b/source/Rod.hpp @@ -63,7 +63,9 @@ class Line; * Each end point of the rod can be fixed or pinned to another object, let free * or control it externally */ -class DECLDIR Rod final : public Instance, public SuperCFL +class DECLDIR Rod final + : public Instance + , public SuperCFL { public: /** @brief Costructor @@ -192,7 +194,8 @@ class DECLDIR Rod final : public Instance, public SuperCFL // wave things /// VOF scalar for each segment (1 = fully submerged, 0 = out of water) - std::vector VOF; // TODO: This doesn't need to be a vector, can be a double reused for each node + std::vector VOF; // TODO: This doesn't need to be a vector, + // can be a double reused for each node /// instantaneous axial submerged length [m] real h0; @@ -559,10 +562,7 @@ class DECLDIR Rod final : public Instance, public SuperCFL * @param rBody The body position * @param vBody The body velocity */ - void getNetForceAndMass(vec6& Fnet_out, - mat6& M_out, - vec rBody, - vec6 vBody); + void getNetForceAndMass(vec6& Fnet_out, mat6& M_out, vec rBody, vec6 vBody); /** @brief Calculate the force and mass contributions of the point on the * parent body @@ -650,8 +650,6 @@ class DECLDIR Rod final : public Instance, public SuperCFL } return F; } - - }; } // ::moordyn diff --git a/source/Seafloor.h b/source/Seafloor.h index 205f7880..bfe72115 100644 --- a/source/Seafloor.h +++ b/source/Seafloor.h @@ -10,41 +10,40 @@ extern "C" { #endif - /// A 3D Seafloor instance - typedef struct __MoorDynSeafloor* MoorDynSeafloor; - - /** @brief Get the depth of the seafloor at some x and y - * @param seafloor The Seafloor instance - * @param x The x coordinate - * @param y The y coordinate - * @param depth The output seafloor depth at that (x, y) point - * @return 0 If the data is correctly set, an error code otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetDepthAt(MoorDynSeafloor seafloor, - double x, - double y, - double* depth); - - /** @brief Get the average of depth of the seafloor - * This value is calculated as the average value of every depth point. - * If the rectilinear grid is not even, this average may not be the actual - * average depth of the surface the data describes. - * @param seafloor The Seafloor instance - * @param avgDepth The output average seafloor depth - * @return 0 If the data is correctly set, an error code otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetAverageDepth(MoorDynSeafloor seafloor, - double* avgDepth); - - /** @brief The depth of the seafloor at the shallowest point - * @param seafloor The Seafloor instance - * @param minDepth The output minimum seafloor depth - * @return 0 If the data is correctly set, an error code otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetMinDepth(MoorDynSeafloor seafloor, double* minDepth); +/// A 3D Seafloor instance +typedef struct __MoorDynSeafloor* MoorDynSeafloor; + +/** @brief Get the depth of the seafloor at some x and y + * @param seafloor The Seafloor instance + * @param x The x coordinate + * @param y The y coordinate + * @param depth The output seafloor depth at that (x, y) point + * @return 0 If the data is correctly set, an error code otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetDepthAt(MoorDynSeafloor seafloor, double x, double y, double* depth); + +/** @brief Get the average of depth of the seafloor + * This value is calculated as the average value of every depth point. + * If the rectilinear grid is not even, this average may not be the actual + * average depth of the surface the data describes. + * @param seafloor The Seafloor instance + * @param avgDepth The output average seafloor depth + * @return 0 If the data is correctly set, an error code otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetAverageDepth(MoorDynSeafloor seafloor, double* avgDepth); + +/** @brief The depth of the seafloor at the shallowest point + * @param seafloor The Seafloor instance + * @param minDepth The output minimum seafloor depth + * @return 0 If the data is correctly set, an error code otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetMinDepth(MoorDynSeafloor seafloor, double* minDepth); #ifdef __cplusplus } diff --git a/source/State.cpp b/source/State.cpp index 2f149df6..2241f212 100644 --- a/source/State.cpp +++ b/source/State.cpp @@ -39,19 +39,24 @@ namespace state { void State::addInstance(moordyn::Instance* obj) { - if (std::find(_objs.begin(), _objs.end(), obj) != _objs.end()) { // check that this quieried object is not in the _objs list already + if (std::find(_objs.begin(), _objs.end(), obj) != + _objs.end()) { // check that this quieried object is not in the _objs + // list already throw moordyn::invalid_value_error("Repeated instance"); } - StateVar new_var(_objs.size() + 1); // make a new Statevar with space for the new instance + StateVar new_var(_objs.size() + + 1); // make a new Statevar with space for the new instance for (size_t i = 0; i < _objs.size(); i++) { new_var(i) = _var(i); // copy over _var values to the new array } - InstanceStateVar obj_var(obj->stateN(), obj->stateDims()); // create a N x Dims array of states - obj_var.setZero(); // initialize the array to zeros - new_var(_objs.size()) = obj_var; // place the array at the end of the _var array - _var = new_var; // same as above - _objs.push_back(obj); // add the object to the end of the _objs list - _indexes = make_indexes(); // update indicies + InstanceStateVar obj_var( + obj->stateN(), obj->stateDims()); // create a N x Dims array of states + obj_var.setZero(); // initialize the array to zeros + new_var(_objs.size()) = + obj_var; // place the array at the end of the _var array + _var = new_var; // same as above + _objs.push_back(obj); // add the object to the end of the _objs list + _indexes = make_indexes(); // update indicies } unsigned int diff --git a/source/State.hpp b/source/State.hpp index 1be9dfba..2aa673cf 100644 --- a/source/State.hpp +++ b/source/State.hpp @@ -57,7 +57,7 @@ class DECLDIR State final : public moordyn::io::IO * @param log The logger */ State(moordyn::Log* log) - : moordyn::io::IO(log) + : moordyn::io::IO(log) { } @@ -65,7 +65,7 @@ class DECLDIR State final : public moordyn::io::IO * @param rhs State to copy */ State(const State& rhs) - : moordyn::io::IO(rhs._log) + : moordyn::io::IO(rhs._log) { copy(rhs); } @@ -122,7 +122,7 @@ class DECLDIR State final : public moordyn::io::IO } inline const std::vector indexer( - std::vector obj) + std::vector obj) { std::vector slcs; slcs.reserve(obj.size()); @@ -182,7 +182,8 @@ class DECLDIR State final : public moordyn::io::IO * This method builds the moordyn::State::indexes map * @return the Total number of dofs */ - inline std::vector make_indexes() { + inline std::vector make_indexes() + { std::vector indexes; for (size_t i = 0; i < _objs.size(); i++) { size_t key = _objs[i]->id(); @@ -208,7 +209,8 @@ class DECLDIR State final : public moordyn::io::IO } // ::moordyn -inline moordyn::StateVar operator*(moordyn::StateVarView v, moordyn::real f) +inline moordyn::StateVar +operator*(moordyn::StateVarView v, moordyn::real f) { moordyn::StateVar out; out.resize(v.rows()); @@ -219,12 +221,14 @@ inline moordyn::StateVar operator*(moordyn::StateVarView v, moordyn::real f) return out; } -inline moordyn::StateVar operator*(moordyn::real f, moordyn::StateVarView v) +inline moordyn::StateVar +operator*(moordyn::real f, moordyn::StateVarView v) { return v * f; } -inline moordyn::StateVar operator*(moordyn::StateVar v, moordyn::real f) +inline moordyn::StateVar +operator*(moordyn::StateVar v, moordyn::real f) { moordyn::StateVar out; out.resize(v.rows()); @@ -235,7 +239,8 @@ inline moordyn::StateVar operator*(moordyn::StateVar v, moordyn::real f) return out; } -inline moordyn::StateVar operator*(moordyn::real f, moordyn::StateVar v) +inline moordyn::StateVar +operator*(moordyn::real f, moordyn::StateVar v) { return v.topLeftCorner(v.rows(), v.cols()) * f; } diff --git a/source/Time.cpp b/source/Time.cpp index 27884f9a..dd928b6d 100644 --- a/source/Time.cpp +++ b/source/Time.cpp @@ -72,8 +72,7 @@ SchemeBase::Update(real t_local, unsigned int substep) for (unsigned int i = 0; i < rods.size(); i++) { rods[i]->setTime(this->t); - if ((rods[i]->type != Rod::PINNED) && - (rods[i]->type != Rod::CPLDPIN) && + if ((rods[i]->type != Rod::PINNED) && (rods[i]->type != Rod::CPLDPIN) && (rods[i]->type != Rod::FREE)) continue; rods[i]->setState(AS_STATE(_r[substep])->get(rods[i])); @@ -123,7 +122,8 @@ SchemeBase::CalcStateDeriv(unsigned int substep) for (unsigned int i = 0; i < bodies.size(); i++) { if (!_calc_mask.bodies[i]) continue; - if ((bodies[i]->type != Body::FREE) && (bodies[i]->type != Body::CPLDPIN)) + if ((bodies[i]->type != Body::FREE) && + (bodies[i]->type != Body::CPLDPIN)) continue; bodies[i]->getStateDeriv(AS_STATE(_rd[substep])->get(bodies[i])); } @@ -179,7 +179,6 @@ StationaryScheme::Step(real& dt) auto r1 = r(1)->get(); auto drdt0 = rd(0)->get(); - Update(0.0, 0); CalcStateDeriv(0); const real error_prev = _error; @@ -188,8 +187,7 @@ StationaryScheme::Step(real& dt) if (error_prev >= _error) { // Let's try to boost the convergence _booster *= STATIONARY_BOOSTING; - } - else if (error_prev < _error) { + } else if (error_prev < _error) { // We clearly overshot, so let's relax the solution and reduce the // boosting _booster /= STATIONARY_BOOSTING; @@ -228,7 +226,8 @@ StationaryScheme::Step(real& dt) * @param r The base quaternion on top of which the derivative is applied * @param rd The vec6 derivative */ -vec7 integrateVec6AsVec7(const moordyn::vec7& r, const moordyn::vec6& rd) +vec7 +integrateVec6AsVec7(const moordyn::vec7& r, const moordyn::vec6& rd) { XYZQuat r7 = XYZQuat::fromVec7(r), v7; v7.pos = rd.head<3>(); @@ -236,25 +235,27 @@ vec7 integrateVec6AsVec7(const moordyn::vec7& r, const moordyn::vec6& rd) return v7.toVec7(); } -#define MAKE_STATIONARY_VEC3(obj) { \ - auto drdt = rd(id)->get(obj); \ - for (unsigned int j = 0; j < drdt.rows(); j++) { \ - auto acc = drdt.row(j).segment<3>(3); \ - _error += acc.norm(); \ - drdt.row(j).head<3>() = 0.5 * dt * acc; \ - acc = vec3::Zero(); \ - } \ -} - -#define MAKE_STATIONARY_QUAT(obj) { \ - const moordyn::vec7 pos = r(i)->get(obj).row(0).head<7>(); \ - auto drdt = rd(id)->get(obj).row(0); \ - auto vel = drdt.head<7>(); \ - auto acc = drdt.tail<6>(); \ - _error += acc.head<3>().norm(); \ - vel = integrateVec6AsVec7(pos, 0.5 * dt * acc); \ - acc = vec6::Zero(); \ -} +#define MAKE_STATIONARY_VEC3(obj) \ + { \ + auto drdt = rd(id)->get(obj); \ + for (unsigned int j = 0; j < drdt.rows(); j++) { \ + auto acc = drdt.row(j).segment<3>(3); \ + _error += acc.norm(); \ + drdt.row(j).head<3>() = 0.5 * dt * acc; \ + acc = vec3::Zero(); \ + } \ + } + +#define MAKE_STATIONARY_QUAT(obj) \ + { \ + const moordyn::vec7 pos = r(i)->get(obj).row(0).head<7>(); \ + auto drdt = rd(id)->get(obj).row(0); \ + auto vel = drdt.head<7>(); \ + auto acc = drdt.tail<6>(); \ + _error += acc.head<3>().norm(); \ + vel = integrateVec6AsVec7(pos, 0.5 * dt * acc); \ + acc = vec6::Zero(); \ + } void StationaryScheme::MakeStationary(real& dt, unsigned int i, unsigned int id) @@ -491,14 +492,14 @@ RK4Scheme::Step(real& dt) r1 = r0 + 0.5 * dt * drdt1; Update(0.5 * dt, 1); CalcStateDeriv(2); - + // k4 t += 0.5 * dt; r2 = r0 + dt * drdt2; - + Update(dt, 2); CalcStateDeriv(3); - + // Apply r0 += (dt / 6.0) * (drdt0 + drdt3) + (dt / 3.0) * (drdt1 + drdt2); @@ -549,25 +550,19 @@ ABScheme::Step(real& dt) r0 += dt * drdt0; break; case 1: - r0 += 1.5 * drdt0 + - 0.5 * drdt1; + r0 += 1.5 * drdt0 + 0.5 * drdt1; break; case 2: - r0 += 23.0 / 12.0 * dt * drdt0 + - 4.0 / 3.0 * dt * drdt1 + + r0 += 23.0 / 12.0 * dt * drdt0 + 4.0 / 3.0 * dt * drdt1 + 5.0 / 12.0 * dt * drdt2; break; case 3: - r0 += 55.0 / 24.0 * dt * drdt0 + - 59.0 / 24.0 * dt * drdt1 + - 37.0 / 24.0 * dt * drdt2 + - 3.0 / 8.0 * dt * drdt3; + r0 += 55.0 / 24.0 * dt * drdt0 + 59.0 / 24.0 * dt * drdt1 + + 37.0 / 24.0 * dt * drdt2 + 3.0 / 8.0 * dt * drdt3; break; default: - r0 += 1901.0 / 720.0 * dt * drdt0 + - 1387.0 / 360.0 * dt * drdt1 + - 109.0 / 360.0 * dt * drdt2 + - 637.0 / 24.0 * dt * drdt3 + + r0 += 1901.0 / 720.0 * dt * drdt0 + 1387.0 / 360.0 * dt * drdt1 + + 109.0 / 360.0 * dt * drdt2 + 637.0 / 24.0 * dt * drdt3 + 251.0 / 720.0 * dt * drdt4; } @@ -581,10 +576,10 @@ template ImplicitSchemeBase::ImplicitSchemeBase(moordyn::Log* log, WavesRef waves, unsigned int iters) - : SchemeBase(log, waves) - , _iters(iters) - , _c0(0.9) - , _c1(0.0) + : SchemeBase(log, waves) + , _iters(iters) + , _c0(0.9) + , _c1(0.0) { } @@ -592,9 +587,9 @@ template real ImplicitSchemeBase::Relax(const unsigned int& iter) { - const real x = 4. * ((iter + 1.) / _iters - 0.5); // [-1, 1] - const real y0 = 1. / _iters; // (0, 1] - const real y1 = 0.5 * (tanh(x) + 1.); // (0, 1) + const real x = 4. * ((iter + 1.) / _iters - 0.5); // [-1, 1] + const real y0 = 1. / _iters; // (0, 1] + const real y1 = 0.5 * (tanh(x) + 1.); // (0, 1) return c0() * (1. - y0) + c1() * (1. - y1); } @@ -650,8 +645,8 @@ ImplicitNewmarkScheme::ImplicitNewmarkScheme(moordyn::Log* log, , _beta(beta) { stringstream s; - s << "gamma=" << gamma << ",beta=" << beta << " implicit Newmark (" - << iters << " iterations)"; + s << "gamma=" << gamma << ",beta=" << beta << " implicit Newmark (" << iters + << " iterations)"; name = s.str(); c0(0.9); c1(0.15); @@ -693,35 +688,37 @@ ImplicitNewmarkScheme::Step(real& dt) SchemeBase::Step(dt); } -#define MAKE_NEWMARK_VEC3(obj) { \ - auto r0 = r(0)->get(obj); \ - auto r1 = r(1)->get(obj); \ - auto drdt0 = rd(0)->get(obj); \ - auto drdt1 = rd(1)->get(obj); \ - InstanceStateVar acc = (1.0 - _gamma) * drdt0.middleCols<3>(3) + \ - _gamma * drdt1.middleCols<3>(3); \ - InstanceStateVar acc_beta = (0.5 - _beta) * drdt0.middleCols<3>(3) + \ - _beta * drdt1.middleCols<3>(3); \ - InstanceStateVar vel = drdt0.leftCols<3>() + dt * acc_beta; \ - r1.leftCols<3>() = r0.leftCols<3>() + vel * dt; \ - r1.middleCols<3>(3) = r0.middleCols<3>(3) + acc * dt; \ -} - -#define MAKE_NEWMARK_QUAT(obj) { \ - auto r0 = r(0)->get(obj).row(0); \ - auto r1 = r(1)->get(obj).row(0); \ - auto drdt0 = rd(0)->get(obj).row(0); \ - auto drdt1 = rd(1)->get(obj).row(0); \ - const vec6 acc = (1.0 - _gamma) * drdt0.tail<6>() + \ - _gamma * drdt1.tail<6>(); \ - const vec6 acc_beta = (1.0 - _beta) * drdt0.tail<6>() + \ - _beta * drdt1.tail<6>(); \ - const vec6 vel = \ - XYZQuat::fromVec7(drdt0.head<7>()).toVec6() + dt * acc_beta; \ - const vec7 pos = r0.head<7>(); \ - r1.head<7>() = pos + integrateVec6AsVec7(pos, dt * vel); \ - r1.tail<6>() = vec6(r0.tail<6>()) + acc * dt; \ -} +#define MAKE_NEWMARK_VEC3(obj) \ + { \ + auto r0 = r(0)->get(obj); \ + auto r1 = r(1)->get(obj); \ + auto drdt0 = rd(0)->get(obj); \ + auto drdt1 = rd(1)->get(obj); \ + InstanceStateVar acc = (1.0 - _gamma) * drdt0.middleCols<3>(3) + \ + _gamma * drdt1.middleCols<3>(3); \ + InstanceStateVar acc_beta = (0.5 - _beta) * drdt0.middleCols<3>(3) + \ + _beta * drdt1.middleCols<3>(3); \ + InstanceStateVar vel = drdt0.leftCols<3>() + dt * acc_beta; \ + r1.leftCols<3>() = r0.leftCols<3>() + vel * dt; \ + r1.middleCols<3>(3) = r0.middleCols<3>(3) + acc * dt; \ + } + +#define MAKE_NEWMARK_QUAT(obj) \ + { \ + auto r0 = r(0)->get(obj).row(0); \ + auto r1 = r(1)->get(obj).row(0); \ + auto drdt0 = rd(0)->get(obj).row(0); \ + auto drdt1 = rd(1)->get(obj).row(0); \ + const vec6 acc = \ + (1.0 - _gamma) * drdt0.tail<6>() + _gamma * drdt1.tail<6>(); \ + const vec6 acc_beta = \ + (1.0 - _beta) * drdt0.tail<6>() + _beta * drdt1.tail<6>(); \ + const vec6 vel = \ + XYZQuat::fromVec7(drdt0.head<7>()).toVec6() + dt * acc_beta; \ + const vec7 pos = r0.head<7>(); \ + r1.head<7>() = pos + integrateVec6AsVec7(pos, dt * vel); \ + r1.tail<6>() = vec6(r0.tail<6>()) + acc * dt; \ + } void ImplicitNewmarkScheme::MakeNewmark(const real& dt) @@ -754,8 +751,7 @@ ImplicitWilsonScheme::ImplicitWilsonScheme(moordyn::Log* log, , _theta(theta) { stringstream s; - s << "theta=" << theta << " implicit Wilson (" - << iters << " iterations)"; + s << "theta=" << theta << " implicit Wilson (" << iters << " iterations)"; name = s.str(); c0(0.015); c1(0.000); @@ -794,35 +790,38 @@ ImplicitWilsonScheme::Step(real& dt) SchemeBase::Step(dt); } -#define MAKE_WILSON_VEC3(obj) { \ - auto r0 = r(0)->get(obj); \ - auto r1 = r(1)->get(obj); \ - auto drdt0 = rd(0)->get(obj); \ - auto drdt1 = rd(1)->get(obj); \ - InstanceStateVar acc = (1 - 0.5 * f) * drdt0.middleCols<3>(3) + \ - 0.5 * f * drdt1.middleCols<3>(3); \ - InstanceStateVar acc_tau = (1 - 1.0 / 3.0 * f) * drdt0.middleCols<3>(3) + \ - 1.0 / 3.0 * f * drdt1.middleCols<3>(3); \ - InstanceStateVar vel = drdt0.leftCols<3>() + 0.5 * dt * acc_tau; \ - r1.leftCols<3>() = r0.leftCols<3>() + vel * tau; \ - r1.middleCols<3>(3) = r0.middleCols<3>(3) + acc * tau; \ -} - -#define MAKE_WILSON_QUAT(obj) { \ - auto r0 = r(0)->get(obj).row(0); \ - auto r1 = r(1)->get(obj).row(0); \ - auto drdt0 = rd(0)->get(obj).row(0); \ - auto drdt1 = rd(1)->get(obj).row(0); \ - const vec6 acc = (1 - 0.5 * f) * drdt0.tail<6>() + \ - 0.5 * f * drdt1.tail<6>(); \ - const vec6 acc_tau = (1 - 1.0 / 3.0 * f) * drdt0.tail<6>() + \ - 1.0 / 3.0 * f * drdt1.tail<6>(); \ - const vec6 vel = \ - XYZQuat::fromVec7(drdt0.head<7>()).toVec6() + 0.5 * dt * acc_tau; \ - const vec7 pos = r0.head<7>(); \ - r1.head<7>() = pos + integrateVec6AsVec7(pos, tau * vel); \ - r1.tail<6>() = vec6(r0.tail<6>()) + acc * tau; \ -} +#define MAKE_WILSON_VEC3(obj) \ + { \ + auto r0 = r(0)->get(obj); \ + auto r1 = r(1)->get(obj); \ + auto drdt0 = rd(0)->get(obj); \ + auto drdt1 = rd(1)->get(obj); \ + InstanceStateVar acc = (1 - 0.5 * f) * drdt0.middleCols<3>(3) + \ + 0.5 * f * drdt1.middleCols<3>(3); \ + InstanceStateVar acc_tau = \ + (1 - 1.0 / 3.0 * f) * drdt0.middleCols<3>(3) + \ + 1.0 / 3.0 * f * drdt1.middleCols<3>(3); \ + InstanceStateVar vel = drdt0.leftCols<3>() + 0.5 * dt * acc_tau; \ + r1.leftCols<3>() = r0.leftCols<3>() + vel * tau; \ + r1.middleCols<3>(3) = r0.middleCols<3>(3) + acc * tau; \ + } + +#define MAKE_WILSON_QUAT(obj) \ + { \ + auto r0 = r(0)->get(obj).row(0); \ + auto r1 = r(1)->get(obj).row(0); \ + auto drdt0 = rd(0)->get(obj).row(0); \ + auto drdt1 = rd(1)->get(obj).row(0); \ + const vec6 acc = \ + (1 - 0.5 * f) * drdt0.tail<6>() + 0.5 * f * drdt1.tail<6>(); \ + const vec6 acc_tau = (1 - 1.0 / 3.0 * f) * drdt0.tail<6>() + \ + 1.0 / 3.0 * f * drdt1.tail<6>(); \ + const vec6 vel = \ + XYZQuat::fromVec7(drdt0.head<7>()).toVec6() + 0.5 * dt * acc_tau; \ + const vec7 pos = r0.head<7>(); \ + r1.head<7>() = pos + integrateVec6AsVec7(pos, tau * vel); \ + r1.tail<6>() = vec6(r0.tail<6>()) + acc * tau; \ + } void ImplicitWilsonScheme::MakeWilson(const real& tau, const real& dt) @@ -900,8 +899,8 @@ create_time_scheme(const std::string& name, out = new ImplicitNewmarkScheme(log, waves, iters, 0.5, 0.25); } catch (std::invalid_argument) { stringstream s; - s << "Invalid Average Constant Acceleration name format '" - << name << "'"; + s << "Invalid Average Constant Acceleration name format '" << name + << "'"; throw moordyn::invalid_value_error(s.str().c_str()); } } else if (str::startswith(str::lower(name), "wilson")) { @@ -910,8 +909,7 @@ create_time_scheme(const std::string& name, out = new ImplicitWilsonScheme(log, waves, iters, 1.37); } catch (std::invalid_argument) { stringstream s; - s << "Invalid Wilson name format '" - << name << "'"; + s << "Invalid Wilson name format '" << name << "'"; throw moordyn::invalid_value_error(s.str().c_str()); } } else { diff --git a/source/Time.hpp b/source/Time.hpp index 7f81c2d6..9ef9a27b 100644 --- a/source/Time.hpp +++ b/source/Time.hpp @@ -260,22 +260,22 @@ class Scheme : public io::IO * @param i The index of the state variable to take * @return The state variable */ - virtual moordyn::state::State GetState(unsigned int i=0) = 0; + virtual moordyn::state::State GetState(unsigned int i = 0) = 0; /** @brief Resume the simulation from the stationary solution * @param state The stationary solution * @param i The index of the state variable to take */ inline virtual void SetState(const moordyn::state::State& state, - unsigned int i=0) - {}; + unsigned int i = 0) {}; /** @brief Save the system state on a file * @param filepath The output file path * @param i The index of the state variable to serialize * @see ::SerializeState() */ - inline virtual void SaveState(const std::string filepath, unsigned int i=0) + inline virtual void SaveState(const std::string filepath, + unsigned int i = 0) { } @@ -283,7 +283,8 @@ class Scheme : public io::IO * @param filepath The output file path * @param i The index of the state variable to overwrite */ - inline virtual void LoadState(const std::string filepath, unsigned int i=0) + inline virtual void LoadState(const std::string filepath, + unsigned int i = 0) { } @@ -403,7 +404,7 @@ class SchemeBase : public Scheme // // Add the mask value // _calc_mask.lines.push_back(true); // } - + /** @brief Remove a line * @param obj The line * @return The index of the removed entity @@ -629,21 +630,17 @@ class SchemeBase : public Scheme * equal than the number of states * @{ */ - inline state::State* r(unsigned int i=0) + inline state::State* r(unsigned int i = 0) { if (i >= NSTATE) { LOGERR << "State " << i << " cannot be got on a '" << name - << "' scheme that has " << NSTATE << "states" - << endl; + << "' scheme that has " << NSTATE << "states" << endl; throw moordyn::invalid_value_error("Invalid state"); } return _r[i]; } - inline state::State GetState(unsigned int i=0) - { - return *r(i); - } + inline state::State GetState(unsigned int i = 0) { return *r(i); } /** * @} */ @@ -654,12 +651,11 @@ class SchemeBase : public Scheme * @throws moordyn::invalid_value_error if the @p i index is greater or * equal than the number of states */ - inline virtual void SetState(const state::State& state, unsigned int i=0) + inline virtual void SetState(const state::State& state, unsigned int i = 0) { if (i >= NSTATE) { LOGERR << "State " << i << " cannot be setted on a '" << name - << "' scheme that has " << NSTATE << " states" - << endl; + << "' scheme that has " << NSTATE << " states" << endl; throw moordyn::invalid_value_error("Invalid state"); } *_r[i] = state; @@ -671,13 +667,13 @@ class SchemeBase : public Scheme * @throws moordyn::invalid_value_error if the @p i index is greater or * equal than the number of states */ - inline virtual void SaveState(const std::string filepath, unsigned int i=0) + inline virtual void SaveState(const std::string filepath, + unsigned int i = 0) { auto f = MakeFile(filepath); if (i >= NSTATE) { LOGERR << "State " << i << " cannot be saved on a '" << name - << "' scheme that has " << NSTATE << "states" - << endl; + << "' scheme that has " << NSTATE << "states" << endl; throw moordyn::invalid_value_error("Invalid state"); } std::vector data = AS_STATE(_r[i])->Serialize(); @@ -697,13 +693,13 @@ class SchemeBase : public Scheme * @throws moordyn::mem_error if the expected size of the serialized data * is not met */ - inline virtual void LoadState(const std::string filepath, unsigned int i=0) + inline virtual void LoadState(const std::string filepath, + unsigned int i = 0) { auto [length, data] = LoadFile(filepath); if (i >= NSTATE) { LOGERR << "State " << i << " cannot be loaded on a '" << name - << "' scheme that has " << NSTATE << "states" - << endl; + << "' scheme that has " << NSTATE << "states" << endl; throw moordyn::invalid_value_error("Invalid state"); } const uint64_t* end = AS_STATE(_r[i])->Deserialize(data); @@ -725,12 +721,12 @@ class SchemeBase : public Scheme * @throws moordyn::invalid_value_error if the @p i index is greater or * equal than the number of state derivatives */ - inline state::State* rd(unsigned int i=0) + inline state::State* rd(unsigned int i = 0) { if (i >= NDERIV) { LOGERR << "State derivative " << i << " cannot be got on a '" - << name << "' scheme that has " << NDERIV - << "state derivatives" << endl; + << name << "' scheme that has " << NDERIV + << "state derivatives" << endl; throw moordyn::invalid_value_error("Invalid state derivative"); } return _rd[i]; @@ -840,10 +836,11 @@ class SchemeBase : public Scheme std::shared_ptr waves; /** @brief A mask to determine which entities shall be computed. - * + * * Useful for local time steps */ - typedef struct _mask { + typedef struct _mask + { /// The lines mask std::vector lines; /// The points mask @@ -897,8 +894,13 @@ class StationaryScheme final : public SchemeBase<2, 1> * no matter if the state is a scalar, a vector or a quaternion, it is * considered as a single entry */ - inline size_t NStates() const { - size_t n = bodies.size() + rods.size() + points.size(); // one row (state) per object here. .size() gives the length of the list, i.e. the number of that kind of object + inline size_t NStates() const + { + size_t n = + bodies.size() + rods.size() + + points.size(); // one row (state) per object here. .size() + // gives the length of the list, i.e. the number of + // that kind of object for (size_t i = 0; i < lines.size(); i++) n += lines[i]->stateN(); return n; @@ -913,7 +915,7 @@ class StationaryScheme final : public SchemeBase<2, 1> * @param i The index of the state * @param id The index of the state derivative */ - void MakeStationary(real& dt, unsigned int i=0, unsigned int id=0); + void MakeStationary(real& dt, unsigned int i = 0, unsigned int id = 0); /** The last computed acceleration module * @see DMoorDynStateDt::MakeStationary() @@ -978,7 +980,7 @@ class LocalSchemeBase : public SchemeBase * @param state The stationary solution * @param i The index of the state variable to take */ - inline virtual void SetState(const state::State& state, unsigned int i=0) + inline virtual void SetState(const state::State& state, unsigned int i = 0) { SchemeBase::SetState(state, i); ComputeDt(); @@ -1010,7 +1012,8 @@ class LocalSchemeBase : public SchemeBase /** @brief The timestep of each instance */ - typedef struct _sdeltat { + typedef struct _sdeltat + { /// The lines mask std::vector lines; /// The points mask @@ -1031,11 +1034,11 @@ class LocalSchemeBase : public SchemeBase /** @class LocalEulerScheme Time.hpp * @brief A modification of the 1st order Euler's time scheme, which is * considering different time steps for each instance. - * + * * The local time step of each entity is computed according to the maximum CFL * factor of all entities. Such local time step is indeed an integer times the * time step provided to LocalEulerScheme::Step(). - * + * * Thus, the derivatives recomputation is delayed until those time steps are * fulfilled */ @@ -1212,30 +1215,28 @@ class ABScheme final : public LocalSchemeBase<1, 5> for (unsigned int i = 0; i < lines.size(); i++) { if (!_calc_mask.lines[i]) continue; - AS_STATE(rd(dst))->get(lines[i]) = - AS_STATE(rd(org))->get(lines[i]); + AS_STATE(rd(dst))->get(lines[i]) = AS_STATE(rd(org))->get(lines[i]); } for (unsigned int i = 0; i < points.size(); i++) { if (!_calc_mask.points[i] && (points[i]->type == Point::FREE)) continue; AS_STATE(rd(dst))->get(points[i]) = - AS_STATE(rd(org))->get(points[i]); + AS_STATE(rd(org))->get(points[i]); } for (unsigned int i = 0; i < rods.size(); i++) { if (!_calc_mask.rods[i] && ((rods[i]->type != Rod::FREE) || (rods[i]->type != Rod::PINNED))) continue; - AS_STATE(rd(dst))->get(rods[i]) = - AS_STATE(rd(org))->get(rods[i]); + AS_STATE(rd(dst))->get(rods[i]) = AS_STATE(rd(org))->get(rods[i]); } for (unsigned int i = 0; i < bodies.size(); i++) { if (!_calc_mask.bodies[i] && (bodies[i]->type == Body::FREE)) continue; AS_STATE(rd(dst))->get(bodies[i]) = - AS_STATE(rd(org))->get(bodies[i]); + AS_STATE(rd(org))->get(bodies[i]); } } @@ -1370,10 +1371,10 @@ class ImplicitNewmarkScheme final : public ImplicitSchemeBase<2, 3> * @param beta The beta factor */ ImplicitNewmarkScheme(moordyn::Log* log, - WavesRef waves, - unsigned int iters = 10, - real gamma = 0.5, - real beta = 0.25); + WavesRef waves, + unsigned int iters = 10, + real gamma = 0.5, + real beta = 0.25); /// @brief Destructor ~ImplicitNewmarkScheme() {} @@ -1421,7 +1422,8 @@ class ImplicitNewmarkScheme final : public ImplicitSchemeBase<2, 3> * With the computed acceleration a Taylor series expansion is practised to * integrate. * - * @see https://www.academia.edu/download/59040594/wilson197220190426-49259-kipdfs.pdf + * @see + * https://www.academia.edu/download/59040594/wilson197220190426-49259-kipdfs.pdf */ class ImplicitWilsonScheme final : public ImplicitSchemeBase<2, 3> { diff --git a/source/Util/CFL.hpp b/source/Util/CFL.hpp index e7ce7324..0bba6a4a 100644 --- a/source/Util/CFL.hpp +++ b/source/Util/CFL.hpp @@ -58,7 +58,8 @@ class DECLDIR CFL public: /** @brief Constructor */ - CFL() : _l((std::numeric_limits::max)()) {}; + CFL() + : _l((std::numeric_limits::max)()) {}; /** @brief Destructor */ @@ -68,7 +69,10 @@ class DECLDIR CFL * @param cfl CFL factor * @return The timestep */ - virtual inline real cfl2dt(const real cfl) const { return (std::numeric_limits::max)(); } + virtual inline real cfl2dt(const real cfl) const + { + return (std::numeric_limits::max)(); + } /** @brief Get the CFL factor from a timestep * @param dt Timestep @@ -81,14 +85,20 @@ class DECLDIR CFL * @param v velocity * @return The timestep */ - virtual inline real cfl2dt(const real cfl, const real v) const { return cfl * length() / v; } + virtual inline real cfl2dt(const real cfl, const real v) const + { + return cfl * length() / v; + } /** @brief Get the CFL factor from a timestep and velocity * @param dt Timestep * @param v velocity * @return CFL factor */ - virtual inline real dt2cfl(const real dt, const real v) const { return dt * v / length(); } + virtual inline real dt2cfl(const real dt, const real v) const + { + return dt * v / length(); + } protected: /** @brief Set the characteristic length of the system @@ -137,14 +147,20 @@ class DECLDIR NatFreqCFL : public CFL * @param v velocity * @return The timestep */ - inline real cfl2dt(const real cfl, const real v) const { return CFL::cfl2dt(cfl, v); } + inline real cfl2dt(const real cfl, const real v) const + { + return CFL::cfl2dt(cfl, v); + } /** @brief Get the CFL factor from a timestep and velocity * @param dt Timestep * @param v velocity * @return CFL factor */ - inline real dt2cfl(const real dt, const real v) const { return CFL::dt2cfl(dt, v); } + inline real dt2cfl(const real dt, const real v) const + { + return CFL::dt2cfl(dt, v); + } protected: /** @brief Set the stiffness of the system @@ -206,7 +222,8 @@ class DECLDIR SuperCFL : public CFL * @param cfl CFL factor * @return The timestUtilep */ - inline real cfl2dt(const real cfl) const { + inline real cfl2dt(const real cfl) const + { auto dt = CFL::cfl2dt(cfl); for (auto obj : _children) dt = (std::min)(dt, obj->cfl2dt(cfl)); @@ -217,7 +234,8 @@ class DECLDIR SuperCFL : public CFL * @param dt Timestep * @return CFL factor */ - inline real dt2cfl(const real dt) const { + inline real dt2cfl(const real dt) const + { auto cfl = CFL::dt2cfl(dt); for (auto obj : _children) cfl = (std::max)(cfl, obj->dt2cfl(dt)); @@ -229,7 +247,8 @@ class DECLDIR SuperCFL : public CFL * @param v velocity * @return The timestep */ - inline real cfl2dt(const real cfl, const real v) const{ + inline real cfl2dt(const real cfl, const real v) const + { auto dt = CFL::cfl2dt(cfl, v); for (auto obj : _children) dt = (std::min)(dt, obj->cfl2dt(cfl, v)); @@ -241,7 +260,8 @@ class DECLDIR SuperCFL : public CFL * @param v velocity * @return CFL factor */ - inline real dt2cfl(const real dt, const real v) const { + inline real dt2cfl(const real dt, const real v) const + { auto cfl = CFL::dt2cfl(dt, v); for (auto obj : _children) cfl = (std::max)(cfl, obj->dt2cfl(dt, v)); @@ -257,7 +277,8 @@ class DECLDIR SuperCFL : public CFL /** @brief Remove a child * @param c child */ - inline void RemoveChild(CFL* c) { + inline void RemoveChild(CFL* c) + { _children.erase(std::remove(_children.begin(), _children.end(), c), _children.end()); } diff --git a/source/Waves.cpp b/source/Waves.cpp index 1fbc4da0..20a208e3 100644 --- a/source/Waves.cpp +++ b/source/Waves.cpp @@ -300,8 +300,9 @@ Waves::setup(EnvCondRef env_in, << " read in dynamic current profile, node approach " << " (current_profile_dynamic.txt)" << endl; else if (current_mode == waves::CURRENTS_4D) - LOGDBG << " Current only: option 4D - read in current profile, grid " - << " approach (current_profile_4d.txt" << endl; + LOGDBG + << " Current only: option 4D - read in current profile, grid " + << " approach (current_profile_4d.txt" << endl; else { LOGDBG << " Invalid current input settings (must be 0-4)" << endl; throw moordyn::invalid_value_error("Invalid settings"); @@ -315,29 +316,30 @@ Waves::setup(EnvCondRef env_in, << " set from inputted wave elevation FFT, grid approach " << " (NOT IMPLEMENTED YET)" << endl; else if (wave_mode == waves::WAVES_GRID) - LOGDBG - << " Waves only: option 3 - " - << " set from inputted wave elevation time series, grid approach" - << endl; + LOGDBG << " Waves only: option 3 - " + << " set from inputted wave elevation time series, grid " + "approach" + << endl; else if (wave_mode == waves::WAVES_FFT_GRID) LOGDBG << " Waves only: option TBD4 - " << " set from inputted wave elevation FFT, node approach " << " (NOT IMPLEMENTED YET)" << endl; else if (wave_mode == waves::WAVES_NODE) - LOGDBG - << " Waves only: option TBD5 - " - << " set from inputted wave elevation time series, node approach" - << endl; + LOGDBG << " Waves only: option TBD5 - " + << " set from inputted wave elevation time series, node " + "approach" + << endl; else if (wave_mode == waves::WAVES_KIN) LOGDBG << " Waves only: option TBD6 - " << " set from inputted velocity, acceleration, and wave " " elevation grid data (TBD)" << endl; else if (wave_mode == waves::WAVES_SUM_COMPONENTS_NODE) - LOGDBG << " Waves only: option 7 - " - << " set from inputted wave spectrum, computed at nodes on " - " update " - << endl; + LOGDBG + << " Waves only: option 7 - " + << " set from inputted wave spectrum, computed at nodes on " + " update " + << endl; else { LOGDBG << " Invald wave kinematics input settings (must be 0-7)" << endl; @@ -549,7 +551,8 @@ Waves::addBody(moordyn::Body* body) void Waves::addPoint(moordyn::Point* point) { - if (point->pointId == static_cast(nodeKin.points.structures.size())) { + if (point->pointId == + static_cast(nodeKin.points.structures.size())) { auto num_nodes = 1; genericAdd(point, num_nodes, nodeKin.points); // TODO - only do this when needed, see comment in addLIne diff --git a/source/Waves.h b/source/Waves.h index 3747dc81..e695ec2d 100644 --- a/source/Waves.h +++ b/source/Waves.h @@ -42,52 +42,54 @@ extern "C" { #endif - /** @addtogroup new_c_api - * @{ - */ +/** @addtogroup new_c_api + * @{ + */ - /// A seafloor descriptor - typedef struct __MoorDynSeafloor* MoorDynSeafloor; +/// A seafloor descriptor +typedef struct __MoorDynSeafloor* MoorDynSeafloor; - /// A mooring point instance - typedef struct __MoorDynWaves* MoorDynWaves; +/// A mooring point instance +typedef struct __MoorDynWaves* MoorDynWaves; - /** @brief Get the velocity, acceleration, wave height and dynamic pressure - * at a specific position and time - * @param waves The Waves instance - * @param x The point x coordinate - * @param y The point y coordinate - * @param z The point z coordinate - * @param U The output velocity - * @param Ud The output acceleration - * @param zeta The output wave height - * @param PDyn The output dynamic pressure - * @param seafloor The seafloor instance, see MoorDyn_GetSeafloor() - * @return 0 If the data is correctly set, an error code otherwise - * (see @ref moordyn_errors) - */ - int DECLDIR MoorDyn_GetWavesKin(MoorDynWaves waves, - double x, - double y, - double z, - double U[3], - double Ud[3], - double* zeta, - double* PDyn, - MoorDynSeafloor seafloor); +/** @brief Get the velocity, acceleration, wave height and dynamic pressure + * at a specific position and time + * @param waves The Waves instance + * @param x The point x coordinate + * @param y The point y coordinate + * @param z The point z coordinate + * @param U The output velocity + * @param Ud The output acceleration + * @param zeta The output wave height + * @param PDyn The output dynamic pressure + * @param seafloor The seafloor instance, see MoorDyn_GetSeafloor() + * @return 0 If the data is correctly set, an error code otherwise + * (see @ref moordyn_errors) + */ +int DECLDIR +MoorDyn_GetWavesKin(MoorDynWaves waves, + double x, + double y, + double z, + double U[3], + double Ud[3], + double* zeta, + double* PDyn, + MoorDynSeafloor seafloor); - /** @brief Compute the wave number - * @param Omega The wave angular frequency - * @param g The gravity acceleration - * @param h The water depth - * @return The wave number - * @note credit: FAST source - */ - double DECLDIR WaveNumber(double Omega, double g, double h); +/** @brief Compute the wave number + * @param Omega The wave angular frequency + * @param g The gravity acceleration + * @param h The water depth + * @return The wave number + * @note credit: FAST source + */ +double DECLDIR +WaveNumber(double Omega, double g, double h); - /** - * @} - */ +/** + * @} + */ #ifdef __cplusplus } diff --git a/source/Waves.hpp b/source/Waves.hpp index 4411b12d..4d6ebcee 100644 --- a/source/Waves.hpp +++ b/source/Waves.hpp @@ -130,7 +130,7 @@ struct SeafloorProvider class AbstractCurrentKin { public: - virtual ~AbstractCurrentKin(){}; + virtual ~AbstractCurrentKin() {}; /** @brief Get the velocity and acceleration at a specific position and time * * @param pos The location @@ -155,7 +155,7 @@ class AbstractCurrentKin class AbstractWaveKin { public: - virtual ~AbstractWaveKin(){}; + virtual ~AbstractWaveKin() {}; /** @brief Get the velocity, acceleration, wave height and dynamic pressure * at a specific position and time * @param pos The location diff --git a/source/Waves/WaveGrid.cpp b/source/Waves/WaveGrid.cpp index ba60e347..1f45b960 100644 --- a/source/Waves/WaveGrid.cpp +++ b/source/Waves/WaveGrid.cpp @@ -438,8 +438,8 @@ constructWaveGridElevationData(const std::string& folder, for (auto line : lines) { vector entries = moordyn::str::split(line); if (entries.size() < 2) { - LOGERR << " The file '" << WaveFilename << "' should have 2 columns" - << endl; + LOGERR << " The file '" << WaveFilename + << "' should have 2 columns" << endl; throw moordyn::input_file_error("Invalid file format"); } wavetimes.push_back(stod(entries[0])); @@ -453,8 +453,8 @@ constructWaveGridElevationData(const std::string& folder, // samples the 1 extra is for the point at zero, [0.0, 1.0, 2.0] is 3 // points even though 2.0/1.0 = 2 unsigned int nt = floor(wavetimes.back() / dtWave) + 1; - LOGDBG << " Number of wave time samples = " << nt << "(" << wavetimes.size() - << " samples provided in the file)" << endl; + LOGDBG << " Number of wave time samples = " << nt << "(" + << wavetimes.size() << " samples provided in the file)" << endl; vector waveTime(nt, 0.0); vector waveElev(nt, 0.0); @@ -555,7 +555,8 @@ constructSteadyCurrentGrid(const std::string& folder, try { lines = moordyn::fileIO::fileToLines(CurrentsFilename); } catch (moordyn::input_file_error& err) { - LOGERR << " Cannot read the file '" << CurrentsFilename << "'" << endl; + LOGERR << " Cannot read the file '" << CurrentsFilename << "'" + << endl; std::stringstream ss; ss << "constructSteadyCurrentGrid failed to read currents_profile.txt " "file: " @@ -631,7 +632,8 @@ constructDynamicCurrentGrid(const std::string& folder, try { lines = moordyn::fileIO::fileToLines(CurrentsFilename); } catch (moordyn::input_file_error& err) { - LOGERR << " Cannot read the file '" << CurrentsFilename << "'" << endl; + LOGERR << " Cannot read the file '" << CurrentsFilename << "'" + << endl; std::stringstream ss; ss << " Waves::setup failed to read currents_profile_dynamic.txt " "file: " @@ -738,15 +740,16 @@ construct4DCurrentGrid(const std::string& folder, { const string CurrentsFilename = folder + "current_profile_4d.txt"; - LOGMSG << " Reading 4d currents dynamic profile from '" << CurrentsFilename - << "'..." << endl; + LOGMSG << " Reading 4d currents dynamic profile from '" + << CurrentsFilename << "'..." << endl; vector lines; try { lines = moordyn::fileIO::fileToLines(CurrentsFilename); } catch (moordyn::input_file_error& err) { - LOGERR << " Cannot read the file '" << CurrentsFilename << "'" << endl; + LOGERR << " Cannot read the file '" << CurrentsFilename << "'" + << endl; std::stringstream ss; ss << " Waves::setup failed to read currents_profile_4d.txt " "file: " diff --git a/source/Waves/WaveSpectrum.cpp b/source/Waves/WaveSpectrum.cpp index aee920fc..1f80f6c6 100644 --- a/source/Waves/WaveSpectrum.cpp +++ b/source/Waves/WaveSpectrum.cpp @@ -72,8 +72,8 @@ DiscreteWaveSpectrum::interpEvenlySpaced() moordyn::waves::DiscreteWaveSpectrum spectrumFromFile(const std::string& path, moordyn::Log* _log) { - LOGMSG << " reading spectrum from file: " << std::filesystem::absolute(path) - << endl; + LOGMSG << " reading spectrum from file: " + << std::filesystem::absolute(path) << endl; vector lines; try { lines = moordyn::fileIO::fileToLines(path); @@ -108,10 +108,11 @@ spectrumFromFile(const std::string& path, moordyn::Log* _log) real i = stod(entries[2]); real beta = entries.size() == 4 ? stod(entries[3]) : 0.0; if (beta > 2 * pi || beta < -2 * pi) { - LOGERR << " Cannot specify a wave frequency with a direction of " - "great than 2pi or less than -2pi. The value should " - "be in radians." - << endl; + LOGERR + << " Cannot specify a wave frequency with a direction of " + "great than 2pi or less than -2pi. The value should " + "be in radians." + << endl; throw moordyn::input_file_error( "Invalid wave_frequencies.txt file"); } diff --git a/source/Waves/WaveSpectrum.hpp b/source/Waves/WaveSpectrum.hpp index 8cefeb29..b58d317f 100644 --- a/source/Waves/WaveSpectrum.hpp +++ b/source/Waves/WaveSpectrum.hpp @@ -29,7 +29,7 @@ struct FrequencyComponent /// Angle, in radians, of the frequency component real beta = 0; - FrequencyComponent(){}; + FrequencyComponent() {}; FrequencyComponent(real omega, moordyn::complex amplitude, real beta = 0) : omega(omega) , amplitude(amplitude) diff --git a/source/_kiss_fft_guts.h b/source/_kiss_fft_guts.h index ee2bd7c5..f096e3a9 100644 --- a/source/_kiss_fft_guts.h +++ b/source/_kiss_fft_guts.h @@ -146,11 +146,11 @@ struct kiss_fft_state #elif defined(USE_SIMD) #define KISS_FFT_COS(phase) _mm_set1_ps(cos(phase)) #define KISS_FFT_SIN(phase) _mm_set1_ps(sin(phase)) -#define HALF_OF(x) ((x)*_mm_set1_ps(.5)) +#define HALF_OF(x) ((x) * _mm_set1_ps(.5)) #else #define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) #define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) -#define HALF_OF(x) ((x)*.5) +#define HALF_OF(x) ((x) * .5) #endif #define kf_cexp(x, phase) \ diff --git a/source/kiss_fft.h b/source/kiss_fft.h index 8b7b6644..ec0b1e52 100644 --- a/source/kiss_fft.h +++ b/source/kiss_fft.h @@ -65,81 +65,81 @@ extern "C" #endif #endif - typedef struct - { - kiss_fft_scalar r; - kiss_fft_scalar i; - } kiss_fft_cpx; - - typedef struct kiss_fft_state* kiss_fft_cfg; - - /* - * kiss_fft_alloc - * - * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. - * - * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); - * - * The return value from fft_alloc is a cfg buffer used internally - * by the fft routine or NULL. - * - * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using - * malloc. The returned value should be free()d when done to avoid memory - * leaks. - * - * The state can be placed in a user supplied buffer 'mem': - * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, - * then the function places the cfg in mem and the size used in *lenmem - * and returns mem. - * - * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), - * then the function returns NULL and places the minimum cfg - * buffer size in *lenmem. - * */ - - kiss_fft_cfg kiss_fft_alloc(int nfft, - int inverse_fft, - void* mem, - size_t* lenmem); - - /* - * kiss_fft(cfg,in_out_buf) - * - * Perform an FFT on a complex input buffer. - * for a forward FFT, - * fin should be f[0] , f[1] , ... ,f[nfft-1] - * fout will be F[0] , F[1] , ... ,F[nfft-1] - * Note that each element is complex and can be accessed like - f[k].r and f[k].i - * */ - void kiss_fft(kiss_fft_cfg cfg, - const kiss_fft_cpx* fin, - kiss_fft_cpx* fout); - - /* - A more generic version of the above function. It reads its input from every - Nth sample. - * */ - void kiss_fft_stride(kiss_fft_cfg cfg, - const kiss_fft_cpx* fin, - kiss_fft_cpx* fout, - int fin_stride); +typedef struct +{ + kiss_fft_scalar r; + kiss_fft_scalar i; +} kiss_fft_cpx; + +typedef struct kiss_fft_state* kiss_fft_cfg; + +/* + * kiss_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using + * malloc. The returned value should be free()d when done to avoid memory + * leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_cfg +kiss_fft_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem); + +/* + * kiss_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void +kiss_fft(kiss_fft_cfg cfg, const kiss_fft_cpx* fin, kiss_fft_cpx* fout); + +/* + A more generic version of the above function. It reads its input from every + Nth sample. + * */ +void +kiss_fft_stride(kiss_fft_cfg cfg, + const kiss_fft_cpx* fin, + kiss_fft_cpx* fout, + int fin_stride); /* If kiss_fft_alloc allocated a buffer, it is one contiguous buffer and can be simply free()d when no longer needed*/ #define kiss_fft_free KISS_FFT_FREE - /* - Cleans up some memory that gets managed internally. Not necessary to call, - but it might clean up your compiler output to call this before you exit. - */ - void kiss_fft_cleanup(void); - - /* - * Returns the smallest integer k, such that k>=n and k has only "fast" - * factors (2,3,5) - */ - int kiss_fft_next_fast_size(int n); +/* + Cleans up some memory that gets managed internally. Not necessary to call, + but it might clean up your compiler output to call this before you exit. +*/ +void +kiss_fft_cleanup(void); + +/* + * Returns the smallest integer k, such that k>=n and k has only "fast" + * factors (2,3,5) + */ +int +kiss_fft_next_fast_size(int n); /* for real ffts, we need an even size */ #define kiss_fftr_next_fast_size_real(n) \ diff --git a/source/kiss_fftr.h b/source/kiss_fftr.h index b7c0497c..5c0099af 100644 --- a/source/kiss_fftr.h +++ b/source/kiss_fftr.h @@ -15,42 +15,42 @@ extern "C" { #endif - /* - - Real optimized version can save about 45% cpu time vs. complex fft of a - real seq. +/* + Real optimized version can save about 45% cpu time vs. complex fft of a + real seq. - */ - typedef struct kiss_fftr_state* kiss_fftr_cfg; + */ - kiss_fftr_cfg kiss_fftr_alloc(int nfft, - int inverse_fft, - void* mem, - size_t* lenmem); - /* - nfft must be even +typedef struct kiss_fftr_state* kiss_fftr_cfg; - If you don't care to allocate space, use mem = lenmem = NULL - */ +kiss_fftr_cfg +kiss_fftr_alloc(int nfft, int inverse_fft, void* mem, size_t* lenmem); +/* + nfft must be even - void kiss_fftr(kiss_fftr_cfg cfg, - const kiss_fft_scalar* timedata, - kiss_fft_cpx* freqdata); - /* - input timedata has nfft scalar points - output freqdata has nfft/2+1 complex points - */ + If you don't care to allocate space, use mem = lenmem = NULL +*/ - void kiss_fftri(kiss_fftr_cfg cfg, - const kiss_fft_cpx* freqdata, - kiss_fft_scalar* timedata); - /* - input freqdata has nfft/2+1 complex points - output timedata has nfft scalar points - */ +void +kiss_fftr(kiss_fftr_cfg cfg, + const kiss_fft_scalar* timedata, + kiss_fft_cpx* freqdata); +/* + input timedata has nfft scalar points + output freqdata has nfft/2+1 complex points +*/ + +void +kiss_fftri(kiss_fftr_cfg cfg, + const kiss_fft_cpx* freqdata, + kiss_fft_scalar* timedata); +/* + input freqdata has nfft/2+1 complex points + output timedata has nfft scalar points +*/ #define kiss_fftr_free KISS_FFT_FREE diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4ff56ed5..b810c041 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,7 +35,6 @@ set(CPP_TESTS seafloor wavekin wavekin_7 - viv ) set(CATCH2_TESTS @@ -46,6 +45,7 @@ set(CATCH2_TESTS beam conveying_fluid polyester + viv quasi_static_chain lowe_and_langley_2006 local_euler diff --git a/tests/aca.cpp b/tests/aca.cpp index da57bdc3..2f42090f 100644 --- a/tests/aca.cpp +++ b/tests/aca.cpp @@ -124,8 +124,8 @@ TEST_CASE("quasi_static_chain with aca10") // Compute the static tension int num_lines = 1; float fh, fv, ah, av; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair0 = sqrt(fh * fh + fv * fv); const double ffair_ref0 = 1.e3 * STATIC_FAIR_TENSION; const double fanch0 = sqrt(ah * ah + av * av); @@ -167,8 +167,8 @@ TEST_CASE("quasi_static_chain with aca10") if (t_ref < 0.0) continue; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair = sqrt(fh * fh + fv * fv) - ffair0; const double ffair_ref = 1.e3 * ref_data[i_ref][3] - ffair_ref0; const double fanch = sqrt(ah * ah + av * av) - fanch0; diff --git a/tests/beuler.cpp b/tests/beuler.cpp index 12d3db0b..cad9307f 100644 --- a/tests/beuler.cpp +++ b/tests/beuler.cpp @@ -124,8 +124,8 @@ TEST_CASE("quasi_static_chain with beuler10") // Compute the static tension int num_lines = 1; float fh, fv, ah, av; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair0 = sqrt(fh * fh + fv * fv); const double ffair_ref0 = 1.e3 * STATIC_FAIR_TENSION; const double fanch0 = sqrt(ah * ah + av * av); @@ -167,8 +167,8 @@ TEST_CASE("quasi_static_chain with beuler10") if (t_ref < 0.0) continue; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair = sqrt(fh * fh + fv * fv) - ffair0; const double ffair_ref = 1.e3 * ref_data[i_ref][3] - ffair_ref0; const double fanch = sqrt(ah * ah + av * av) - fanch0; diff --git a/tests/bodies.cpp b/tests/bodies.cpp index 3378fc4a..c86d51a6 100644 --- a/tests/bodies.cpp +++ b/tests/bodies.cpp @@ -106,9 +106,7 @@ struct Trajectory */ template bool -followTrajectory(MoorDyn& system, - const Trajectory& trajectory, - double& t) +followTrajectory(MoorDyn& system, const Trajectory& trajectory, double& t) { int err; @@ -164,19 +162,19 @@ TEST_CASE("Rotating body") double t = 0, dt = 0.1; // do one outer time step just to make sure everything is settled - REQUIRE(MoorDyn_Step( - system, x.data(), dx.data(), f, &t, &dt) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_Step(system, x.data(), dx.data(), f, &t, &dt) == + MOORDYN_SUCCESS); double start_t = t; // goes from (2, 0, 0) to (0, 0, 2) in 2 seconds - auto trajectory = Trajectory< - moordyn:: - vec3>::fromLambda(start_t, start_t + 2.0, dt, [&](double time) { - const double elapsed_time = time - start_t; - const double angle = 0.5 * (M_PI / 2.0) * elapsed_time; - x = body_center + (radius * moordyn::vec3{ cos(angle), 0, sin(angle) }); - return x; - }); + auto trajectory = Trajectory::fromLambda( + start_t, start_t + 2.0, dt, [&](double time) { + const double elapsed_time = time - start_t; + const double angle = 0.5 * (M_PI / 2.0) * elapsed_time; + x = body_center + + (radius * moordyn::vec3{ cos(angle), 0, sin(angle) }); + return x; + }); REQUIRE(followTrajectory(system, trajectory, t)); start_t = t; @@ -184,8 +182,8 @@ TEST_CASE("Rotating body") dx = moordyn::vec3(0, 0, 0.0); // give 0.5 seconds to settle at the top while (t < start_t + 0.5) { - REQUIRE(MoorDyn_Step( - system, x.data(), dx.data(), f, &t, &dt) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_Step(system, x.data(), dx.data(), f, &t, &dt) == + MOORDYN_SUCCESS); } moordyn::vec3 point_pos; @@ -199,14 +197,14 @@ TEST_CASE("Rotating body") start_t = t; // goes from (0, 0, 2) to (0, 2, 0) in 2 seconds - auto trajectory2 = Trajectory< - moordyn:: - vec3>::fromLambda(start_t, start_t + 2.0, dt, [&](double time) { - const double elapsed_time = time - start_t; - const double angle = 0.5 * (M_PI / 2.0) * elapsed_time; - x = body_center + (radius * moordyn::vec3{ 0, sin(angle), cos(angle) }); - return x; - }); + auto trajectory2 = Trajectory::fromLambda( + start_t, start_t + 2.0, dt, [&](double time) { + const double elapsed_time = time - start_t; + const double angle = 0.5 * (M_PI / 2.0) * elapsed_time; + x = body_center + + (radius * moordyn::vec3{ 0, sin(angle), cos(angle) }); + return x; + }); REQUIRE(followTrajectory(system, trajectory2, t)); start_t = t; @@ -214,8 +212,8 @@ TEST_CASE("Rotating body") dx = moordyn::vec3(0, 0.0, 0.0); // give 0.5 seconds to settle at the top while (t < start_t + 0.5) { - REQUIRE(MoorDyn_Step( - system, x.data(), dx.data(), f, &t, &dt) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_Step(system, x.data(), dx.data(), f, &t, &dt) == + MOORDYN_SUCCESS); } REQUIRE(MoorDyn_GetPointPos(point, point_pos.data()) == MOORDYN_SUCCESS); @@ -229,14 +227,14 @@ TEST_CASE("Rotating body") start_t = t; // goes from (0, 2, 0) to (2, 0, 0) in 2 seconds - auto trajectory3 = Trajectory< - moordyn:: - vec3>::fromLambda(start_t, start_t + 2.0, dt, [&](double time) { - const double elapsed_time = time - start_t; - const double angle = 0.5 * (M_PI / 2.0) * elapsed_time; - x = body_center + (radius * moordyn::vec3{ sin(angle), cos(angle), 0 }); - return x; - }); + auto trajectory3 = Trajectory::fromLambda( + start_t, start_t + 2.0, dt, [&](double time) { + const double elapsed_time = time - start_t; + const double angle = 0.5 * (M_PI / 2.0) * elapsed_time; + x = body_center + + (radius * moordyn::vec3{ sin(angle), cos(angle), 0 }); + return x; + }); REQUIRE(followTrajectory(system, trajectory3, t)); start_t = t; @@ -244,8 +242,8 @@ TEST_CASE("Rotating body") dx = moordyn::vec3(0, 0.0, 0.0); // give 0.1 seconds to settle at the top while (t < start_t + 0.5) { - REQUIRE(MoorDyn_Step( - system, x.data(), dx.data(), f, &t, &dt) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_Step(system, x.data(), dx.data(), f, &t, &dt) == + MOORDYN_SUCCESS); } REQUIRE(MoorDyn_GetPointPos(point, point_pos.data()) == MOORDYN_SUCCESS); @@ -259,8 +257,7 @@ TEST_CASE("Rotating body") auto body = MoorDyn_GetBody(system, 1); REQUIRE(body); moordyn::vec6 r, rd; - REQUIRE(MoorDyn_GetBodyState( - body, r.data(), rd.data()) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetBodyState(body, r.data(), rd.data()) == MOORDYN_SUCCESS); // We want axis-angle representation, and it's easier to compute that from // quaternion so we convert back to quaternion auto xyz_quat = moordyn::XYZQuat::fromVec6(r); @@ -269,9 +266,8 @@ TEST_CASE("Rotating body") double angle = moordyn::rad2deg * 2 * acos(q.w()); double denom = (sqrt(1 - q.w() * q.w())); moordyn::vec3 axis{ q.x() / denom, q.y() / denom, q.z() / denom }; - REQUIRE((abs(axis.x()) > 0.85 && - abs(axis.y()) < 0.2 && - abs(axis.z()) < 0.2)); + REQUIRE( + (abs(axis.x()) > 0.85 && abs(axis.y()) < 0.2 && abs(axis.z()) < 0.2)); // normalize angle between +180 and -180 while (angle > 180.) { angle -= 360; @@ -308,7 +304,7 @@ TEST_CASE("Pinned body") unsigned int n_dof; REQUIRE(MoorDyn_NCoupledDOF(system, &n_dof) == MOORDYN_SUCCESS); - REQUIRE(n_dof ==6); + REQUIRE(n_dof == 6); moordyn::vec6 x{ 0, 0, -5, 0, 0, 0 }; moordyn::vec6 xd{ 0, 0, 0, 0, 0, 0 }; @@ -328,11 +324,11 @@ TEST_CASE("Pinned body") x[1] = 0.5 * accel * pow(t, 2); xd[1] = accel * t; - REQUIRE(MoorDyn_Step( - system, x.data(), xd.data(), f, &t, &dt) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_Step(system, x.data(), xd.data(), f, &t, &dt) == + MOORDYN_SUCCESS); - REQUIRE(MoorDyn_GetBodyState( - body, r.data(), rd.data()) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetBodyState(body, r.data(), rd.data()) == + MOORDYN_SUCCESS); roll.push_back(r[3]); if (i >= 30) { // after the simulation has run for a few time steps @@ -378,8 +374,8 @@ TEST_CASE("Body drag") double max_t = 5; while (t < max_t) { // do one outer time step just to make sure everything is settled - REQUIRE(MoorDyn_Step( - system, nullptr, nullptr, f, &t, &dt) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_Step(system, nullptr, nullptr, f, &t, &dt) == + MOORDYN_SUCCESS); } REQUIRE(MoorDyn_Close(system) == MOORDYN_SUCCESS); @@ -394,11 +390,10 @@ TEST_CASE("Excentric body") const double omega = 0.2; const moordyn::vec r0 = moordyn::vec(0, 0, 20.0); auto bodies = system.GetBodies(); - for (auto body : bodies) - { + for (auto body : bodies) { const auto [pos, vel] = body->getState(); - const moordyn::vec6 new_vel = moordyn::vec6( - 0.0, 0.0, radius * omega, omega, 0.0, 0.0); + const moordyn::vec6 new_vel = + moordyn::vec6(0.0, 0.0, radius * omega, omega, 0.0, 0.0); body->r7 = pos; body->v6 = new_vel; } @@ -414,8 +409,7 @@ TEST_CASE("Excentric body") REQUIRE(system.Step(NULL, NULL, f, t, small_dt) == MOORDYN_SUCCESS); while ((t_max - t) > (0.1 * dt)) { REQUIRE(system.Step(NULL, NULL, f, t, dt) == MOORDYN_SUCCESS); - for (auto body : bodies) - { + for (auto body : bodies) { const auto [pos, vel] = body->getState(); const moordyn::vec3 global_pos = pos.pos; const moordyn::vec q = (global_pos - r0) / radius; diff --git a/tests/csv_parser.h b/tests/csv_parser.h index 0cea81ef..d20198b9 100644 --- a/tests/csv_parser.h +++ b/tests/csv_parser.h @@ -9,8 +9,8 @@ * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -31,338 +31,377 @@ #include namespace aria { - namespace csv { - enum class Term { CRLF = -2 }; - enum class FieldType { DATA, ROW_END, CSV_END }; - using CSV = std::vector>; - - // Checking for '\n', '\r', and '\r\n' by default - inline bool operator==(const char c, const Term t) { - switch (t) { - case Term::CRLF: - return c == '\r' || c == '\n'; - default: - return static_cast(t) == c; - } - } - - inline bool operator!=(const char c, const Term t) { - return !(c == t); - } - - // Wraps returned fields so we can also indicate - // that we hit row endings or the end of the csv itself - struct Field { - explicit Field(FieldType t): type(t), data(nullptr) {} - explicit Field(const std::string& str): type(FieldType::DATA), data(&str) {} - - FieldType type; - const std::string *data; - }; - - // Reads and parses lines from a csv file - class CsvParser { - private: - // CSV state for state machine - enum class State { - START_OF_FIELD, - IN_FIELD, - IN_QUOTED_FIELD, - IN_ESCAPED_QUOTE, - END_OF_ROW, - EMPTY - }; - State m_state = State::START_OF_FIELD; - - // Configurable attributes - char m_quote = '"'; - char m_delimiter = ','; - Term m_terminator = Term::CRLF; - std::istream& m_input; - - // Buffer capacities - static constexpr int FIELDBUF_CAP = 1024; - static constexpr int INPUTBUF_CAP = 1024 * 128; - - // Buffers - std::string m_fieldbuf{}; - std::unique_ptr m_inputbuf = std::unique_ptr(new char[INPUTBUF_CAP]{}); - - // Misc - bool m_eof = false; - size_t m_cursor = INPUTBUF_CAP; - size_t m_inputbuf_size = INPUTBUF_CAP; - std::streamoff m_scanposition = -INPUTBUF_CAP; - public: - // Creates the CSV parser which by default, splits on commas, - // uses quotes to escape, and handles CSV files that end in either - // '\r', '\n', or '\r\n'. - explicit CsvParser(std::istream& input): m_input(input) { - // Reserve space upfront to improve performance - m_fieldbuf.reserve(FIELDBUF_CAP); - if (!m_input.good()) { - throw std::runtime_error("Something is wrong with input stream"); - } - } - - // Change the quote character - CsvParser&& quote(char c) noexcept { - m_quote = c; - return std::move(*this); - } - - // Change the delimiter character - CsvParser&& delimiter(char c) noexcept { - m_delimiter = c; - return std::move(*this); - } - - // Change the terminator character - CsvParser&& terminator(char c) noexcept { - m_terminator = static_cast(c); - return std::move(*this); - } - - // The parser is in the empty state when there are - // no more tokens left to read from the input buffer - bool empty() { - return m_state == State::EMPTY; - } - - // Not the actual position in the stream (its buffered) just the - // position up to last availiable token - std::streamoff position() const - { - return m_scanposition + static_cast(m_cursor); - } - - // Reads a single field from the CSV - Field next_field() { - if (empty()) { - return Field(FieldType::CSV_END); - } - m_fieldbuf.clear(); - - // This loop runs until either the parser has - // read a full field or until there's no tokens left to read - for (;;) { - char *maybe_token = top_token(); - - // If we're out of tokens to read return whatever's left in the - // field and row buffers. If there's nothing left, return null. - if (!maybe_token) { - m_state = State::EMPTY; - return !m_fieldbuf.empty() ? Field(m_fieldbuf) : Field(FieldType::CSV_END); - } - - // Parsing the CSV is done using a finite state machine - char c = *maybe_token; - switch (m_state) { - case State::START_OF_FIELD: - m_cursor++; - if (c == m_terminator) { - handle_crlf(c); - m_state = State::END_OF_ROW; - return Field(m_fieldbuf); - } - - if (c == m_quote) { - m_state = State::IN_QUOTED_FIELD; - } else if (c == m_delimiter) { - return Field(m_fieldbuf); - } else { - m_state = State::IN_FIELD; - m_fieldbuf += c; - } - - break; - - case State::IN_FIELD: - m_cursor++; - if (c == m_terminator) { - handle_crlf(c); - m_state = State::END_OF_ROW; - return Field(m_fieldbuf); - } - - if (c == m_delimiter) { - m_state = State::START_OF_FIELD; - return Field(m_fieldbuf); - } else { - m_fieldbuf += c; - } - - break; - - case State::IN_QUOTED_FIELD: - m_cursor++; - if (c == m_quote) { - m_state = State::IN_ESCAPED_QUOTE; - } else { - m_fieldbuf += c; - } - - break; - - case State::IN_ESCAPED_QUOTE: - m_cursor++; - if (c == m_terminator) { - handle_crlf(c); - m_state = State::END_OF_ROW; - return Field(m_fieldbuf); - } - - if (c == m_quote) { - m_state = State::IN_QUOTED_FIELD; - m_fieldbuf += c; - } else if (c == m_delimiter) { - m_state = State::START_OF_FIELD; - return Field(m_fieldbuf); - } else { - m_state = State::IN_FIELD; - m_fieldbuf += c; - } - - break; - - case State::END_OF_ROW: - m_state = State::START_OF_FIELD; - return Field(FieldType::ROW_END); - - case State::EMPTY: - throw std::logic_error("You goofed"); - } - } - } - private: - // When the parser hits the end of a line it needs - // to check the special case of '\r\n' as a terminator. - // If it finds that the previous token was a '\r', and - // the next token will be a '\n', it skips the '\n'. - void handle_crlf(const char c) { - if (m_terminator != Term::CRLF || c != '\r') { - return; - } - - char *token = top_token(); - if (token && *token == '\n') { - m_cursor++; - } - } - - // Pulls the next token from the input buffer, but does not move - // the cursor forward. If the stream is empty and the input buffer - // is also empty return a nullptr. - char* top_token() { - // Return null if there's nothing left to read - if (m_eof && m_cursor == m_inputbuf_size) { - return nullptr; - } - - // Refill the input buffer if it's been fully read - if (m_cursor == m_inputbuf_size) { - m_scanposition += static_cast(m_cursor); - m_cursor = 0; - m_input.read(m_inputbuf.get(), INPUTBUF_CAP); - - // Indicate we hit end of file, and resize - // input buffer to show that it's not at full capacity - if (m_input.eof()) { - m_eof = true; - m_inputbuf_size = static_cast(m_input.gcount()); - - // Return null if there's nothing left to read - if (m_inputbuf_size == 0) { - return nullptr; - } - } - } - - return &m_inputbuf[m_cursor]; - } - public: - // Iterator implementation for the CSV parser, which reads - // from the CSV row by row in the form of a vector of strings - class iterator { - public: - using difference_type = std::ptrdiff_t; - using value_type = std::vector; - using pointer = const std::vector*; - using reference = const std::vector&; - using iterator_category = std::input_iterator_tag; - - explicit iterator(CsvParser *p, bool end = false): m_parser(p) { - if (!end) { - m_row.reserve(50); - m_current_row = 0; - next(); - } - } - - iterator& operator++() { - next(); - return *this; - } - - iterator operator++(int) { - iterator i = (*this); - ++(*this); - return i; - } - - bool operator==(const iterator& other) const { - return m_current_row == other.m_current_row - && m_row.size() == other.m_row.size(); - } - - bool operator!=(const iterator& other) const { - return !(*this == other); - } - - reference operator*() const { - return m_row; - } - - pointer operator->() const { - return &m_row; - } - private: - value_type m_row{}; - CsvParser *m_parser; - int m_current_row = -1; - - void next() { - value_type::size_type num_fields = 0; - for (;;) { - auto field = m_parser->next_field(); - switch (field.type) { - case FieldType::CSV_END: - if (num_fields < m_row.size()) { - m_row.resize(num_fields); - } - m_current_row = -1; - return; - case FieldType::ROW_END: - if (num_fields < m_row.size()) { - m_row.resize(num_fields); - } - m_current_row++; - return; - case FieldType::DATA: - if (num_fields < m_row.size()) { - m_row[num_fields] = std::move(*field.data); - } else { - m_row.push_back(std::move(*field.data)); - } - num_fields++; - } - } - } - }; - - iterator begin() { return iterator(this); }; - iterator end() { return iterator(this, true); }; - }; - } +namespace csv { +enum class Term +{ + CRLF = -2 +}; +enum class FieldType +{ + DATA, + ROW_END, + CSV_END +}; +using CSV = std::vector>; + +// Checking for '\n', '\r', and '\r\n' by default +inline bool +operator==(const char c, const Term t) +{ + switch (t) { + case Term::CRLF: + return c == '\r' || c == '\n'; + default: + return static_cast(t) == c; + } } -#endif + +inline bool +operator!=(const char c, const Term t) +{ + return !(c == t); +} + +// Wraps returned fields so we can also indicate +// that we hit row endings or the end of the csv itself +struct Field +{ + explicit Field(FieldType t) + : type(t) + , data(nullptr) + { + } + explicit Field(const std::string& str) + : type(FieldType::DATA) + , data(&str) + { + } + + FieldType type; + const std::string* data; +}; + +// Reads and parses lines from a csv file +class CsvParser +{ + private: + // CSV state for state machine + enum class State + { + START_OF_FIELD, + IN_FIELD, + IN_QUOTED_FIELD, + IN_ESCAPED_QUOTE, + END_OF_ROW, + EMPTY + }; + State m_state = State::START_OF_FIELD; + + // Configurable attributes + char m_quote = '"'; + char m_delimiter = ','; + Term m_terminator = Term::CRLF; + std::istream& m_input; + + // Buffer capacities + static constexpr int FIELDBUF_CAP = 1024; + static constexpr int INPUTBUF_CAP = 1024 * 128; + + // Buffers + std::string m_fieldbuf{}; + std::unique_ptr m_inputbuf = + std::unique_ptr(new char[INPUTBUF_CAP]{}); + + // Misc + bool m_eof = false; + size_t m_cursor = INPUTBUF_CAP; + size_t m_inputbuf_size = INPUTBUF_CAP; + std::streamoff m_scanposition = -INPUTBUF_CAP; + + public: + // Creates the CSV parser which by default, splits on commas, + // uses quotes to escape, and handles CSV files that end in either + // '\r', '\n', or '\r\n'. + explicit CsvParser(std::istream& input) + : m_input(input) + { + // Reserve space upfront to improve performance + m_fieldbuf.reserve(FIELDBUF_CAP); + if (!m_input.good()) { + throw std::runtime_error("Something is wrong with input stream"); + } + } + + // Change the quote character + CsvParser&& quote(char c) noexcept + { + m_quote = c; + return std::move(*this); + } + + // Change the delimiter character + CsvParser&& delimiter(char c) noexcept + { + m_delimiter = c; + return std::move(*this); + } + + // Change the terminator character + CsvParser&& terminator(char c) noexcept + { + m_terminator = static_cast(c); + return std::move(*this); + } + + // The parser is in the empty state when there are + // no more tokens left to read from the input buffer + bool empty() { return m_state == State::EMPTY; } + + // Not the actual position in the stream (its buffered) just the + // position up to last availiable token + std::streamoff position() const + { + return m_scanposition + static_cast(m_cursor); + } + + // Reads a single field from the CSV + Field next_field() + { + if (empty()) { + return Field(FieldType::CSV_END); + } + m_fieldbuf.clear(); + + // This loop runs until either the parser has + // read a full field or until there's no tokens left to read + for (;;) { + char* maybe_token = top_token(); + + // If we're out of tokens to read return whatever's left in the + // field and row buffers. If there's nothing left, return null. + if (!maybe_token) { + m_state = State::EMPTY; + return !m_fieldbuf.empty() ? Field(m_fieldbuf) + : Field(FieldType::CSV_END); + } + + // Parsing the CSV is done using a finite state machine + char c = *maybe_token; + switch (m_state) { + case State::START_OF_FIELD: + m_cursor++; + if (c == m_terminator) { + handle_crlf(c); + m_state = State::END_OF_ROW; + return Field(m_fieldbuf); + } + + if (c == m_quote) { + m_state = State::IN_QUOTED_FIELD; + } else if (c == m_delimiter) { + return Field(m_fieldbuf); + } else { + m_state = State::IN_FIELD; + m_fieldbuf += c; + } + + break; + + case State::IN_FIELD: + m_cursor++; + if (c == m_terminator) { + handle_crlf(c); + m_state = State::END_OF_ROW; + return Field(m_fieldbuf); + } + + if (c == m_delimiter) { + m_state = State::START_OF_FIELD; + return Field(m_fieldbuf); + } else { + m_fieldbuf += c; + } + + break; + + case State::IN_QUOTED_FIELD: + m_cursor++; + if (c == m_quote) { + m_state = State::IN_ESCAPED_QUOTE; + } else { + m_fieldbuf += c; + } + + break; + + case State::IN_ESCAPED_QUOTE: + m_cursor++; + if (c == m_terminator) { + handle_crlf(c); + m_state = State::END_OF_ROW; + return Field(m_fieldbuf); + } + + if (c == m_quote) { + m_state = State::IN_QUOTED_FIELD; + m_fieldbuf += c; + } else if (c == m_delimiter) { + m_state = State::START_OF_FIELD; + return Field(m_fieldbuf); + } else { + m_state = State::IN_FIELD; + m_fieldbuf += c; + } + + break; + + case State::END_OF_ROW: + m_state = State::START_OF_FIELD; + return Field(FieldType::ROW_END); + + case State::EMPTY: + throw std::logic_error("You goofed"); + } + } + } + + private: + // When the parser hits the end of a line it needs + // to check the special case of '\r\n' as a terminator. + // If it finds that the previous token was a '\r', and + // the next token will be a '\n', it skips the '\n'. + void handle_crlf(const char c) + { + if (m_terminator != Term::CRLF || c != '\r') { + return; + } + + char* token = top_token(); + if (token && *token == '\n') { + m_cursor++; + } + } + + // Pulls the next token from the input buffer, but does not move + // the cursor forward. If the stream is empty and the input buffer + // is also empty return a nullptr. + char* top_token() + { + // Return null if there's nothing left to read + if (m_eof && m_cursor == m_inputbuf_size) { + return nullptr; + } + + // Refill the input buffer if it's been fully read + if (m_cursor == m_inputbuf_size) { + m_scanposition += static_cast(m_cursor); + m_cursor = 0; + m_input.read(m_inputbuf.get(), INPUTBUF_CAP); + + // Indicate we hit end of file, and resize + // input buffer to show that it's not at full capacity + if (m_input.eof()) { + m_eof = true; + m_inputbuf_size = static_cast(m_input.gcount()); + + // Return null if there's nothing left to read + if (m_inputbuf_size == 0) { + return nullptr; + } + } + } + + return &m_inputbuf[m_cursor]; + } + + public: + // Iterator implementation for the CSV parser, which reads + // from the CSV row by row in the form of a vector of strings + class iterator + { + public: + using difference_type = std::ptrdiff_t; + using value_type = std::vector; + using pointer = const std::vector*; + using reference = const std::vector&; + using iterator_category = std::input_iterator_tag; + + explicit iterator(CsvParser* p, bool end = false) + : m_parser(p) + { + if (!end) { + m_row.reserve(50); + m_current_row = 0; + next(); + } + } + + iterator& operator++() + { + next(); + return *this; + } + + iterator operator++(int) + { + iterator i = (*this); + ++(*this); + return i; + } + + bool operator==(const iterator& other) const + { + return m_current_row == other.m_current_row && + m_row.size() == other.m_row.size(); + } + + bool operator!=(const iterator& other) const + { + return !(*this == other); + } + + reference operator*() const { return m_row; } + + pointer operator->() const { return &m_row; } + + private: + value_type m_row{}; + CsvParser* m_parser; + int m_current_row = -1; + + void next() + { + value_type::size_type num_fields = 0; + for (;;) { + auto field = m_parser->next_field(); + switch (field.type) { + case FieldType::CSV_END: + if (num_fields < m_row.size()) { + m_row.resize(num_fields); + } + m_current_row = -1; + return; + case FieldType::ROW_END: + if (num_fields < m_row.size()) { + m_row.resize(num_fields); + } + m_current_row++; + return; + case FieldType::DATA: + if (num_fields < m_row.size()) { + m_row[num_fields] = std::move(*field.data); + } else { + m_row.push_back(std::move(*field.data)); + } + num_fields++; + } + } + } + }; + + iterator begin() { return iterator(this); }; + iterator end() { return iterator(this, true); }; +}; +} +} +#endif diff --git a/tests/local_euler.cpp b/tests/local_euler.cpp index 4ac04f10..4a626b48 100644 --- a/tests/local_euler.cpp +++ b/tests/local_euler.cpp @@ -7,7 +7,8 @@ #define DUPLICATED_TOL 1e-4 #define HANGING_TOL 1e-1 -double compare_lines(MoorDynLine line1, MoorDynLine line2) +double +compare_lines(MoorDynLine line1, MoorDynLine line2) { unsigned int n1, n2; REQUIRE(MoorDyn_GetLineN(line1, &n1) == MOORDYN_SUCCESS); @@ -110,18 +111,20 @@ TEST_CASE("Complex system performance test") auto in_init = std::chrono::steady_clock::now(); REQUIRE(MoorDyn_Init(system, x, dx) == MOORDYN_SUCCESS); auto out_init = std::chrono::steady_clock::now(); - auto dt_init = std::chrono::duration_cast< - std::chrono::duration>>( - out_init - in_init).count(); + auto dt_init = + std::chrono::duration_cast< + std::chrono::duration>>(out_init - in_init) + .count(); double f[6]; double t = 0.0, dt = 50.0; auto in_step = std::chrono::steady_clock::now(); REQUIRE(MoorDyn_Step(system, x, dx, f, &t, &dt) == MOORDYN_SUCCESS); auto out_step = std::chrono::steady_clock::now(); - auto dt_step = std::chrono::duration_cast< - std::chrono::duration>>( - out_step - in_step).count(); + auto dt_step = + std::chrono::duration_cast< + std::chrono::duration>>(out_step - in_step) + .count(); REQUIRE(dt_step < dt_init); REQUIRE(MoorDyn_Close(system) == MOORDYN_SUCCESS); diff --git a/tests/lowe_and_langley_2006.cpp b/tests/lowe_and_langley_2006.cpp index 776c2314..efde940f 100644 --- a/tests/lowe_and_langley_2006.cpp +++ b/tests/lowe_and_langley_2006.cpp @@ -112,14 +112,14 @@ init() std::fill(u, u + 3, 0.0); REQUIRE(MoorDyn_Init(system, r, u) == MOORDYN_SUCCESS); - return {system, line, point}; + return { system, line, point }; } TEST_CASE("Stationary") { const double tol = 0.2; - const double top_ten_ref[3] = {11.40, 0.0, 45.71}; - const double bottom_ten_ref[3] = {-11.40, 0.0, 24.04}; + const double top_ten_ref[3] = { 11.40, 0.0, 45.71 }; + const double bottom_ten_ref[3] = { -11.40, 0.0, 24.04 }; auto [system, line, point] = init(); unsigned int n_segments; REQUIRE(MoorDyn_GetLineN(line, &n_segments) == MOORDYN_SUCCESS); @@ -173,10 +173,11 @@ case123(const unsigned int case_id) const double t_ref = t - t_ramp; if (t_ref >= ref_data[ref_data_index][0]) { - REQUIRE(MoorDyn_GetLineNodeForce( - line, n_segments, ten) == MOORDYN_SUCCESS); - const double ten_kn = 1.0e-3 * sqrt( - ten[0] * ten[0] + ten[1] * ten[1] + ten[2] * ten[2]); + REQUIRE(MoorDyn_GetLineNodeForce(line, n_segments, ten) == + MOORDYN_SUCCESS); + const double ten_kn = + 1.0e-3 * + sqrt(ten[0] * ten[0] + ten[1] * ten[1] + ten[2] * ten[2]); REQUIRE(std::abs(ten_kn - ref_data[ref_data_index][1]) < tol); ref_data_index++; if (ref_data_index >= ref_data.size()) @@ -215,8 +216,14 @@ TEST_CASE("Case 3") * @param a Output acceleration */ void -wave(double A, double T, double phi, double d, double t, - const double* r, double* u, double* a) +wave(double A, + double T, + double phi, + double d, + double t, + const double* r, + double* u, + double* a) { const double omega = 2.0 * M_PI / T; const double k = omega * omega / 9.81; @@ -259,9 +266,9 @@ case456(const unsigned int case_id, double phi) auto [system, line, point] = init(); unsigned int nwp; REQUIRE(MoorDyn_ExternalWaveKinInit(system, &nwp) == MOORDYN_SUCCESS); - double *rwp = (double*)malloc(3 * nwp * sizeof(double)); - double *uwp = (double*)malloc(3 * nwp * sizeof(double)); - double *awp = (double*)malloc(3 * nwp * sizeof(double)); + double* rwp = (double*)malloc(3 * nwp * sizeof(double)); + double* uwp = (double*)malloc(3 * nwp * sizeof(double)); + double* awp = (double*)malloc(3 * nwp * sizeof(double)); REQUIRE((rwp && uwp && awp)); unsigned int n_segments; @@ -276,22 +283,29 @@ case456(const unsigned int case_id, double phi) while (t < 30.0 + t_ramp) { double ten[3]; - REQUIRE(MoorDyn_ExternalWaveKinGetCoordinates( - system, rwp) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_ExternalWaveKinGetCoordinates(system, rwp) == + MOORDYN_SUCCESS); for (unsigned int i = 0; i < nwp; i++) { - wave(A, T, phi, (case_id - 4) * 0.25 * M_PI, t + 0.5 * dt, - rwp + 3 * i, uwp + 3 * i, awp + 3 * i); + wave(A, + T, + phi, + (case_id - 4) * 0.25 * M_PI, + t + 0.5 * dt, + rwp + 3 * i, + uwp + 3 * i, + awp + 3 * i); } - REQUIRE(MoorDyn_ExternalWaveKinSet( - system, uwp, awp, t + 0.5 * dt) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_ExternalWaveKinSet(system, uwp, awp, t + 0.5 * dt) == + MOORDYN_SUCCESS); REQUIRE(MoorDyn_Step(system, r, u, ten, &t, &dt) == MOORDYN_SUCCESS); const double t_ref = t - t_ramp; if (t_ref >= ref_data[ref_data_index][0]) { - REQUIRE(MoorDyn_GetLineNodeForce( - line, n_segments, ten) == MOORDYN_SUCCESS); - const double ten_kn = 1.0e-3 * sqrt( - ten[0] * ten[0] + ten[1] * ten[1] + ten[2] * ten[2]); + REQUIRE(MoorDyn_GetLineNodeForce(line, n_segments, ten) == + MOORDYN_SUCCESS); + const double ten_kn = + 1.0e-3 * + sqrt(ten[0] * ten[0] + ten[1] * ten[1] + ten[2] * ten[2]); REQUIRE(std::abs(ten_kn - ref_data[ref_data_index][1]) < tol); ref_data_index++; if (ref_data_index >= ref_data.size()) diff --git a/tests/midpoint.cpp b/tests/midpoint.cpp index e5987fab..c8388bca 100644 --- a/tests/midpoint.cpp +++ b/tests/midpoint.cpp @@ -124,8 +124,8 @@ TEST_CASE("quasi_static_chain with midpoint10") // Compute the static tension int num_lines = 1; float fh, fv, ah, av; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair0 = sqrt(fh * fh + fv * fv); const double ffair_ref0 = 1.e3 * STATIC_FAIR_TENSION; const double fanch0 = sqrt(ah * ah + av * av); @@ -167,8 +167,8 @@ TEST_CASE("quasi_static_chain with midpoint10") if (t_ref < 0.0) continue; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair = sqrt(fh * fh + fv * fv) - ffair0; const double ffair_ref = 1.e3 * ref_data[i_ref][3] - ffair_ref0; const double fanch = sqrt(ah * ah + av * av) - fanch0; diff --git a/tests/polyester.cpp b/tests/polyester.cpp index acee81bf..4229e68d 100644 --- a/tests/polyester.cpp +++ b/tests/polyester.cpp @@ -42,9 +42,8 @@ #include "csv_parser.h" #include - #define MBL 25.3e6 -#define KRS 13.4 // normalized static stiffness +#define KRS 13.4 // normalized static stiffness #define KRD1 16.0 // alpha term in dynamic stiffness eqn from ABS #define KRD2 0.35 // beta term in dynamic stiffness eqn from ABS #define TC 200.0 @@ -52,15 +51,16 @@ #define TTIMES { 320.0, 640.0, 960.0, 1280.0, 1599.0 } #define TMEANS { 0.1, 0.2, 0.3, 0.4, 0.5 } - -double vec_norm(const double v[3]) +double +vec_norm(const double v[3]) { return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } -double get_average_tension(MoorDynLine line, - MoorDynPoint anchor, - MoorDynPoint fairlead) +double +get_average_tension(MoorDynLine line, + MoorDynPoint anchor, + MoorDynPoint fairlead) { unsigned int n; REQUIRE(MoorDyn_GetLineN(line, &n) == MOORDYN_SUCCESS); @@ -81,11 +81,13 @@ double get_average_tension(MoorDynLine line, } // Function to calculate the Euclidean distance between two points -double calculate_stretched_length(const double rA[3], const double rB[3]) { - double dx = rB[0] - rA[0]; - double dy = rB[1] - rA[1]; - double dz = rB[2] - rA[2]; - return sqrt(dx * dx + dy * dy + dz * dz); +double +calculate_stretched_length(const double rA[3], const double rB[3]) +{ + double dx = rB[0] - rA[0]; + double dy = rB[1] - rA[1]; + double dz = rB[2] - rA[2]; + return sqrt(dx * dx + dy * dy + dz * dz); } TEST_CASE("Ramp up, stabilization and cycles") @@ -131,8 +133,8 @@ TEST_CASE("Ramp up, stabilization and cycles") // Time to move double t = 0.0, dt; // Data about the length and stiffness recomputation as a function of time - std::deque times; - std::deque tensions; + std::deque times; + std::deque tensions; std::deque ttimes(TTIMES); std::deque tmeans(TMEANS); // tension means for (unsigned int i = 0; i < tdata.size(); i++) { @@ -159,31 +161,29 @@ TEST_CASE("Ramp up, stabilization and cycles") // Compute the dynamic stiffness from static and tension double ks = KRS * MBL; - double kd = (KRD1 + KRD2 * tension / MBL * 100) * MBL; // rope dynamic stiffness eqn. From eqn 2 in MD visco paper + double kd = + (KRD1 + KRD2 * tension / MBL * 100) * + MBL; // rope dynamic stiffness eqn. From eqn 2 in MD visco paper double l = l0 * (1.0 + tension / ks) / (1.0 + tension / kd); - REQUIRE( - MoorDyn_SetLineConstantEA(line, kd) == MOORDYN_SUCCESS); - REQUIRE( - MoorDyn_SetLineUnstretchedLength(line, l) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_SetLineConstantEA(line, kd) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_SetLineUnstretchedLength(line, l) == MOORDYN_SUCCESS); if (t >= ttimes.front()) { const double tmean = tmeans.front(); ttimes.pop_front(); tmeans.pop_front(); - REQUIRE( - fabs(tension / MBL - tmean) < 0.025); + REQUIRE(fabs(tension / MBL - tmean) < 0.025); } } REQUIRE(MoorDyn_Close(system) == MOORDYN_SUCCESS); } - TEST_CASE("Visco-elastic testing") { - // This is more of a regression test, but is sufficient to check the model. - // This checks if the stress strain curve matches the verification case in the - // original PR. + // This is more of a regression test, but is sufficient to check the model. + // This checks if the stress strain curve matches the verification case in + // the original PR. MoorDyn system = MoorDyn_Create("Mooring/polyester/visco.txt"); REQUIRE(system); @@ -233,10 +233,10 @@ TEST_CASE("Visco-elastic testing") // Time to move double t = 0.0, dt = 0.01; - std::deque times; - std::deque tensions; - std::deque strains; - std::deque stresses; + std::deque times; + std::deque tensions; + std::deque strains; + std::deque stresses; std::deque ttimes(TTIMES); std::deque tmeans(TMEANS); // tension means for (unsigned int i = 0; i < tdata.size(); i++) { @@ -247,8 +247,9 @@ TEST_CASE("Visco-elastic testing") dr[0] = (x_dst - r[0]) / dt; double f[3]; // info for if it fails - INFO("Time " << t); - INFO("r: [" << r[0] << ", " << r[1] << ", " << r[2] << "], dr: [" << dr[0] << ", " << dr[1] << ", " << dr[2] << "]"); + INFO("Time " << t); + INFO("r: [" << r[0] << ", " << r[1] << ", " << r[2] << "], dr: [" + << dr[0] << ", " << dr[1] << ", " << dr[2] << "]"); REQUIRE(system); REQUIRE(MoorDyn_Step(system, r, dr, f, &t, &dt) == MOORDYN_SUCCESS); times.push_back(t); @@ -256,7 +257,8 @@ TEST_CASE("Visco-elastic testing") MoorDyn_GetLineNodeTen(line, 1, &ten); tensions.push_back(ten); - // Calculate strain and stress every 10 timesteps (becasue stress strain file is 0.01 timestep) + // Calculate strain and stress every 10 timesteps (becasue stress strain + // file is 0.01 timestep) if (i % 10 == 0) { double rA[3]; double rB[3]; @@ -264,7 +266,9 @@ TEST_CASE("Visco-elastic testing") MoorDyn_GetLineNodePos(line, 1, rB); double l_stretched = calculate_stretched_length(rA, rB); double strain = (l_stretched - l0) / l0; - double area = M_PI * std::pow(0.1438/2, 2); // Diameter of 0.1438 from visco.txt + double area = + M_PI * + std::pow(0.1438 / 2, 2); // Diameter of 0.1438 from visco.txt double stress = ten / area; strains.push_back(strain); stresses.push_back(stress); @@ -272,7 +276,8 @@ TEST_CASE("Visco-elastic testing") } // Compare the calculated stress-strain data with the expected data - std::ifstream plot_data("Mooring/polyester/viscoelastic/stress_strain_curve.csv"); + std::ifstream plot_data( + "Mooring/polyester/viscoelastic/stress_strain_curve.csv"); aria::csv::CsvParser plot_parser(plot_data); std::vector expected_strains, expected_stresses; @@ -295,11 +300,16 @@ TEST_CASE("Visco-elastic testing") for (unsigned int i = 0; i < strains.size(); ++i) { INFO("Time: " << times[i]); INFO("Strains[i]: " << strains[i] << ", stresses[i]:" << stresses[i]); - INFO("Expected Strains[i]: " << expected_strains[i] << ", Expected Stresses[i]:" << expected_stresses[i]); - REQUIRE(fabs(strains[i] - expected_strains[i])/expected_strains[i] < 0.03); // Check if the strain is within 3% of the expected strain - REQUIRE(fabs(stresses[i] - expected_stresses[i])/expected_stresses[i] < 0.03); // Check if the stress is within 3% of the exoected stress + INFO("Expected Strains[i]: " << expected_strains[i] + << ", Expected Stresses[i]:" + << expected_stresses[i]); + REQUIRE( + fabs(strains[i] - expected_strains[i]) / expected_strains[i] < + 0.03); // Check if the strain is within 3% of the expected strain + REQUIRE( + fabs(stresses[i] - expected_stresses[i]) / expected_stresses[i] < + 0.03); // Check if the stress is within 3% of the exoected stress } REQUIRE(MoorDyn_Close(system) == MOORDYN_SUCCESS); } - diff --git a/tests/quasi_static_chain.cpp b/tests/quasi_static_chain.cpp index a57a86f4..dbc6442f 100644 --- a/tests/quasi_static_chain.cpp +++ b/tests/quasi_static_chain.cpp @@ -133,8 +133,8 @@ validation(const char* depth, const char* motion) // Compute the static tension int num_lines = 1; float fh, fv, ah, av; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair0 = sqrt(fh * fh + fv * fv); const double ffair_ref0 = 1.e3 * STATIC_FAIR_TENSION[depth_i]; const double fanch0 = sqrt(ah * ah + av * av); @@ -169,8 +169,8 @@ validation(const char* depth, const char* motion) if (t_ref < 0.0) continue; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair = sqrt(fh * fh + fv * fv) - ffair0; const double ffair_ref = 1.e3 * ref_data[i_ref][3] - ffair_ref0; const double fanch = sqrt(ah * ah + av * av) - fanch0; diff --git a/tests/state_tests.cpp b/tests/state_tests.cpp index 7f2e7c82..2590d4fb 100644 --- a/tests/state_tests.cpp +++ b/tests/state_tests.cpp @@ -30,7 +30,9 @@ CreatePoint(md::Log* log, EnvCondRef env) } md::Line* -CreateLine(md::Log* log, EnvCondRef env, unsigned int n, +CreateLine(md::Log* log, + EnvCondRef env, + unsigned int n, shared_ptr outfile) { md::Line* obj = new md::Line(log, 0); @@ -50,19 +52,12 @@ CreateLine(md::Log* log, EnvCondRef env, unsigned int n, props.nEApoints = 0; props.nBApoints = 0; props.nEIpoints = 0; - obj->setup(0, - &props, - 1.e3, - n, - env, - outfile, - "", - 0); + obj->setup(0, &props, 1.e3, n, env, outfile, "", 0); return obj; } #define SYS_STARTER \ - md::Log *log = new md::Log(MOORDYN_DBG_LEVEL); \ + md::Log* log = new md::Log(MOORDYN_DBG_LEVEL); \ EnvCondRef env = std::make_shared(); \ env->g = 9.81; \ env->WtrDpth = 0.; \ @@ -133,9 +128,9 @@ TEST_CASE("State initializing") r.get(p2).row(0).tail<3>() = md::vec(4.0, 5.0, 6.0); md::real norm = 0.0; for (unsigned int i = 0; i < 19; i++) { - norm += md::vec6(i, 2*i, 4*i, 5*i, 6*i, 7*i).squaredNorm(); - r.get(l).row(i).head<3>() = md::vec(i, 2*i, 4*i); - r.get(l).row(i).tail<3>() = md::vec(5*i, 6*i, 7*i); + norm += md::vec6(i, 2 * i, 4 * i, 5 * i, 6 * i, 7 * i).squaredNorm(); + r.get(l).row(i).head<3>() = md::vec(i, 2 * i, 4 * i); + r.get(l).row(i).tail<3>() = md::vec(5 * i, 6 * i, 7 * i); } norm = sqrt(norm); @@ -175,8 +170,8 @@ TEST_CASE("Operating states") r.get(p2).row(0).head<3>() = md::vec(1.0, 2.0, 3.0); r.get(p2).row(0).tail<3>() = md::vec(4.0, 5.0, 6.0); for (unsigned int i = 0; i < 19; i++) { - r.get(l).row(i).head<3>() = md::vec(i, 2*i, 4*i); - r.get(l).row(i).tail<3>() = md::vec(5*i, 6*i, 7*i); + r.get(l).row(i).head<3>() = md::vec(i, 2 * i, 4 * i); + r.get(l).row(i).tail<3>() = md::vec(5 * i, 6 * i, 7 * i); } r2.get() = r.get() * 2.0; diff --git a/tests/time_schemes.cpp b/tests/time_schemes.cpp index 8d27440d..f9f50dc6 100644 --- a/tests/time_schemes.cpp +++ b/tests/time_schemes.cpp @@ -70,26 +70,26 @@ static std::vector schemes({ "Euler", "ACA15", "ACA20", "Wilson20" }); -static std::vector dts({ "1.5E-4", // Euler - "1.8E-4", // Heun - "2.6E-4", // RK2 - "4.9E-4", // RK4 +static std::vector dts({ "1.5E-4", // Euler + "1.8E-4", // Heun + "2.6E-4", // RK2 + "4.9E-4", // RK4 // "1.4E-4", // AB2 // "1.1E-4", // AB3 // "1.0E-4", // AB5 - "6.0E-4", // BEuler5 - "1.0E-3", // BEuler10 - "1.2E-3", // BEuler15 - "1.5E-3", // BEuler20 - "1.0E-3", // Midpoint5 - "1.9E-3", // Midpoint10 - "2.5E-3", // Midpoint15 - "3.0E-3", // Midpoint20 - "9.4E-4", // ACA5 - "1.5E-3", // ACA10 - "1.5E-3", // ACA15 - "1.6E-3", // ACA20 - "2.4E-3"}); // Wilson20 + "6.0E-4", // BEuler5 + "1.0E-3", // BEuler10 + "1.2E-3", // BEuler15 + "1.5E-3", // BEuler20 + "1.0E-3", // Midpoint5 + "1.9E-3", // Midpoint10 + "2.5E-3", // Midpoint15 + "3.0E-3", // Midpoint20 + "9.4E-4", // ACA5 + "1.5E-3", // ACA10 + "1.5E-3", // ACA15 + "1.6E-3", // ACA20 + "2.4E-3" }); // Wilson20 using namespace std; diff --git a/tests/viv.cpp b/tests/viv.cpp index 071d2007..a325f76b 100644 --- a/tests/viv.cpp +++ b/tests/viv.cpp @@ -41,10 +41,13 @@ #include #include #include +#include // NOTE: this is largely built on the pendulum test framework -#define TOL 1.0e-2 // absolute tolerance. In setting this up, max error was 0.008069, but this can vary slightly with every simulation +#define TOL \ + 1.0e-2 // absolute tolerance. In setting this up, max error was 0.008069, + // but this can vary slightly with every simulation bool compare(double v1, double v2, double tol) @@ -52,113 +55,82 @@ compare(double v1, double v2, double tol) return fabs(v1 - v2) <= tol; } -#define CHECK_VALUE(name, v1, v2, tol, t) \ - if (!compare(v1, v2, tol)) { \ - cerr << setprecision(8) << "Checking " << name \ - << " failed at t = " << t << " s. " << v1 << " was expected" \ - << " but " << v2 << " was computed" << endl; \ - MoorDyn_Close(system); \ - return false; \ +void +check_value(const char* name, double v1, double v2, double tol, double t) +{ + if (!compare(v1, v2, tol)) { + std::cerr << std::setprecision(8) << "Checking " << name + << " failed at t = " << t << " s. " << v1 << " was expected" + << " but " << v2 << " was computed" << std::endl; + throw std::runtime_error("Missmatching values"); } +} using namespace std; -/** @brief VIV frequency simulation and check - * @return true if the test worked, false otherwise - */ -bool -VIV() +TEST_CASE("VIV frequency simulation and check") { MoorDyn system = MoorDyn_Create("Mooring/viv/viv.txt"); - if (!system) { - cerr << "Failure Creating the Mooring system" << endl; - return false; - } + REQUIRE(system); unsigned int n_dof; - if (MoorDyn_NCoupledDOF(system, &n_dof) != MOORDYN_SUCCESS) { - MoorDyn_Close(system); - return false; - } - if (n_dof != 0) { - cerr << "0 DOFs were expected, but " << n_dof << "were reported" - << endl; - MoorDyn_Close(system); - return false; - } + REQUIRE(MoorDyn_NCoupledDOF(system, &n_dof) == MOORDYN_SUCCESS); + REQUIRE(n_dof == 0); - int err; - err = MoorDyn_Init(system, NULL, NULL); - if (err != MOORDYN_SUCCESS) { - cerr << "Failure during the mooring initialization: " << err << endl; - return false; - } + REQUIRE(MoorDyn_Init(system, NULL, NULL) == MOORDYN_SUCCESS); - // get the moordyn line object - const MoorDynLine line1 = MoorDyn_GetLine(system, 1); - + // get the moordyn line object + const MoorDynLine line1 = MoorDyn_GetLine(system, 1); + REQUIRE(line1); - const double T = 1/(2*1.04); // Target VIV period, fairten frequency is 2x target CF strain frequency of 1.04 Hz. - double dt = 0.0001; // time step (same as dtM) - double t = 0.0; // time - double ten = 0.0; // tension (initialize as zero) + const double T = + 1 / (2 * 1.04); // Target VIV period, fairten frequency is 2x target CF + // strain frequency of 1.04 Hz. + double dt = 0.0001; // time step (same as dtM) + double t = 0.0; // time + double ten = 0.0; // tension (initialize as zero) std::vector ten_peaks = { 0.0 }; // tension peaks? - std::vector peak_times = {}; // tracking the time of peaks (empty to start, will be filled in for every peak) - double d_peak = 0.0; // last peak tracker. For checking if there is a change in the peak - - while (t < 15) { // run for 15 seconds - - err = MoorDyn_Step(system, NULL, NULL, NULL, &t, &dt); - if (err != MOORDYN_SUCCESS) { - cerr << "Failure during the mooring step: " << err << endl; - return false; + std::vector + peak_times = {}; // tracking the time of peaks (empty to start, will be + // filled in for every peak) + double d_peak = + 0.0; // last peak tracker. For checking if there is a change in the peak + + while (t < 15) { // run for 15 seconds + REQUIRE(MoorDyn_Step(system, NULL, NULL, NULL, &t, &dt) == + MOORDYN_SUCCESS); + + REQUIRE(MoorDyn_GetLineFairTen(line1, &ten) == MOORDYN_SUCCESS); + + if (t > 10) { // only check period after 10 seconds. Before then, there + // isn't complete lock in + // check for peaks in tension. These are used to determine the + // period + const double d = fabs(ten - ten_peaks.back()); // tension delta + if (d > d_peak) + d_peak = d; + else { + ten_peaks.push_back(ten); + peak_times.push_back(t); + d_peak = 0.0; + } } - - err = MoorDyn_GetLineFairTen(line1, &ten); - if (err != MOORDYN_SUCCESS) { - cerr << "Failure getting the fairlead tension: " << err << endl; - return false; - } - - if (t > 10) { // only check period after 10 seconds. Before then, there isn't complete lock in - // check for peaks in tension. These are used to determine the period - const double d = fabs(ten - ten_peaks.back()); // tension delta - if (d > d_peak) - d_peak = d; - else { - ten_peaks.push_back(ten); - peak_times.push_back(t); - d_peak = 0.0; - } - } } - if (peak_times.size() == 0) cerr << "No peaks detected in fairten signal" << endl; // if no peaks something is wrong, like viv model was broken or disabled + REQUIRE(peak_times.size() != 0); - // Check period is correct + // Check period is correct for (unsigned int i = 2; i < peak_times.size(); i++) { - cout << "Target Period: " << T << " s. Calculated period: " << peak_times[i]-peak_times[i-2] << " s" << endl; - // check that peak_times[i]-peak_times[i-2] is within TOL of T - CHECK_VALUE("Period", T, peak_times[i]-peak_times[i-2], TOL, peak_times[i]); // note that peak_times[i]-peak_times[i-1] would be a half period - } - - err = MoorDyn_Close(system); - if (err != MOORDYN_SUCCESS) { - cerr << "Failure closing Moordyn: " << err << endl; - return false; + INFO("Target Period: " << T << " s. Calculated period: " + << peak_times[i] - peak_times[i - 2] << " s"); + // check that peak_times[i]-peak_times[i-2] is within TOL of T + // note that peak_times[i]-peak_times[i-1] would be a half period + REQUIRE_NOTHROW(check_value("Period", + T, + peak_times[i] - peak_times[i - 2], + TOL, + peak_times[i])); } - return true; -} - -/** @brief Runs all the test - * @return 0 if the tests have ran just fine. The index of the failing test - * otherwise - */ -int -main(int, char**) -{ - if (!VIV()) - return 1; - return 0; + REQUIRE(MoorDyn_Close(system) == MOORDYN_SUCCESS); } diff --git a/tests/wavekin.cpp b/tests/wavekin.cpp index c0601de8..7caf005a 100644 --- a/tests/wavekin.cpp +++ b/tests/wavekin.cpp @@ -69,7 +69,8 @@ current(double PARAM_UNUSED t, void wave(double t, const double* r, double* u, double* du) { - const double pi = 3.1416, g = 9.80665, A = 1.5, L = 10.0, T = 15.0, H = 50.0; + const double pi = 3.1416, g = 9.80665, A = 1.5, L = 10.0, T = 15.0, + H = 50.0; memset(u, 0.0, 3 * sizeof(double)); memset(du, 0.0, 3 * sizeof(double)); const double k = 2.0 * L / pi, w = 2.0 * T / pi, zf = (1.0 + r[2] / H); diff --git a/tests/wilson.cpp b/tests/wilson.cpp index 734da76a..e60a14c5 100644 --- a/tests/wilson.cpp +++ b/tests/wilson.cpp @@ -124,8 +124,8 @@ TEST_CASE("quasi_static_chain with wilson20") // Compute the static tension int num_lines = 1; float fh, fv, ah, av; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair0 = sqrt(fh * fh + fv * fv); const double ffair_ref0 = 1.e3 * STATIC_FAIR_TENSION; const double fanch0 = sqrt(ah * ah + av * av); @@ -167,8 +167,8 @@ TEST_CASE("quasi_static_chain with wilson20") if (t_ref < 0.0) continue; - REQUIRE(MoorDyn_GetFASTtens( - system, &num_lines, &fh, &fv, &ah, &av) == MOORDYN_SUCCESS); + REQUIRE(MoorDyn_GetFASTtens(system, &num_lines, &fh, &fv, &ah, &av) == + MOORDYN_SUCCESS); const double ffair = sqrt(fh * fh + fv * fv) - ffair0; const double ffair_ref = 1.e3 * ref_data[i_ref][3] - ffair_ref0; const double fanch = sqrt(ah * ah + av * av) - fanch0; diff --git a/wrappers/matlab/MoorDynM_GetBodyM.cpp b/wrappers/matlab/MoorDynM_GetBodyM.cpp index cd97901f..8e9b89dc 100644 --- a/wrappers/matlab/MoorDynM_GetBodyM.cpp +++ b/wrappers/matlab/MoorDynM_GetBodyM.cpp @@ -43,7 +43,7 @@ MOORDYNM_MEX_FUNCTION_BEGIN(MoorDynBody, 1, 1) const int err = MoorDyn_GetBodyM(instance, m); MOORDYNM_CHECK_ERROR(err); - outputs[0] = factory.createArray( - { 6, 6 }, &(m[0][0]), &(m[0][0]) + 6 * 6); + outputs[0] = + factory.createArray({ 6, 6 }, &(m[0][0]), &(m[0][0]) + 6 * 6); } MOORDYNM_MEX_FUNCTION_END diff --git a/wrappers/matlab/MoorDynM_GetLineNodeM.cpp b/wrappers/matlab/MoorDynM_GetLineNodeM.cpp index 1ec0bfa0..8ee2ba40 100644 --- a/wrappers/matlab/MoorDynM_GetLineNodeM.cpp +++ b/wrappers/matlab/MoorDynM_GetLineNodeM.cpp @@ -44,7 +44,7 @@ MOORDYNM_MEX_FUNCTION_BEGIN(MoorDynLine, 2, 1) const int err = MoorDyn_GetLineNodeM(instance, i, m); MOORDYNM_CHECK_ERROR(err); - outputs[0] = factory.createArray( - { 3, 3 }, &(m[0][0]), &(m[0][0]) + 3 * 3); + outputs[0] = + factory.createArray({ 3, 3 }, &(m[0][0]), &(m[0][0]) + 3 * 3); } MOORDYNM_MEX_FUNCTION_END diff --git a/wrappers/matlab/MoorDynM_GetPointM.cpp b/wrappers/matlab/MoorDynM_GetPointM.cpp index 19321ba9..adb59ae0 100644 --- a/wrappers/matlab/MoorDynM_GetPointM.cpp +++ b/wrappers/matlab/MoorDynM_GetPointM.cpp @@ -43,7 +43,7 @@ MOORDYNM_MEX_FUNCTION_BEGIN(MoorDynPoint, 1, 1) const int err = MoorDyn_GetPointM(instance, m); MOORDYNM_CHECK_ERROR(err); - outputs[0] = factory.createArray( - { 3, 3 }, &(m[0][0]), &(m[0][0]) + 3 * 3); + outputs[0] = + factory.createArray({ 3, 3 }, &(m[0][0]), &(m[0][0]) + 3 * 3); } MOORDYNM_MEX_FUNCTION_END diff --git a/wrappers/matlab/MoorDynM_GetRodM.cpp b/wrappers/matlab/MoorDynM_GetRodM.cpp index 4275f5ff..5419c4bc 100644 --- a/wrappers/matlab/MoorDynM_GetRodM.cpp +++ b/wrappers/matlab/MoorDynM_GetRodM.cpp @@ -43,7 +43,7 @@ MOORDYNM_MEX_FUNCTION_BEGIN(MoorDynRod, 1, 1) const int err = MoorDyn_GetRodM(instance, m); MOORDYNM_CHECK_ERROR(err); - outputs[0] = factory.createArray( - { 6, 6 }, &(m[0][0]), &(m[0][0]) + 6 * 6); + outputs[0] = + factory.createArray({ 6, 6 }, &(m[0][0]), &(m[0][0]) + 6 * 6); } MOORDYNM_MEX_FUNCTION_END diff --git a/wrappers/matlab/MoorDynM_Serialize.cpp b/wrappers/matlab/MoorDynM_Serialize.cpp index 80363908..42ddbd6d 100644 --- a/wrappers/matlab/MoorDynM_Serialize.cpp +++ b/wrappers/matlab/MoorDynM_Serialize.cpp @@ -48,6 +48,5 @@ MOORDYNM_MEX_FUNCTION_BEGIN(MoorDyn, 1, 1) MOORDYNM_CHECK_ERROR(err); outputs[0] = factory.createArray( { 1, v.size() }, v.data(), v.data() + v.size()); - } MOORDYNM_MEX_FUNCTION_END diff --git a/wrappers/python/cmoordyn.cpp b/wrappers/python/cmoordyn.cpp index 39521c38..bd78c45c 100644 --- a/wrappers/python/cmoordyn.cpp +++ b/wrappers/python/cmoordyn.cpp @@ -1255,15 +1255,15 @@ waves_getkin(PyObject*, PyObject* args) MoorDynSeafloor seabed = NULL; if (seafloor != Py_None) { - seabed = (MoorDynSeafloor)PyCapsule_GetPointer( - seafloor, seafloor_capsule_name); + seabed = (MoorDynSeafloor)PyCapsule_GetPointer(seafloor, + seafloor_capsule_name); if (!seabed) return NULL; } double u[3], ud[3], zeta, pdyn; - const int err = MoorDyn_GetWavesKin( - instance, x, y, z, u, ud, &zeta, &pdyn, seabed); + const int err = + MoorDyn_GetWavesKin(instance, x, y, z, u, ud, &zeta, &pdyn, seabed); if (err != 0) { PyErr_SetString(PyExc_RuntimeError, "MoorDyn reported an error"); return NULL; @@ -2882,7 +2882,6 @@ line_get_node_m(PyObject*, PyObject* args) return lst; } - /** @brief Wrapper to MoorDyn_GetLineFairTen() function * @param args Python passed arguments * @return The tension magnitude @@ -2991,10 +2990,7 @@ static PyMethodDef moordyn_methods[] = { METH_VARARGS, "deallocates the variables used by MoorDyn" }, { "get_waves", get_waves, METH_VARARGS, "Get the waves manager instance" }, - { "get_seafloor", - get_seafloor, - METH_VARARGS, - "Get the seafloor instance" }, + { "get_seafloor", get_seafloor, METH_VARARGS, "Get the seafloor instance" }, { "ext_wave_init", ext_wave_init, METH_VARARGS, @@ -3074,7 +3070,10 @@ static PyMethodDef moordyn_methods[] = { { "body_get_pos", body_get_pos, METH_VARARGS, "Get the body pos" }, { "body_get_angle", body_get_angle, METH_VARARGS, "Get the body angle" }, { "body_get_vel", body_get_vel, METH_VARARGS, "Get the body velocity" }, - { "body_get_angvel", body_get_angvel, METH_VARARGS, "Get the body ang vel" }, + { "body_get_angvel", + body_get_angvel, + METH_VARARGS, + "Get the body ang vel" }, { "body_get_force", body_get_force, METH_VARARGS, "Get the body force" }, { "body_get_m", body_get_m, METH_VARARGS, "Get the body mass" }, { "body_save_vtk", @@ -3104,18 +3103,9 @@ static PyMethodDef moordyn_methods[] = { "Save a .vtp file of the rod" }, { "point_get_id", point_get_id, METH_VARARGS, "Get the point id" }, { "point_get_type", point_get_type, METH_VARARGS, "Get the point type" }, - { "point_get_pos", - point_get_pos, - METH_VARARGS, - "Get the point position" }, - { "point_get_vel", - point_get_vel, - METH_VARARGS, - "Get the point velocity" }, - { "point_get_force", - point_get_force, - METH_VARARGS, - "Get the point force" }, + { "point_get_pos", point_get_pos, METH_VARARGS, "Get the point position" }, + { "point_get_vel", point_get_vel, METH_VARARGS, "Get the point velocity" }, + { "point_get_force", point_get_force, METH_VARARGS, "Get the point force" }, { "point_get_m", point_get_m, METH_VARARGS, "Get the point mass matrix" }, { "point_get_nattached", point_get_nattached,