File: instrumentAccelerometer2ThermosphericDensity.cpp

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 (142 lines) | stat: -rw-r--r-- 6,179 bytes parent folder | download | duplicates (2)
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
/***********************************************/
/**
* @file instrumentAccelerometer2ThermosphericDensity.cpp
*
* @brief Estimate neutral density from accelerometer data.
*
* @author Sandro Krauss
* @date 2020-06-22
*/
/***********************************************/

// Latex documentation
#define DOCSTRING docstring
static const char *docstring = R"(
This program estimates neutral mass densities along the satellite trajectory based on \file{accelerometer data}{instrument}.
In order to determine the neutral mass density the accelerometer input should only reflect the accelerations due to drag
(e.g. \configClass{miscAccelerations:atmosphericDrag}{miscAccelerationsType:atmosphericDrag}).
Thus, influences from solar and Earth radiation pressure must be reduced beforehand.
)";

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

#include "programs/program.h"
#include "files/fileMatrix.h"
#include "files/fileSatelliteModel.h"
#include "classes/earthRotation/earthRotation.h"
#include "classes/parametrizationAcceleration/parametrizationAcceleration.h"
#include "classes/thermosphere/thermosphere.h"
#include "classes/miscAccelerations/miscAccelerationsAtmosphericDrag.h"
#include "classes/ephemerides/ephemerides.h"

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

/** @brief Estimate neutral density from accelerometer data.
* @ingroup programsGroup */
class InstrumentAccelerometer2ThermosphericDensity
{
public:
  void run(Config &config, Parallel::CommunicatorPtr comm);
};

GROOPS_REGISTER_PROGRAM(InstrumentAccelerometer2ThermosphericDensity, PARALLEL, "Estimate neutral density from accelerometer data", Instrument)

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

void InstrumentAccelerometer2ThermosphericDensity::run(Config &config, Parallel::CommunicatorPtr comm)
{
  try
  {
    FileName         fileNameOutDensity;
    FileName         fileNameSatellite;
    FileName         fileNameOrbit, fileNameStarCamera, fileNameAccelerometer;
    EarthRotationPtr earthRotation;
    ThermospherePtr  thermosphere;
    Bool             useTemperature, useWind;
    EphemeridesPtr   ephemerides;

    readConfig(config, "outputfileDensity",      fileNameOutDensity,     Config::MUSTSET,  "",    "MISCVALUE (kg/m^3)");
    readConfig(config, "satelliteModel",         fileNameSatellite,      Config::OPTIONAL, "{groopsDataDir}/satelliteModel/", "satellite macro model");
    readConfig(config, "inputfileOrbit",         fileNameOrbit,          Config::MUSTSET,  "",    "");
    readConfig(config, "inputfileStarCamera",    fileNameStarCamera,     Config::MUSTSET,  "",    "");
    readConfig(config, "inputfileAccelerometer", fileNameAccelerometer,  Config::MUSTSET,  "",    "add non-gravitational forces in satellite reference frame");
    readConfig(config, "thermosphere",           thermosphere,           Config::MUSTSET,  "",    "used to compute temperature and wind");
    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, "earthRotation",          earthRotation,          Config::MUSTSET,  "",    "");
    readConfig(config, "ephemerides",            ephemerides,            Config::OPTIONAL, "jpl", "");
    if(isCreateSchema(config)) return;

    // open and test instrument files
    // ------------------------------
    InstrumentFile orbitFile, starCameraFile, accelerometerFile;
    orbitFile.open(fileNameOrbit);
    starCameraFile.open(fileNameStarCamera);
    accelerometerFile.open(fileNameAccelerometer);
    InstrumentFile::checkArcCount({orbitFile, starCameraFile, accelerometerFile});

    SatelliteModelPtr satellite;
    if(!fileNameSatellite.empty())
      readFileSatelliteModel(fileNameSatellite, satellite);

    logStatus<<"computing density"<<Log::endl;
    std::vector<Arc> arcList(orbitFile.arcCount());
    Parallel::forEach(arcList, [&](UInt arcNo)
    {
      OrbitArc      orbit      = orbitFile.readArc(arcNo);
      StarCameraArc starCamera = starCameraFile.readArc(arcNo);
      AccelerometerArc accelerometer = accelerometerFile.readArc(arcNo);
      Arc::checkSynchronized({orbit, starCamera, accelerometer});

      MiscValueArc output;
      for(UInt k=0; k<orbit.size(); k++)
      {
        Rotary3d rotSat;
        if(starCamera.size())
          rotSat = starCamera.at(k).rotary;
        const Time     time     = orbit.at(k).time;
        const Rotary3d rotEarth = earthRotation->rotaryMatrix(time);
        const Vector3d omega    = earthRotation->rotaryAxis(orbit.at(k).time);

        if(satellite)
        {
          Vector3d positionSun;
          if(ephemerides)
            positionSun = ephemerides->position(time, Ephemerides::SUN);
          satellite->changeState(time, orbit.at(k).position, orbit.at(k).velocity, positionSun, rotSat, rotEarth);
        }

        Double   modelDensity, temperature;
        Vector3d wind;
        thermosphere->state(time, rotEarth.rotate(orbit.at(k).position), modelDensity, 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, orbit.at(k).position) - orbit.at(k).velocity);
        const Double v = direction.normalize();
        const Vector3d acc = (1./satellite->mass) * MiscAccelerationsAtmosphericDrag::force(satellite, direction, v, 1., temperature);

        MiscValueEpoch epoch;
        epoch.time  = time;
        epoch.value = accelerometer.at(k).acceleration.x() / acc.x(); // density
        output.push_back(epoch);
      }
      return output;
    }, comm);

    if(Parallel::isMaster(comm))
    {
      logStatus<<"write density data to file <"<<fileNameOutDensity<<">"<<Log::endl;
      InstrumentFile::write(fileNameOutDensity, arcList);
    }
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

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