File: miscAccelerationsAtmosphericDrag.h

package info (click to toggle)
groops 0%2Bgit20250907%2Bds-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 11,140 kB
  • sloc: cpp: 135,607; fortran: 1,603; makefile: 20
file content (180 lines) | stat: -rw-r--r-- 6,865 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/***********************************************/
/**
* @file miscAccelerationsAtmosphericDrag.h
*
* @brief Atmospheric drag.
* @see MiscAccelerations
*
* @author Beate Klinger
* @author Sandro Krauss
* @date 2015-12-10
*
*/
/***********************************************/

#ifndef __GROOPS_MISCACCELERATIONSATMOSPHERICDRAG__
#define __GROOPS_MISCACCELERATIONSATMOSPHERICDRAG__

// Latex documentation
#ifdef DOCSTRING_MiscAccelerations
static const char *docstringMiscAccelerationsAtmosphericDrag = R"(
\subsection{AtmosphericDrag}\label{miscAccelerationsType:atmosphericDrag}
Atmospheric drag model.
Algorithm for the atmospheric drag modelling is based on the free molecule flow
theory by Sentman 1961. An analytical expression of this treatise is given in
Moe and Moe 2005.

Sentman L. (1961), Free molecule flow theory and its application to the determination
of aerodynamic forces, Technical report.

Moe K., Moe M. M. (2005), Gas-surface interactions and satellite drag coefficients,
Planetary and Space Science 53(8), 793-801, doi:10.1016/j.pss.2005.03.005.

Optional determination steps:
Turn temperature on or off.
In the first case, the model mentioned above is applied, which estimates variable drag
and lift coefficients - in the latter case a constant drag coefficient can be specified.

Turn wind on/off:
It enables the usage of the Horizontal Wind Model 2014 to add additional thermospheric
winds in the calculation process.
)";
#endif

/***********************************************/

#include "classes/thermosphere/thermosphere.h"
#include "classes/miscAccelerations/miscAccelerations.h"

/***** CLASS ***********************************/

/** @brief Atmospheric drag.
 * @ingroup miscAccelerationsGroup
 * @see MiscAccelerations */
class MiscAccelerationsAtmosphericDrag : public MiscAccelerationsBase
{
  ThermospherePtr thermosphere;
  Bool            useTemperature, useWind;
  Vector3d        omega;
  Double          factor;

public:
  MiscAccelerationsAtmosphericDrag(Config &config);

  Vector3d acceleration(SatelliteModelPtr satellite, const Time &time, const Vector3d &position, const Vector3d &velocity,
                        const Rotary3d &rotSat, const Rotary3d &rotEarth, EphemeridesPtr ephemerides) override;

  static Vector3d force(SatelliteModelPtr satellite, const Vector3d &direction, Double velocity, Double density, Double temperature);
};

/***********************************************/

inline MiscAccelerationsAtmosphericDrag::MiscAccelerationsAtmosphericDrag(Config &config)
{
  try
  {
    Double angleVelocity;

    readConfig(config, "thermosphere",        thermosphere,   Config::MUSTSET, "", "");
    readConfig(config, "earthRotation",       angleVelocity,  Config::DEFAULT, "7.29211585531e-5", "[rad/s]");
    readConfig(config, "considerTemperature", useTemperature, Config::DEFAULT, "1",   "compute drag and lift, otherwise simple drag coefficient is used");
    readConfig(config, "considerWind",        useWind,        Config::DEFAULT, "1",   "");
    readConfig(config, "factor",              factor,         Config::DEFAULT, "1.0", "the result is multiplied by this factor");
    if(isCreateSchema(config)) return;

    omega = Vector3d(0, 0, angleVelocity);
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

/***********************************************/

inline Vector3d MiscAccelerationsAtmosphericDrag::acceleration(SatelliteModelPtr satellite, const Time &time,
                                                               const Vector3d &position, const Vector3d &velocity,
                                                               const Rotary3d &rotSat, const Rotary3d &rotEarth, EphemeridesPtr /*ephemerides*/)
{
  try
  {
    if(!satellite)
      throw(Exception("No satellite model given"));

    Double   density, temperature;
    Vector3d wind;
    thermosphere->state(time, rotEarth.rotate(position), density, temperature, wind);
    if(!useTemperature)
      temperature = 0;
    if(!useWind)
      wind = Vector3d();

    // direction and speed of thermosphere relative to satellite in SRF
    Vector3d direction = rotSat.inverseRotate(rotEarth.inverseRotate(wind) + crossProduct(omega, position) - velocity);
    const Double v = direction.normalize();
    Vector3d acc = (factor/satellite->mass) * rotEarth.rotate(rotSat.rotate(force(satellite, direction, v, density, temperature)));
    if(std::isnan(acc.r()))
    {
      logWarning<<satellite->satelliteName<<" (altitude "<<1e-3*(position.r()-DEFAULT_R)<<" km, velocity "<<1e-3*v<<" km/s)"
                <<"atmosphericDrag is NaN (set to zero) at "<<time.dateTimeStr()<<Log::endl;
      acc = Vector3d();
    }
    return acc;
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

/***********************************************/

inline Vector3d MiscAccelerationsAtmosphericDrag::force(SatelliteModelPtr satellite, const Vector3d &direction, Double velocity, Double density, Double temperature)
{
  try
  {
    constexpr Double R     = 8.3144;    // universal gas constant [J mol-1 K-1]
    constexpr Double M     = 15.5/1000; // average modelcular mass [kg/mol]
    constexpr Double alpha = 0.9;       // accomodation coefficientDrag [-]
    constexpr Double Tw    = 273;       // temperature of the surface [K]

    Vector3d F;
    for(UInt i=0; i<satellite->surfaces.size(); i++)
    {
      auto &surface = satellite->surfaces.at(i);
      if((surface.type == SatelliteModel::Surface::PLATE) || (surface.type == SatelliteModel::Surface::GRACESHADOW))
      {
        const Double cosPhi = -inner(direction, surface.normal);

        if(temperature > 0)
        {
          const Vector3d ul   = crossProduct(direction, crossProduct(direction, surface.normal));
          const Double   s    = velocity/std::sqrt(2*R*temperature/M); // molecular speed ratio
          const Double   P    = std::exp(-std::pow(cosPhi*s, 2))/s;
          const Double   G    = 1/(2*s*s);
          const Double   Z    = 1 + std::erf(cosPhi*s);
          const Double   x    = std::sqrt(1./6.*(1 + alpha * (3*R*Tw/(velocity*velocity)-1))) * (cosPhi*std::sqrt(PI)*Z+P);
          F += 0.5 * density * surface.area *velocity*velocity * ((P/std::sqrt(PI) + cosPhi*((1+G)*Z+x)) * direction + (G*Z+x) * ul);
        }
        else if(cosPhi > 0) // simple drag coefficient
          F += 0.5 * density * surface.area * cosPhi * velocity*velocity * satellite->coefficientDrag * direction;
      }
      else if (surface.type == SatelliteModel::Surface::SPHERE)
      {
        F += 0.5 * density * surface.area * velocity*velocity * satellite->coefficientDrag * direction;
      }
      else
        throw(Exception("cylinder not implemented yet"));
    } // for(i=surface)

    return F;
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

/***********************************************/

#endif