FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
CableRMWaterLoad.h
1#pragma once
2
9#include "Cable.h"
10#include <fhsim_environment/hydrodynamics/BodySubmergence.h>
11#include <fhsim_environment/hydrodynamics/WetCylinderLaw.h>
12
13#include "cable/GaussPointDrag.h"
14#include "cable/WetCylinderWater.h"
15
16#include <sfh/constants.h>
17
18#include <Eigen/Eigen>
19
20#include <cmath>
21#include <fhsim_environment/EnvironmentProvider.h>
22#include <fhsim_environment/ElementFlowInteraction.h>
23#include <marenv/marenv.h>
24
25namespace RbCable
26{
29{
30 double length;
31 double radius;
32 bool kelp;
33 double kelpWeight;
34};
35
36const double kWaterDensity = marenv::seawaterDensity;
37const double kAirDensity = 1.025;
38
40inline environment::wet_cylinder::WetCylinder CylinderOf(const ElementProperties& element)
41{
42 environment::wet_cylinder::WetCylinder cylinder {};
43 cylinder.length = element.length;
44 cylinder.radius = element.radius;
45 cylinder.volume = sfh::pi * element.radius * element.radius * element.length;
46 cylinder.waterDensity = kWaterDensity;
47 cylinder.inertia = environment::wet_cylinder::AddedMassInertia::NoCoriolis;
48 return cylinder;
49}
50
83inline double AddAboveSeabedLoad(const environment::wake::ElementFlowInteraction& flow, double T, const Eigen::Vector3d& P, const Eigen::Vector3d& V,
84 const Eigen::Vector3d& W, const Eigen::Vector3d& axis, const ElementProperties& element, int point, Eigen::Matrix<double, 6, 1>& load,
85 const wet_cylinder_water::EndWater* gaussWater = nullptr)
86{
87 using vec3 = Eigen::Vector3d;
88 // The wet fraction of the element's cylinder against the wave surface over its ends (owner
89 // ruling R104, extending R66): the water part of the load takes f, the air part 1 - f. It was
90 // all water or all air by the centre's side of the surface.
91 const auto water = gaussWater ? wet_cylinder_water::SampleWaterGivenVelocity(flow, T, P.data(), axis.data(), element.length, element.radius, gaussWater->Mean())
92 : wet_cylinder_water::SampleWater(flow, T, P.data(), axis.data(), element.length, element.radius, point);
93 const double f = water.wetFraction;
94 if (f > 0.0) {
95 const double rho = kWaterDensity;
96 load(2) -= element.length * element.radius * element.radius * sfh::pi * rho * marenv::gravity * f;
97
98 vec3 v = V - vec3(water.waterVelocity.data());
99
100 // The wet-cylinder law (fhsim_environment): the Coriolis force of the turning added mass, on the relative velocity
101 // (MARE-0314, MARE-0323), the normal drag and the skin friction along the axis (R68) by the independence principle,
102 // Cd on |v_n| D / ν, Ct on |v| D / ν (ENV-0104, ENV-0105), the skin-friction moment on the spin about the axis, relative
103 // to the non-rotating water (MARE-0376), and the Morison inertia force (1 + Ca) rho f V a_n normal to the axis (owner
104 // ruling R104, extending R67; MARE-0314).
105 using environment::wet_cylinder::Vector;
106 const environment::wet_cylinder::WetCylinderState state {f, Vector {V(0), V(1), V(2)}, water.waterVelocity, Vector {W(0), W(1), W(2)}, Vector {axis(0), axis(1), axis(2)},
107 water.waveAcceleration};
108 const auto cylinder = CylinderOf(element);
109 const auto law = gaussWater ? environment::wet_cylinder::WaterLoadWithoutDrag(cylinder, environment::wet_cylinder::ReynoldsDrag {}, state)
110 : environment::wet_cylinder::WaterLoad(cylinder, environment::wet_cylinder::ReynoldsDrag {}, state);
111 load.segment<3>(0) += vec3(law.coriolis.data());
112
113 double v_abs2 = v.squaredNorm();
114 if (v_abs2 > 0) {
115 vec3 vz = v.dot(axis) * axis;
116 vec3 vxy = v - vz;
117
118 double v_abs = v.norm(); /*Kelp application v2*/
119 double vxy_abs = vxy.norm();
120
121 // v . v_xy = |v_xy|^2, so cos(theta) = |v_xy| / |v|, which tends to 0 as v_xy does:
122 // 0 for flow along the axis, where the quotient below is 0/0 (MARE-0221).
123 double cosTheta = vxy_abs > 0 ? v.dot(vxy) / (v_abs * vxy_abs) : 0.0; /*Kelp application v2*/
124
125 // Sugar kelp rope application - start
126 if (element.kelp) {
127 load.segment<3>(0) += -0.2 * (1 + 4 * cosTheta) * element.kelpWeight * element.length * (1.0731 * v_abs * v + 1.0509 * v) * f; /*Kelp application v2*/
128 }
129 // Sugar kelp rope application - end
130 if (!gaussWater)
131 load.segment<3>(0) += vec3(law.drag.data());
132 }
133 if (gaussWater) {
134 const auto gauss = wet_cylinder_water::GaussPointDragLoad(cylinder, f, V, W, axis, *gaussWater);
135 load.segment<3>(0) += gauss.force;
136 load.segment<3>(3) += gauss.moment;
137 }
138 load.segment<3>(3) += vec3(law.torsion.data());
139 if (water.waveAcceleration)
140 load.segment<3>(0) += vec3(law.morison.data());
141 }
142 if (f < 1.0) {
143 const double rho = kAirDensity;
144 vec3 vz = V.dot(axis) * axis;
145 vec3 vxy = V - vz;
146 double vz_abs = vz.norm();
147 double vxy_abs = vxy.norm();
148
149 double Cd = 1;
150 double Ct = 1;
151
152 load(2) -= element.length * element.radius * element.radius * sfh::pi * rho * marenv::gravity * (1.0 - f);
153 load.segment<3>(0) -= rho * element.radius * element.length * (Cd * vxy_abs * vxy + Ct * vz_abs * vz) * (1.0 - f);
154 }
155 return f;
156}
157
158} // namespace RbCable
constexpr double gravity
Gravity constant.
Definition marenv.h:19
constexpr double seawaterDensity
Ocean water density.
Definition marenv.h:20
The properties of a CableRM element.
Definition CableRMWaterLoad.h:29
bool kelp
True for a kelp rope.
Definition CableRMWaterLoad.h:32
double length
The element length [m].
Definition CableRMWaterLoad.h:30
double kelpWeight
The kelp biomass per metre [N/m].
Definition CableRMWaterLoad.h:33
double radius
The element radius [m].
Definition CableRMWaterLoad.h:31
double wetFraction
f in [0, 1].
Definition WetCylinderWater.h:33