• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nasa / cml / 30298859408

27 Jul 2026 07:34PM UTC coverage: 90.212% (-0.002%) from 90.214%
30298859408

Pull #50

github

web-flow
Merge b18566236 into e2fa79540
Pull Request #50: Create cppcheck action

7811 of 8492 branches covered (91.98%)

Branch coverage included in aggregate %.

23 of 29 new or added lines in 22 files covered. (79.31%)

1 existing line in 1 file now uncovered.

17866 of 19971 relevant lines covered (89.46%)

115993.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.98
/models/dynamics/state_initialize/state_initialize/src/state_initialize.cc
1
/*******************************************************************************
2

3
PURPOSE:
4
   (Provide the capability to initialize the state from a number of potential
5
   sources.  This class inherits from the JEOD BodyAction class and combines
6
   the capabilities of JEOD's DynBodyInitState with CML's ORBITAL_ELEMENTS,
7
   ORB_INIT, and ICOPT models, and CEV's Corr_State_Init_T and
8
   State_Init_Exec_T structures and the state_init_exec method.)
9

10
REFERENCE:
11
  (This is a reworking of the following models from old CML:
12
    cml/models/dynamics/state_init_exec/src/state_init_exec.cpp
13
    cml/models/dynamics/icopt
14
    cml/dynamics/pom/src/rvmat.c
15
    cml/models/dynamics/orbital
16
    cev/models/dynamics/orbital_body
17
    )
18

19
PROGRAMMERS:
20
   (((Gary Turner) (OSR) (September 2014) (New))
21
 ******************************************************************************/
22

23

24
#include <random> // default_random_engine,
25
                  // uniform_real_distribution,
26
                  // normal_distribution
27

28

29
#include "jeod/models/utils/math/include/vector3.hh"
30
#include "jeod/models/utils/math/include/matrix3x3.hh"
31
#include "jeod/models/utils/memory/include/jeod_alloc.hh"
32
#include "jeod/models/utils/ref_frames/include/ref_frame.hh"
33
#include "jeod/models/dynamics/body_action/include/body_action_messages.hh"
34
#include "jeod/models/dynamics/dyn_body/include/dyn_body.hh"
35

36
#include "../include/state_initialize.hh"
37

38
/*****************************************************************************
39
Constructor
40
*****************************************************************************/
41
StateInitialize::StateInitialize()
229✔
42
  :
43
  // public values:
44
  position_input_data_type(Unspecified),
45
  velocity_input_data_type(Unspecified),
46
  attitude_input_data_type(Unspecified),
47
  att_rate_input_data_type(Unspecified),
48
  orb_elem_init(),
49
  trans_init(),
50
  rot_init(),
51
  ned_rot_init(),
52
  correlation(),
53
  monte_carlo_dispersion(trans_init),
229✔
54
  TR_param(),
55
  planet_name(),
56
  ref_point_altitude(0.0),
57
  ref_point_latitude(0.0),
58
  ref_point_longitude(0.0),
59
  TR_geodetic_altitude(0.0),
60
  TR_theta_Rng(0.0),
61
  TR_theta_Rot(0.0),
62
  TR_phi_Cross(0.0),
63
  rot_ref_latitude(0.0),
64
  rot_ref_longitude(0.0),
65
  rot_ref_azimuth(0.0),
66
  speed(0.0),
67
  flight_path_angle(0.0),
68
  azimuth(0.0),
69
  TR_Lambda(0.0),
70
  yaw(0.0),
71
  roll(0.0),
72
  pitch(0.0),
73
  angle_of_bank(0.0),
74
  angle_of_sideslip(0.0),
75
  angle_of_attack(0.0),
76
  T_inrtl_body{{1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{0.0, 0.0, 1.0}},
77
  ref_body_sequence_override(jeod::Orientation::NoSequence),
78
  roll_rate_body(0.0),
79
  pitch_rate_body(0.0),
80
  yaw_rate_body(0.0),
81
  max_rate_random(0.0),
82
  att_random_seed(1),
83
  att_rate_random_seed(2),
84
  free_stream_velocity{0.0, 0.0, 0.0},
85
  // protected values:
86
  initialized(false),
87
  planet(nullptr),
88
  use_orbital_init(false),
89
  use_trans_init(true),
90
  use_rot_init(true),
91
  use_ned_rot_init(false),
92
  use_trans_init_passthrough(false),
93
  use_rot_init_passthrough(false),
94
  use_pfix_frame_trans(false),
95
  pfix_ref_point_state_generated(false),
96
  use_veh_position_as_reference(false),
97
  populate_trans_init_pos_from_pfix(false),
98
  populate_trans_init_vel_from_pfix(false),
99
  velocity_is_relative_to_inertial(false),
100
  requires_free_stream_velocity(false),
101
  populate_rot_init_transform_source(RITS_None),
102
  z_axis_points_up(false),
103
  increment_rot_rate_init_with_pfix(false),
104
  pfix_position{0.0, 0.0, 0.0},
105
  pfix_velocity{0.0, 0.0, 0.0},
106
  omega_cross_r{0.0, 0.0, 0.0},
107
  T_pfix_reference{{1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{0.0, 0.0, 1.0}},
108
  T_inrtl_reference{{1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{0.0, 0.0, 1.0}},
109
  T_reference_body{{1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{0.0, 0.0, 1.0}},
110
  E_pfix_reference{0.0, 0.0, 0.0},
111
  E_reference_body{0.0, 0.0, 0.0},
112
  random_value(0.0),
113
  random_unit_vector{0.0, 0.0, 0.0},
114
  force_match_trans(false),
115
  force_match_rot(false)
458✔
116
{}
229✔
117

118

119
/*****************************************************************************
120
initialize
121
Purpose:(Initializes the BodyAction and contained body actions.)
122
Reference: (cml/models/dynamics/state_init_exec/src/state_init_exec.cpp:80:215
123
            Note - the options:
124
            INIT_EXEC_PRE_ORB_INIT is not implemented
125
            INIT_EXEC_PRE_ICOPT is covered by options except OrbitalElements
126
            INIT_EXEC_PRE_OE2CAR is covered by option OrbitalElements.
127
            )
128
*****************************************************************************/
129
void
130
StateInitialize::initialize(
190✔
131
      jeod::DynManager & dyn_manager)
132
{
133

134
  // find_planet is a DynBodyInit method, accessible by inheritance.
135
  planet = find_planet (dyn_manager, planet_name, "planet_name");
190✔
136
  // Method fails if planet pointer is NULL.  but just to be sure (in case the
137
  // DynBodyInit method changes) check it again here.  Note, however, it is
138
  // not possible to test this line of code.
139
  if (planet == nullptr) {
190✔
140
    CMLMessage::fail(
×
141
      __FILE__, __LINE__, "Invalid configuration.\n",
142
      "Action named '", action_identifier, "' failed:\n" "Could not find planet named '", planet_name, "'");
×
143
    return;
×
144
  }
145

146
  // The subject for any state initialization action must be a DynBody, not a
147
  // MassBody. This pointer will also be null if a subject was never set.
148
  auto* subject = get_subject_dyn_body();
190✔
149
  if (subject == nullptr) {
190✔
150
    if (mass_subject != nullptr) {
×
151
      CMLMessage::fail(
×
152
        __FILE__, __LINE__, "Invalid configuration.\n",
153
        "The subject provided must be a DynBody, not a MassBody.");
154
    } else {
155
      CMLMessage::fail(
×
156
        __FILE__, __LINE__, "Invalid configuration.\n",
157
        "A subject was never provided.");
158
    }
159
    return;
×
160
  }
161

162
  // Here we are copying the reference frame names to strings within this
163
  //       StateInitialize object, as opposed to passing their pointers directly
164
  //       into trans_init and rot_init. This is to avoid a possible scenario in
165
  //       which planet is changed or the object it points to is deleted, which
166
  //       would deallocate the location of the names and potentially break
167
  //       trans_init and rot_init if the names were not copied.
168
  reference_ref_frame_name_inertial = planet->inertial.get_name();
190✔
169
  reference_ref_frame_name_pfix = planet->pfix.get_name();
190✔
170

171
  // reference_ref_frame_name is inherited from parent class (DynBodyInit).
172
  // It must be set to prevent an error in a function in the parent class
173
  // (DynBodyInit::initialize) even though it isn't actually used directly --
174
  // the specific instances (trans_init, rot_init, etc.) are used instead, but
175
  // these may be populated from this value.
176
  reference_ref_frame_name = reference_ref_frame_name_inertial;
190✔
177

178
  // set planet pointer for target relative state init options:
179
  //       TR_GeodAlt_RngAng_RotAng, TR_GeodAlt_RngAng_CrossAng*,
180
  //       TR_InertialSpeedGammaLatang
181
  TR_param.set_planet(planet);
190✔
182

183
  // set planet pointer for correlated dispersion option: PV_COVAR_TR_PARAM
184
  correlation.TR_param.set_planet(planet);
190✔
185

186
  DynBodyInit::initialize( dyn_manager );
190✔
187

188
  select_position_initializer();
190✔
189
  select_velocity_initializer();
187✔
190
  select_attitude_initializer();
185✔
191
  select_att_rate_initializer();
181✔
192
  verify_compatibility();
179✔
193

194
  if (use_orbital_init) {
172✔
195
    orb_elem_init.action_name = action_name;
9✔
196
    orb_elem_init.set_subject_body(*subject);
9✔
197
    orb_elem_init.body_frame_id = body_frame_id;
9✔
198
    orb_elem_init.reference_ref_frame_name = reference_ref_frame_name;
9✔
199
    orb_elem_init.planet_name = planet_name;
9✔
200
    orb_elem_init.orbit_frame_name = reference_ref_frame_name;
9✔
201
    orb_elem_init.initialize( dyn_manager);
9✔
202
    // If the state is to have correlations/dispersions added, then use the
203
    // orb-elem-generated state to populate trans_init, so configure
204
    // trans_init for post-dispersion application.
205
    // NOTE
206
    //  - Do not set use_trans_init=true at this point; we will want to
207
    //    populate trans_init (and THEN set use_trans_init=true) AFTER
208
    //    orb_elem_init has populated the state so that the orb-elem-defined
209
    //    nominal state can then be dispersed and then reapplied by trans-init.
210
    //  - set the ref-frame name for trans-init regardless because it saves an
211
    //    if-check later in the model
212
    trans_init.reference_ref_frame_name = reference_ref_frame_name;
9✔
213
    if ( correlation.dispersion_distribution !=
9✔
214
                             CorrelatedStateDispersion::NoDispersion ||
8✔
215
        monte_carlo_dispersion.disperse_pv){
8✔
216
      trans_init.action_name = action_name;
5✔
217
      trans_init.body_frame_id = body_frame_id;
5✔
218
      trans_init.set_subject_body(*subject);
5✔
219
      trans_init.initialize( dyn_manager);
5✔
220
    }
221
  }
222
  if (use_trans_init) {
172✔
223
    if (!use_trans_init_passthrough) {
162✔
224
      trans_init.action_name = action_name;
158✔
225
      trans_init.reference_ref_frame_name = use_pfix_frame_trans ?
158✔
226
                    reference_ref_frame_name_pfix : reference_ref_frame_name;
158✔
227
      trans_init.body_frame_id = body_frame_id;
158✔
228
    }
229
    trans_init.set_subject_body(*subject);
162✔
230
    trans_init.initialize( dyn_manager);
162✔
231
  }
232
  if (use_rot_init) {
172✔
233
    if (!use_rot_init_passthrough) {
171✔
234
      rot_init.action_name = action_name;
168✔
235
      rot_init.reference_ref_frame_name = reference_ref_frame_name;
168✔
236
      rot_init.body_frame_id = body_frame_id;
168✔
237
    }
238
    rot_init.set_subject_body(*subject);
171✔
239
    rot_init.initialize( dyn_manager);
171✔
240
  }
241
  if (use_ned_rot_init) {
172✔
242
    ned_rot_init.set_subject_body(*subject);
3✔
243
    ned_rot_init.action_name = action_name;
3✔
244
    ned_rot_init.reference_ref_frame_name = reference_ref_frame_name;
3✔
245
    ned_rot_init.body_frame_id = body_frame_id;
3✔
246
    ned_rot_init.planet_name = planet_name;
3✔
247
    ned_rot_init.initialize( dyn_manager);
3✔
248
  }
249
  initialized = true;
172✔
250
}
251

252
/*****************************************************************************
253
select_position_initializer
254
Purpose:(directs the flow through the initialization options)
255
*****************************************************************************/
256
void
257
StateInitialize::select_position_initializer()
190✔
258
{
259
  switch(position_input_data_type) {
190✔
260
   case TransInit:
5✔
261
    use_trans_init_passthrough = true;
5✔
262
    force_match_trans = (velocity_input_data_type != Off);
5✔
263
    break;
5✔
264

265
   case Inertial:
128✔
266
   case ICOPT_R_INERTIAL:
267
    // Copy the local position into the TransInit class.
268
    jeod::Vector3::copy(position, trans_init.position);
128✔
269
    break;
128✔
270

271
   case Pfix:
3✔
272
    use_pfix_frame_trans = true;
3✔
273
    force_match_trans = (velocity_input_data_type != Off);
3✔
274
    jeod::Vector3::copy(position, trans_init.position);
3✔
275
    break;
3✔
276

277
   case NED_Geodetic:
2✔
278
   case GEOD_LAT_LON_ALT:
279
    pfix_ref_point_state.altlatlong_type = jeod::NorthEastDown::elliptical;
2✔
280
    generate_pfix_position();
2✔
281
    break;
2✔
282

283
   case NED_Geocentric:
28✔
284
    pfix_ref_point_state.altlatlong_type = jeod::NorthEastDown::spherical;
28✔
285
    generate_pfix_position();
28✔
286
    break;
28✔
287

288
   case OrbitalElements:
9✔
289
    use_orbital_init = true;
9✔
290
    use_trans_init = false;
9✔
291
    force_match_trans = (velocity_input_data_type != Off);
9✔
292
    remove_from_trans_init( jeod::DynBodyInitTransState::Position);
9✔
293
    break;
9✔
294

295
   case TR_GeodAlt_RngAng_RotAng:
5✔
296
    populate_trans_init_pos_from_pfix = true;
5✔
297
    TR_param.initialize( ref_point_altitude,
15✔
298
                         ref_point_latitude,
5✔
299
                         ref_point_longitude);
5✔
300
    // generate pfix_position 3-array from TR-param configuration and
301
    // specified altitude, range-angle, rotation-angle.
302
    TR_param.compute_position_from_params( TR_geodetic_altitude,
12✔
303
                                           TR_theta_Rng,
4✔
304
                                           TR_theta_Rot,
4✔
305
            TargetRelative_StateParameter::INPUT_THETA_ROT,
306
                                           pfix_position);
4✔
307
    break;
4✔
308

309
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_LT_90:
3✔
310
    populate_trans_init_pos_from_pfix = true;
3✔
311
    TR_param.initialize( ref_point_altitude,
9✔
312
                         ref_point_latitude,
3✔
313
                         ref_point_longitude);
3✔
314
    TR_param.compute_position_from_params( TR_geodetic_altitude,
9✔
315
                                           TR_theta_Rng,
3✔
316
                                           TR_phi_Cross,
3✔
317
            TargetRelative_StateParameter::INPUT_PHI_ABS_THETA_ROT_LT_90,
318
                                           pfix_position);
3✔
319
    break;
3✔
320

321
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_GT_90:
1✔
322
    populate_trans_init_pos_from_pfix = true;
1✔
323
    TR_param.initialize( ref_point_altitude,
3✔
324
                         ref_point_latitude,
1✔
325
                         ref_point_longitude);
1✔
326
    TR_param.compute_position_from_params( TR_geodetic_altitude,
3✔
327
                                           TR_theta_Rng,
1✔
328
                                           TR_phi_Cross,
1✔
329
            TargetRelative_StateParameter::INPUT_PHI_ABS_THETA_ROT_GT_90,
330
                                           pfix_position);
1✔
331
    break;
1✔
332

333
   case Off:
4✔
334
    remove_from_trans_init( jeod::DynBodyInitTransState::Position);
4✔
335
    break;
4✔
336

337
   case Unspecified:
1✔
338
    CMLMessage::fail (
4✔
339
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
340
       action_identifier, " failed:\n"
1✔
341
      "Position init option not specified.  Use 'Off' to turn off");
342
    break;
×
343

344
   case ICOPT_INERT_VEL_GAM_AZ:
×
345
   case ICOPT_REL_VEL_GAM_AZ:
346
   case EulerPfixVelvec_YPR:
347
   case PfixUpCompAzimuth:
348
   case ICOPT_EUL_YPR_BR:
349
   case ICOPT_EUL_PYR_PL:
350
   case ICOPT_EUL_RYP_FS:
351
   case ICOPT_INERT_BODY_ROTMAT:
352
   case ICOPT_EUL_YPR_INERT_BODY:
353
    CMLMessage::warn(
×
354
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
355
      action_identifier, " error:\n"
×
356
      "Deprecated init option specified. This will be removed in the future.");
357
    [[fallthrough]];
358

359
   case ICOPT_V_INERTIAL:
1✔
360
   case InertialSpeedGammaAzimuth:
361
   case PfixSpeedGammaAzimuth:
362
   case EulerInertialVelvec_YPR:
363
   case SunPointing_YPR:
364
   case SunPointingEcliptic_PYR:
365
   case PfixUpCompAzimuth_YPR:
366
   case EulerNED_YPR:
367
   case EulerBoostRef_YPR:
368
   case EulerPlumbline_PYR:
369
   case EulerFreestream_RYP:
370
   case MatrixInertialBody:
371
   case EulerInertial_YPR:
372
   case BodyInertialRate:
373
   case BodyPfixRate:
374
   case Random:
375
   case RotInit:
376
   case RotInit_NED:
377
   case TR_InertialSpeedGammaLatang:
378
   default:
379
    CMLMessage::fail (
4✔
380
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
381
       action_identifier, " failed:\n"
1✔
382
      "Illegal position init option specified");
383
  }
384
}
187✔
385

386

387

388
/*****************************************************************************
389
select_velocity_initializer
390
Purpose:(directs the flow through the initialization options)
391
*****************************************************************************/
392
void
393
StateInitialize::select_velocity_initializer()
187✔
394
{
395
  double vel_XY = 0.0;
187✔
396

397
  switch (velocity_input_data_type) {
187✔
398
   case TransInit:
4✔
399
    use_trans_init_passthrough = true;
4✔
400
    force_match_trans = force_match_trans || (position_input_data_type != Off);
4✔
401
    break;
4✔
402

403
   case Inertial:
129✔
404
   case ICOPT_V_INERTIAL:
405
    // Copy the local velocity into the TransInit class.
406
    jeod::Vector3::copy(velocity, trans_init.velocity);
129✔
407
    // If TransInit is not being used for velocity, change the state_items
408
    // from Both (default) to position-only.
409
    break;
129✔
410

411
   case Pfix:
1✔
412
    use_pfix_frame_trans = true;
1✔
413
    force_match_trans = force_match_trans || (position_input_data_type != Off);
1✔
414
    jeod::Vector3::copy(velocity, trans_init.velocity);
1✔
415
    break;
1✔
416

417
   case NED_Geodetic:
1✔
418
    pfix_ref_point_state.altlatlong_type = jeod::NorthEastDown::elliptical;
1✔
419
    generate_pfix_velocity();
1✔
420
    break;
1✔
421

422
   case NED_Geocentric:
28✔
423
    pfix_ref_point_state.altlatlong_type = jeod::NorthEastDown::spherical;
28✔
424
    generate_pfix_velocity();
28✔
425
    break;
28✔
426

427
   case  InertialSpeedGammaAzimuth :
1✔
428
   case  ICOPT_INERT_VEL_GAM_AZ :
429
    velocity_is_relative_to_inertial = true;
1✔
430
    // fall through, or go direct with
431
    // default velocity_is_relative_to_inertial = false
432
    [[fallthrough]];
433
   case  PfixSpeedGammaAzimuth :
2✔
434
   case  ICOPT_REL_VEL_GAM_AZ :
435
    vel_XY = speed * std::cos(flight_path_angle);
2✔
436
    velocity[0] = vel_XY * std::cos(azimuth);
2✔
437
    velocity[1] = vel_XY * std::sin(azimuth);
2✔
438
    velocity[2] = -speed * std::sin(flight_path_angle);
2✔
439
    use_veh_position_as_reference = true;
2✔
440
    pfix_ref_point_state.altlatlong_type = jeod::NorthEastDown::spherical;
2✔
441
    break;
2✔
442

443
   case OrbitalElements:
8✔
444
    use_orbital_init = true;
8✔
445
    use_trans_init = false;
8✔
446
    force_match_trans = force_match_trans || (position_input_data_type != Off);
8✔
447
    remove_from_trans_init( jeod::DynBodyInitTransState::Velocity);
8✔
448
    break;
8✔
449

450
   case TR_InertialSpeedGammaLatang:
5✔
451
    // Note: Set "use_veh_position_as_reference" to force the call to
452
    //       generate_pfix_velocity_from_veh_pos() when the trans-state initial
453
    //       conditions are getting computed.  This will generate a velocity
454
    //       expressed in the pfix frame (via the TR-state-params methods).
455
    //       Also set "velocity_is_relative_to_inertial" to indicate that the
456
    //       velocity so generated is wrt inertial (while expressed in pfix).
457
    use_veh_position_as_reference     = true;
5✔
458
    velocity_is_relative_to_inertial  = true;
5✔
459
    TR_param.initialize( ref_point_altitude,
15✔
460
                         ref_point_latitude,
5✔
461
                         ref_point_longitude);
5✔
462
    break;
5✔
463

464
   case Off:
7✔
465
    remove_from_trans_init( jeod::DynBodyInitTransState::Velocity);
7✔
466
    break;
7✔
467

468
   case Unspecified:
1✔
469
    CMLMessage::fail (
4✔
470
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
471
       action_identifier, " failed:\n"
1✔
472
      "Velocity init option not specified.  Use 'Off' to turn off");
473
    break;
×
474

475
   case GEOD_LAT_LON_ALT:
×
476
   case EulerPfixVelvec_YPR:
477
   case PfixUpCompAzimuth:
478
   case ICOPT_EUL_YPR_BR:
479
   case ICOPT_EUL_PYR_PL:
480
   case ICOPT_EUL_RYP_FS:
481
   case ICOPT_INERT_BODY_ROTMAT:
482
   case ICOPT_EUL_YPR_INERT_BODY:
483
    CMLMessage::warn(
×
484
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
485
      action_identifier, " error:\n"
×
486
      "Deprecated init option specified. This will be removed in the future.");
487
    [[fallthrough]];
488

489
   case ICOPT_R_INERTIAL:
1✔
490
   case EulerInertialVelvec_YPR:
491
   case SunPointing_YPR:
492
   case SunPointingEcliptic_PYR:
493
   case PfixUpCompAzimuth_YPR:
494
   case EulerNED_YPR:
495
   case EulerBoostRef_YPR:
496
   case EulerPlumbline_PYR:
497
   case EulerFreestream_RYP:
498
   case MatrixInertialBody:
499
   case EulerInertial_YPR:
500
   case BodyInertialRate:
501
   case BodyPfixRate:
502
   case Random:
503
   case RotInit:
504
   case RotInit_NED:
505
   case TR_GeodAlt_RngAng_RotAng:
506
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_LT_90:
507
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_GT_90:
508
   default:
509
    CMLMessage::fail (
4✔
510
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
511
       action_identifier, " failed:\n"
1✔
512
      "Illegal velocity init option specified");
513
  }
514
}
185✔
515

516

517
/*****************************************************************************
518
select_attitude_initializer
519
Purpose:(directs the flow through the initialization options)
520
*****************************************************************************/
521
void
522
StateInitialize::select_attitude_initializer()
185✔
523
{
524
  // Pass through the switch twice; there is a great deal of duplicated code
525
  // otherwise.
526
  // First pass for E_reference_body
527
  switch (attitude_input_data_type) {
185✔
528
   case EulerInertialVelvec_YPR:
139✔
529
   case SunPointing_YPR:
530
   case PfixUpCompAzimuth:
531
   case PfixUpCompAzimuth_YPR:
532
   case EulerBoostRef_YPR:
533
   case ICOPT_EUL_YPR_BR: // Boost reference
534
   case EulerInertial_YPR:
535
   case ICOPT_EUL_YPR_INERT_BODY:
536
   case EulerNED_YPR:
537
    // For these cases, need to set the inertial-reference orientation after
538
    // the trans_init has been applied, so these are not set here.
539
    // Set the Euler angles from reference to body frame.
540
    E_reference_body[0] = yaw;
139✔
541
    E_reference_body[1] = pitch;
139✔
542
    E_reference_body[2] = roll;
139✔
543
    ref_body_sequence = jeod::Orientation::Yaw_Pitch_Roll;
139✔
544
    break;
139✔
545
   case SunPointingEcliptic_PYR:
3✔
546
   case EulerPlumbline_PYR:
547
   case ICOPT_EUL_PYR_PL: // plumbline
548
    E_reference_body[0] = pitch;
3✔
549
    E_reference_body[1] = yaw;
3✔
550
    E_reference_body[2] = roll;
3✔
551
    ref_body_sequence = jeod::Orientation::Pitch_Yaw_Roll;
3✔
552
    break;
3✔
553
   case EulerFreestream_RYP:
4✔
554
   case ICOPT_EUL_RYP_FS:
555
    // Set the Euler angles from reference to body frame.
556
    E_reference_body[0] = angle_of_bank;
4✔
557
    E_reference_body[1] = -angle_of_sideslip;
4✔
558
    E_reference_body[2] = angle_of_attack;
4✔
559
    ref_body_sequence = jeod::Orientation::Roll_Yaw_Pitch;
4✔
560
    break;
4✔
561
   case Unspecified:
39✔
562
   case Inertial:
563
   case Pfix:
564
   case ICOPT_R_INERTIAL:
565
   case ICOPT_V_INERTIAL:
566
   case NED_Geodetic:
567
   case GEOD_LAT_LON_ALT:
568
   case NED_Geocentric:
569
   case InertialSpeedGammaAzimuth:
570
   case ICOPT_INERT_VEL_GAM_AZ:
571
   case PfixSpeedGammaAzimuth:
572
   case ICOPT_REL_VEL_GAM_AZ:
573
   case OrbitalElements:
574
   case EulerPfixVelvec_YPR:
575
   case MatrixInertialBody:
576
   case ICOPT_INERT_BODY_ROTMAT:
577
   case BodyInertialRate:
578
   case BodyPfixRate:
579
   case Random:
580
   case Off:
581
   case TransInit:
582
   case RotInit:
583
   case RotInit_NED:
584
   case TR_GeodAlt_RngAng_RotAng:
585
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_LT_90:
586
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_GT_90:
587
   case TR_InertialSpeedGammaLatang:
588
   default:
589
    break; // No action, this covers options that do not need E_reference_body.
39✔
590
           // Note - "Unspecified" or illegal values will fail at the next
591
           //        switch.
592
  }
593
  // Check for an override of the default sequence.
594
  if (ref_body_sequence_override != jeod::Orientation::NoSequence) {
185✔
595
    CMLMessage::inform(
1✔
596
      __FILE__,__LINE__,"Modified Euler Sequence\n",
597
      "Euler sequence for orientation type ", attitude_input_data_type, " is being changed from the "
1✔
598
      "default ", ref_body_sequence, " to the manual override ", ref_body_sequence_override, ".\n");
1✔
599
    ref_body_sequence = ref_body_sequence_override;
1✔
600
  }
601

602
  // Now specific cases:
603
  switch (attitude_input_data_type) {
185✔
604
   case RotInit:
3✔
605
    use_rot_init_passthrough = true;
3✔
606
    // force a match with the same attitude rate initializer if
607
    // the attitude rate initializer is not Off.  I.e. cannot use this option
608
    // if the attitude rate initializer uses any other legitimate option.
609
    // This may seem like a radical requirement, but the other methods
610
    // configure the rot_init object for their own purposes, overriding the
611
    // settings that may be given to rot_init by the user.
612
    // Modification:  RotInit_NED also turns rot_init off, so is an acceptable
613
    //                bypass alternative.
614
    force_match_rot = (att_rate_input_data_type != Off &&
5✔
615
                       att_rate_input_data_type != RotInit_NED);
2✔
616
    break;
3✔
617

618
   case EulerInertialVelvec_YPR:
1✔
619
    populate_rot_init_transform_source = RITS_VelPos;
1✔
620
    z_axis_points_up = true;
1✔
621
    break;
1✔
622

623
   case SunPointing_YPR:
4✔
624
   case SunPointingEcliptic_PYR:
625
    // Need to use the trans-init position to generate the sun-earth
626
    // position vector.  If that is not specified in the correct frame
627
    // (possible if using use_trans_init_passthrough or pfix initialization),
628
    // the algebra will not work out.
629
    // NOTE trans_init.reference_ref_frame_name requires manual setting if
630
    //      using a passthrough option and may not have been set at all if
631
    //      using an orbital-elements specification.
632
    if( use_trans_init_passthrough &&
5✔
633
           (!reference_ref_frame_name_inertial.compare(
2✔
634
                                 trans_init.reference_ref_frame_name))) {
1✔
635
      CMLMessage::fail (
4✔
636
        __FILE__, __LINE__, "StateInitialization::invalid_configuration\n",
637
        "Rot init is being configured using the sun-vehicle vector.\n"
638
        "That requires the vehicle position wrt the initializing planet.\n"
639
        "This must be expressed in planet-relative inertial.\n"
640
        "Expecting ", reference_ref_frame_name_inertial, " but the specified frame name is ", trans_init.reference_ref_frame_name, ".\n");
1✔
641
    }
642
    if( use_pfix_frame_trans) { // which defaults to false
3✔
643
      CMLMessage::fail (
4✔
644
        __FILE__, __LINE__, "StateInitialization::invalid_configuration\n",
645
        "Rot init is being configured using the sun-vehicle vector.\n"
646
        "That requires the vehicle position wrt the initializing planet.\n"
647
        "This must be expressed in planet-relative inertial but the\n"
648
        "trans-init is specified in pfix.\n");
649
    }
650
    // Now split on which option:
651
    if (attitude_input_data_type == SunPointing_YPR) {
2✔
652
      populate_rot_init_transform_source = RITS_SolarPosPos;
1✔
653
      z_axis_points_up = true;
1✔
654
    } else {
655
      populate_rot_init_transform_source = RITS_SolarPosEclipticPole;
1✔
656
    }
657
    break;
2✔
658

659
   case PfixUpCompAzimuth:
1✔
660
   case PfixUpCompAzimuth_YPR:
661
    // Set the Euler angles from planet-fix to reference.
662
    // Reference in this case is (Up - East - North) and uses the same
663
    // reference point as the position and velocity specifications.
664
    E_pfix_reference[0] = ref_point_longitude;
1✔
665
    E_pfix_reference[1] = -ref_point_latitude;
1✔
666
    E_pfix_reference[2] = azimuth;
1✔
667
    jeod::Orientation::compute_matrix_from_euler_angles( jeod::Orientation::Yaw_Pitch_Roll,
1✔
668
                                                   E_pfix_reference,
1✔
669
                                                   T_pfix_reference);
1✔
670
    // note - this technique for attitude can be used with other
671
    //        attitude-rates, but this technique for attitude rates requires
672
    //        this technique for attitude.
673
    populate_rot_init_transform_source = RITS_PfixRef;
1✔
674
    break;
1✔
675

676
   case EulerNED_YPR:
1✔
677
    // Set the Euler angles from planet-fix to reference.
678
    // Reference in this case is (North - East - Down) and uses the same
679
    // reference point as the position and velocity specifications.
680
    E_pfix_reference[0] = ref_point_longitude;
1✔
681
    E_pfix_reference[1] = -(M_PI_2 + ref_point_latitude);
1✔
682
    E_pfix_reference[2] = 0.0;
1✔
683
    jeod::Orientation::compute_matrix_from_euler_angles( jeod::Orientation::Yaw_Pitch_Roll,
1✔
684
                                                   E_pfix_reference,
1✔
685
                                                   T_pfix_reference);
1✔
686
    // note - this technique for attitude can be used with other
687
    //        attitude-rates, but this technique for attitude rates requires
688
    //        this technique for attitude.
689
    populate_rot_init_transform_source = RITS_PfixRef;
1✔
690
    break;
1✔
691

692

693
   case EulerBoostRef_YPR:
1✔
694
   case ICOPT_EUL_YPR_BR: // Boost reference
695
    // Set the Euler angles from planet-fix to reference.
696
    E_pfix_reference[0] = rot_ref_longitude;
1✔
697
    E_pfix_reference[1] = -(M_PI_2 + rot_ref_latitude);
1✔
698
    E_pfix_reference[2] = 0.0;
1✔
699
    jeod::Orientation::compute_matrix_from_euler_angles( jeod::Orientation::Yaw_Pitch_Roll,
1✔
700
                                                   E_pfix_reference,
1✔
701
                                                   T_pfix_reference);
1✔
702
    populate_rot_init_transform_source = RITS_PfixRef;
1✔
703
    break;
1✔
704

705
   case EulerPlumbline_PYR:
2✔
706
   case ICOPT_EUL_PYR_PL: // plumbline
707
    // Set the Euler angles from planet-fix to reference.
708
    E_pfix_reference[0] = rot_ref_longitude;
2✔
709
    E_pfix_reference[1] = -rot_ref_latitude;
2✔
710
    E_pfix_reference[2] = -rot_ref_azimuth;
2✔
711
    jeod::Orientation::compute_matrix_from_euler_angles( jeod::Orientation::Yaw_Pitch_Roll,
2✔
712
                                                   E_pfix_reference,
2✔
713
                                                   T_pfix_reference);
2✔
714
    populate_rot_init_transform_source = RITS_PfixRef;
2✔
715
    break;
2✔
716

717
   case EulerFreestream_RYP:
4✔
718
   case ICOPT_EUL_RYP_FS:
719
    // The inertial wind velocity, necessary for generating the free-stream
720
    // velocity, is not known until after the vehicle position has been
721
    // initialized (among other steps).
722
    // This option requires an additional step; the  method
723
    //       overwrite_attitude_from_free_stream( double rel_wind_inrtl[3])
724
    // must be called AFTER the wind velocity is available.
725
    // For now, the attitude will be initialized with the assumption that the
726
    // wind velocity (relative to ground) is zero.
727
    requires_free_stream_velocity = true;
4✔
728
    populate_rot_init_transform_source = RITS_VelPos;
4✔
729
    break;
4✔
730

731
   case MatrixInertialBody:
28✔
732
   case ICOPT_INERT_BODY_ROTMAT:
733
    jeod::Matrix3x3::copy(T_inrtl_body,
28✔
734
                    rot_init.orientation.trans);
28✔
735
    rot_init.orientation.data_source = jeod::Orientation::InputMatrix;
28✔
736
    break;
28✔
737

738
   case EulerInertial_YPR:
132✔
739
   case ICOPT_EUL_YPR_INERT_BODY: // Populate E_reference_body as YPR
740
    populate_rot_init_transform_source = RITS_Inertial;
132✔
741
    break;
132✔
742

743
   case Random:
1✔
744
    // Generate a uniformly-distributed random attitude. This is done by
745
    // rotating so that the x-axis is uniformly randomly oriented, then rotating
746
    // about the x-axis by a uniformly-distributed random angle. See
747
    // docs/state_initialize.pdf for a more detailed explanation.
748
   {
749
    generate_random(att_random_seed);
1✔
750
    random_value *= M_PI; // Half of the random rotation angle about the x-axis
1✔
751
    double sinhalf = std::sin(random_value), coshalf = std::cos(random_value);
1✔
752
    double temp = std::sqrt(2 * (random_unit_vector[0] + 1));
1✔
753
    jeod::Quaternion random_att;
1✔
754
    // random_unit_vector is the new orientation of the x-axis
755
    if (MathUtils::is_near_equal(temp, 0.0)) { // Avoid dividing by 0
1✔
756
      random_att.scalar    = 0.0;
×
757
      random_att.vector[0] = 0.0;
×
758
      random_att.vector[1] = sinhalf;
×
759
      random_att.vector[2] = coshalf;
×
760
    }
761
    else {
762
      random_att.scalar    = temp/2 * coshalf;
1✔
763
      random_att.vector[0] = temp/2 * sinhalf;
1✔
764
      random_att.vector[1] =
1✔
765
         (random_unit_vector[1]*sinhalf - random_unit_vector[2]*coshalf) / temp;
1✔
766
      random_att.vector[2] =
1✔
767
         (random_unit_vector[1]*coshalf + random_unit_vector[2]*sinhalf) / temp;
1✔
768
    }
769
    rot_init.orientation.set_quaternion(random_att);
1✔
770
    rot_init.orientation.data_source = jeod::Orientation::InputQuaternion;
1✔
771
   }
772
    break;
1✔
773

774
   case RotInit_NED:
2✔
775
    // turn on the rot-init-ned option.  If it is to be used only for attitude,
776
    // configure as such (default is to use for both attitude and attitude
777
    // rate).  Finally, remove attitude from the regular rot-init
778
    // responsibilities.
779
    use_ned_rot_init = true;
2✔
780
    if (att_rate_input_data_type != RotInit_NED) {
2✔
781
      ned_rot_init.set_items = jeod::RefFrameItems::Att;
1✔
782
    }
783
    [[fallthrough]];
784
   case Off:
785
    remove_from_rot_init( jeod::DynBodyInitRotState::Attitude);
5✔
786
    break;
5✔
787

788
   case Unspecified:
1✔
789
    CMLMessage::fail (
4✔
790
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
791
       action_identifier, " failed:\n"
1✔
792
      "Attitude init option not specified.  Use 'Off' to turn off");
793
    break;
×
794

795
   case GEOD_LAT_LON_ALT:
×
796
   case ICOPT_INERT_VEL_GAM_AZ:
797
   case ICOPT_REL_VEL_GAM_AZ:
798
   case EulerPfixVelvec_YPR:
799
    CMLMessage::warn(
×
800
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
801
      action_identifier, " error:\n"
×
802
      "Deprecated init option specified. This will be removed in the future.");
803
    [[fallthrough]];
804

805
   case Inertial:
1✔
806
   case Pfix:
807
   case ICOPT_R_INERTIAL:
808
   case ICOPT_V_INERTIAL:
809
   case NED_Geodetic:
810
   case NED_Geocentric:
811
   case InertialSpeedGammaAzimuth:
812
   case PfixSpeedGammaAzimuth:
813
   case OrbitalElements:
814
   case BodyInertialRate:
815
   case BodyPfixRate:
816
   case TransInit:
817
   case TR_GeodAlt_RngAng_RotAng:
818
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_LT_90:
819
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_GT_90:
820
   case TR_InertialSpeedGammaLatang:
821
   default:
822
    CMLMessage::fail (
4✔
823
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
824
       action_identifier, " failed:\n"
1✔
825
      "Illegal attitude init option specified");
826
  }
827
}
181✔
828

829
/*****************************************************************************
830
select_att_rate_initializer
831
Purpose:(directs the flow through the initialization options)
832
*****************************************************************************/
833
void
834
StateInitialize::select_att_rate_initializer()
181✔
835
{
836
  switch (att_rate_input_data_type) {
181✔
837
   case RotInit:
3✔
838
    // force a match with the same attitude initializer if
839
    // the attitude initializer is anything other than Off of RotInit_NED.
840
    // i.e. cannot use this option if the attitude initializer uses any
841
    // option that may reconfigure rot_init for its own purposes.
842
    use_rot_init_passthrough = true;
3✔
843
    force_match_rot = force_match_rot ||
5✔
844
                      (attitude_input_data_type != Off &&
2✔
845
                       attitude_input_data_type != RotInit_NED);
1✔
846
    break;
3✔
847

848
   case PfixUpCompAzimuth:
3✔
849
   case PfixUpCompAzimuth_YPR:
850
   case EulerNED_YPR:
851
   case BodyPfixRate:
852
    increment_rot_rate_init_with_pfix = true;
3✔
853
    // fallthrough to populate rot_init.ang_velocity.
854
    [[fallthrough]];
855

856
   case BodyInertialRate:
171✔
857
    // These are the body rates wrt the specified frame, expressed in body.
858
    rot_init.ang_velocity[0] = roll_rate_body;
171✔
859
    rot_init.ang_velocity[1] = pitch_rate_body;
171✔
860
    rot_init.ang_velocity[2] = yaw_rate_body;
171✔
861
    break;
171✔
862

863
   case Random:
1✔
864
    generate_random(att_rate_random_seed);
1✔
865
    random_value *= max_rate_random;
1✔
866
    jeod::Vector3::scale( random_unit_vector,
1✔
867
                    random_value,
1✔
868
                    rot_init.ang_velocity);
1✔
869
    break;
1✔
870

871
   case RotInit_NED:
2✔
872
    // turn on the rot-init-ned option.  If it is to be used only for
873
    // attitude-rate, configure as such (default is to use for both attitude
874
    // and attitude-rate).  Finally, remove attitude-rate from the regular
875
    // rot-init responsibilities.
876
    use_ned_rot_init = true;
2✔
877
    if (attitude_input_data_type != RotInit_NED) {
2✔
878
      ned_rot_init.set_items = jeod::RefFrameItems::Rate;
1✔
879
    }
880
    [[fallthrough]];
881
   case Off:
882
    remove_from_rot_init( jeod::DynBodyInitRotState::Rate);
4✔
883
    break;
4✔
884

885
   case Unspecified:
1✔
886
    CMLMessage::fail (
4✔
887
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
888
       action_identifier, " failed:\n"
1✔
889
      "Attitude-rate init option not specified.  Use 'Off' to turn off");
890
    break;
×
891

892
   case GEOD_LAT_LON_ALT:
×
893
   case ICOPT_INERT_VEL_GAM_AZ:
894
   case ICOPT_REL_VEL_GAM_AZ:
895
   case EulerPfixVelvec_YPR:
896
   case ICOPT_EUL_YPR_BR:
897
   case ICOPT_EUL_PYR_PL:
898
   case ICOPT_EUL_RYP_FS:
899
   case ICOPT_INERT_BODY_ROTMAT:
900
   case ICOPT_EUL_YPR_INERT_BODY:
901
    CMLMessage::warn(
×
902
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
903
      action_identifier, " error:\n"
×
904
      "Deprecated init option specified. This will be removed in the future.");
905
    [[fallthrough]];
906

907
   case Inertial:
1✔
908
   case Pfix:
909
   case ICOPT_R_INERTIAL:
910
   case ICOPT_V_INERTIAL:
911
   case NED_Geodetic:
912
   case NED_Geocentric:
913
   case InertialSpeedGammaAzimuth:
914
   case PfixSpeedGammaAzimuth:
915
   case OrbitalElements:
916
   case EulerInertialVelvec_YPR:
917
   case SunPointing_YPR:
918
   case SunPointingEcliptic_PYR:
919
   case EulerBoostRef_YPR:
920
   case EulerPlumbline_PYR:
921
   case EulerFreestream_RYP:
922
   case MatrixInertialBody:
923
   case EulerInertial_YPR:
924
   case TransInit:
925
   case TR_GeodAlt_RngAng_RotAng:
926
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_LT_90:
927
   case TR_GeodAlt_RngAng_CrossAng_AbsRotAng_GT_90:
928
   case TR_InertialSpeedGammaLatang:
929
   default:
930
    CMLMessage::fail (
4✔
931
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
932
       action_identifier, " failed:\n"
1✔
933
      "Illegal attitude-rate init option specified");
934
  }
935
}
179✔
936

937

938
/*****************************************************************************
939
apply
940
Purpose:(Applies the state_initialize action)
941
*****************************************************************************/
942
void
943
StateInitialize::apply(
158✔
944
   jeod::DynManager & dyn_manager)
945
{
946
  if (!initialized) {
158✔
947
    CMLMessage::error(
×
948
      __FILE__,__LINE__,"Premature application of Body Action.\n"
949
      "This body-action ('", action_identifier, "') must be initialized before it can be applied.\n"
×
950
      "Application failed.\n");
951
    return;
×
952
  }
953

954
  if (use_orbital_init) {
158✔
955
    generate_orbital_init_values( dyn_manager);
8✔
956
    //includes call to DynBodyInitOrbit::apply
957
  }
958
  if (use_trans_init) { // Not an elseif; orbital_init may have turned this on
158✔
959
    generate_trans_init_values();
154✔
960
  }
961
  // apply MonteCarlo dispersions to the nominal state.  Note - the
962
  // translational state may be a necessary component in setting the
963
  // state of the frames used to define the rotational state.  So apply these
964
  // dispersions beforegenerating the rotational state.
965
  if (monte_carlo_dispersion.disperse_pv) {
158✔
966
    if ( correlation.dispersion_distribution !=
5✔
967
                              CorrelatedStateDispersion::NoDispersion) {
968
      CMLMessage::warn(
1✔
969
        __FILE__,__LINE__,"Simultaneous application of dispersions\n",
970
        "The configuration calls for application of 2 independent dispersions"
971
        "\napplied to the nominal state.\n"
972
        "The first to be applied will be a MonteCarlo direct-dispersion of\n"
973
        "state on independent axes. This could be random or file-driven but\n"
974
        "effectively treats each of the state components independently.\n"
975
        "The second to be applied uses a covariance matrix.  This dispersion\n"
976
        "will be applied onto the state resulting from the first dispersion.\n"
977
        "Check configuration to ensure that this is the intended setup.\n");
978
    }
979
    // Note -- apply direct dispersion first to support analysis along a short
980
    //         arc around the nominal state.  This can move the vehicle to a
981
    //         point on the arc (defined in a file), then apply a
982
    //         correlated-dispersion to that state.
983
    monte_carlo_dispersion.disperse_trans_state();
5✔
984
  }
985

986
   if (use_rot_init) {
157✔
987
    generate_rot_init_values( dyn_manager);
156✔
988
  }
989

990
  // apply correlations
991
  if ( correlation.dispersion_distribution !=
157✔
992
                              CorrelatedStateDispersion::NoDispersion) {
993
    if ( correlation.corr_base_frame_name.empty() ||
2✔
994
         correlation.corr_base_frame_name == trans_init.reference_ref_frame_name) {
×
995
      correlation.disperse_state( trans_init.position,
4✔
996
                                  trans_init.velocity,
2✔
997
                                  rot_init.orientation.trans);
2✔
998
    }
999
    else {
1000
      // find ref_frame is a DynBodyInit method, accessible by inheritance
1001
      jeod::RefFrame * corr_base = find_ref_frame( dyn_manager,
×
1002
                                             correlation.corr_base_frame_name,
×
1003
                                             "ref-frame name");
1004
                         
1005
      // find ref_frame is a DynBodyInit method, accessible by inheritance
1006
      jeod::RefFrame * trans_ref = find_ref_frame( dyn_manager,
×
1007
                                             trans_init.reference_ref_frame_name,
×
1008
                                             "ref-frame name");
1009

1010
      // Compute relative rotation from corr_base to trans_base
1011
      jeod::RefFrame * rot_ref = find_ref_frame( dyn_manager,
×
1012
                                           rot_init.reference_ref_frame_name,
×
1013
                                           "ref-frame name");
1014

1015
      // NULL checked in find_ref_frame
1016
      dyn_manager.subscribe_to_frame(*corr_base);
×
1017
      dyn_manager.subscribe_to_frame(*trans_ref);
×
1018
      dyn_manager.subscribe_to_frame(*rot_ref);
×
1019
      dyn_manager.update_ephemerides();
×
1020
      dyn_manager.unsubscribe_to_frame(*corr_base);
×
1021
      dyn_manager.unsubscribe_to_frame(*trans_ref);
×
1022
      dyn_manager.unsubscribe_to_frame(*rot_ref);
×
1023

1024
      // Compute relative translation from corr_base to trans_base
1025
      jeod::RefFrameState trans_init_wrt_corr_base;
×
1026
      trans_ref->compute_relative_state( *corr_base,
×
1027
                                          trans_init_wrt_corr_base);
×
1028

1029
      if (trans_init.reference_ref_frame_name == rot_init.reference_ref_frame_name) {
×
1030
        correlation.disperse_state( trans_init_wrt_corr_base,
×
1031
                                    trans_init.position,
×
1032
                                    trans_init.velocity,
×
1033
                                    rot_init.orientation.trans);
×
1034
      }
1035
      else {
1036
        jeod::RefFrameState rot_init_wrt_corr_base;
×
1037
        rot_ref->compute_relative_state( *corr_base,
×
1038
                                          rot_init_wrt_corr_base);
×
1039
                         
1040
        correlation.disperse_state( trans_init_wrt_corr_base,
×
1041
                                    rot_init_wrt_corr_base.rot.T_parent_this,
1042
                                    trans_init.position,
×
1043
                                    trans_init.velocity,
×
1044
                                    rot_init.orientation.trans);
×
1045
      }
1046
    }
1047
  }
1048

1049

1050
  // Make the actual applications at this point.
1051
  // Separating off to make this injection point available to derivations
1052
  // of this class.
1053
  apply_internal( dyn_manager);
157✔
1054
}
1055

1056

1057
/*****************************************************************************
1058
apply_internal
1059
Purpose:(applies the appropriate body-actions)
1060
*****************************************************************************/
1061
void
1062
StateInitialize::apply_internal(
171✔
1063
   jeod::DynManager & dyn_manager)
1064
{
1065
  // apply body actions:
1066
  if (use_trans_init) {
171✔
1067
    trans_init.apply( dyn_manager);
166✔
1068
  }
1069
  if (use_rot_init) {
171✔
1070
    rot_init.apply( dyn_manager);
170✔
1071
  }
1072
  if (use_ned_rot_init) {
171✔
1073
    ned_rot_init.apply( dyn_manager);
3✔
1074
  }
1075

1076
  DynBodyInit::apply( dyn_manager );
171✔
1077
}
171✔
1078

1079

1080

1081

1082
/*****************************************************************************
1083
generate_orbital_init_values
1084
Purpose:(Generates the data for DynBodyInitOrbit)
1085
*****************************************************************************/
1086
void
1087
StateInitialize::generate_orbital_init_values(
9✔
1088
       jeod::DynManager & dyn_manager)
1089
{
1090
  // The validity of the subject dyn_body pointer was checked in initialize().
1091
  auto* subject = get_subject_dyn_body();
9✔
1092

1093
  // If one of the states is NOT to be initialized this way, store off the
1094
  // current value before it gets overwritten.
1095
  double temp_state[3] {};
9✔
1096
  if (position_input_data_type == Off) {
9✔
1097
    jeod::Vector3::copy(subject->composite_body.state.trans.position,
1✔
1098
                  temp_state);
1099
  }
1100
  else if (velocity_input_data_type == Off) {
8✔
1101
    jeod::Vector3::copy(subject->composite_body.state.trans.velocity,
2✔
1102
                  temp_state);
1103
  }
1104

1105
  orb_elem_init.apply( dyn_manager);
9✔
1106

1107
  // Then reinstate the state values that were just unintentionally copied
1108
  // over.
1109
  if (position_input_data_type == Off) {
9✔
1110
    jeod::Vector3::copy( temp_state,
1✔
1111
                   subject->composite_body.state.trans.position);
1✔
1112
  }
1113
  else if (velocity_input_data_type == Off) {
8✔
1114
    jeod::Vector3::copy( temp_state,
2✔
1115
                   subject->composite_body.state.trans.velocity);
2✔
1116
  }
1117

1118
  // Populate the trans_init values in case they are needed by rot_init or
1119
  // by the dispersion generator.
1120
  // Notes:
1121
  // -- In some situations, it may be necessary to have accurate
1122
  //    trans_init.position and trans_init.velocity values to generate
1123
  //    frame transformations, e.g. Lvlh-to-inertial.
1124
  // -- copy position value if trans-init is not being used or if it is only
1125
  //    being used for initializing velocity values.  In this case,  DO NOT
1126
  //    copy the velocity values coming from orbital parameter initialization
1127
  //    because that would overwrite the desired velocity values.
1128
  // -- Similarly, copy velocity values if trans-init is not being used or if
1129
  //    it is only being used for initializing position values.
1130
  // -- Copying in a position value when trans-init is only being used for
1131
  //    velocity (and vice-versa) has no effect on the state initialization.
1132
  //    Trans-init is smart enough to ignore position values when
1133
  //    state_items = jeod::DynBodyInitTransState::velocity (and vice-versa).
1134
  if (!use_trans_init ||
9✔
1135
      trans_init.state_items == jeod::DynBodyInitTransState::Velocity) {
×
1136
    jeod::Vector3::copy(subject->composite_body.state.trans.position,
9✔
1137
                  trans_init.position);
9✔
1138
  }
1139
  if (!use_trans_init ||
9✔
1140
      trans_init.state_items == jeod::DynBodyInitTransState::Position) {
×
1141
    jeod::Vector3::copy(subject->composite_body.state.trans.velocity,
9✔
1142
                  trans_init.velocity);
9✔
1143
  }
1144
  // If the state is to have correlated or direct dispersions added, then
1145
  // set trans_init back in effect.
1146
  if ( correlation.dispersion_distribution !=
9✔
1147
                           CorrelatedStateDispersion::NoDispersion ||
8✔
1148
      monte_carlo_dispersion.disperse_pv){
8✔
1149
    trans_init.state_items = jeod::DynBodyInitTransState::Both;
5✔
1150
    use_trans_init = true;
5✔
1151
  }
1152
}
9✔
1153

1154

1155
/*****************************************************************************
1156
generate_trans_init_values
1157
Purpose:(Generates the data for jeod::DynBodyInitTransState)
1158
*****************************************************************************/
1159
void
1160
StateInitialize::generate_trans_init_values()
179✔
1161
{
1162
  // Position, one optional computation
1163
  if (populate_trans_init_pos_from_pfix) {
179✔
1164
    jeod::Vector3::transform_transpose(planet->pfix.state.rot.T_parent_this,
38✔
1165
                                 pfix_position,
38✔
1166
                                 trans_init.position);
38✔
1167
  }
1168
  // Could be using the trans_init position value to initialize other parts
1169
  // of the state. If position is initialized elsewhere, need that value
1170
  // copying into trans_init.position so that the other elements can still
1171
  // access it.
1172
  else if ( trans_init.state_items == jeod::DynBodyInitTransState::Velocity) {
141✔
1173
    jeod::Vector3::copy( get_subject_dyn_body()->composite_body.state.trans.position,
2✔
1174
                   trans_init.position);
2✔
1175
  }
1176
  // Velocity, two options, potentially sequential:
1177
  if (use_veh_position_as_reference) {
179✔
1178
    generate_pfix_velocity_from_veh_pos();
7✔
1179
  }
1180
  if (populate_trans_init_vel_from_pfix) {
179✔
1181
    generate_inertial_velocity();
36✔
1182
  }
1183
}
179✔
1184

1185

1186
/*****************************************************************************
1187
generate_rot_init_values
1188
Purpose:(Generates the data for jeod::DynBodyInitRotState)
1189
*****************************************************************************/
1190
void
1191
StateInitialize::generate_rot_init_values(
170✔
1192
       jeod::DynManager & dyn_manager)
1193
{
1194
  if (requires_free_stream_velocity) {
170✔
1195
    double scratch_vec[3];
4✔
1196
    jeod::Vector3::initialize(scratch_vec);
4✔
1197
    // Don't know the wind velocity, but need something.  Generate the
1198
    // free-stream velocity (temporarily) assuming a zero wind velocity.
1199
    // This can be corrected with a call to
1200
    // overwrite_attitude_from_free_stream( wind_vel[3])
1201
    // once the wind velocity is known.
1202
    generate_free_stream_velocity(scratch_vec);
4✔
1203
  }
1204

1205
  // Now generate the orientation of the reference ref-frame.  There are
1206
  // several options for doing this; these could be enumerated and replaced
1207
  // with a switch statement.
1208
  switch (populate_rot_init_transform_source) {
170✔
1209
   case RITS_None: // already fully populated
35✔
1210
    break;
35✔
1211
   case RITS_Inertial: // reference is inertial
123✔
1212
    jeod::Matrix3x3::identity( T_inrtl_reference );
123✔
1213
    break;
123✔
1214

1215
   case RITS_VelPos: // Velocity and position:
5✔
1216
    if (requires_free_stream_velocity) {
5✔
1217
      // 1st vector (velocity) specifies x-axis,
1218
      // 2nd vector (position) provides -z-axis (general direction)
1219
      // y-axis complets.
1220
      MathUtils::generate_inrtl_to_reference ( free_stream_velocity,
4✔
1221
                                               trans_init.position,
4✔
1222
                                               T_inrtl_reference);
4✔
1223
    }
1224
    else {
1225
      MathUtils::generate_inrtl_to_reference ( trans_init.velocity,
1✔
1226
                                               trans_init.position,
1✔
1227
                                               T_inrtl_reference);
1✔
1228
    }
1229
    break;
5✔
1230
   case RITS_PfixRef: // Reference is known relative to Pfix
5✔
1231
    jeod::Matrix3x3::product( T_pfix_reference,
5✔
1232
                        planet->pfix.state.rot.T_parent_this,
5✔
1233
                        T_inrtl_reference);
5✔
1234
    break;
5✔
1235
   case RITS_SolarPosPos:
2✔
1236
   case RITS_SolarPosEclipticPole:
1237
    // Can't get vehicle-sun vector directly because vehicle not yet
1238
    // initialized.  Have to go through the planet.
1239
    // First, find the sun-inertial frame, subscribe to it, and update
1240
    // ephemerides to get its state  (and the state of planet-inertial).
1241
    // Note - update-ephemerides usually gets run AFTER body initializations.
1242

1243
    // find_ref_frame is a DynBodyInit method, accessible by inheritance
1244
    jeod::RefFrame * sun_inrtl = find_ref_frame( dyn_manager,
2✔
1245
                                           "Sun.inertial",
1246
                                           "ref-frame name");
1247
    // NULL checked in find_ref_frame
1248
    dyn_manager.subscribe_to_frame(*sun_inrtl);
2✔
1249
    dyn_manager.update_ephemerides();
2✔
1250
    // Now generate the vehicle to sun position vector
1251
    double sun_to_veh_pos[3];
2✔
1252
    sun_inrtl->compute_position_from( planet->inertial,
2✔
1253
                                      sun_to_veh_pos );
2✔
1254
    // Assume trans_init is expressed in inertial.  This was verified in
1255
    // select_attitude_initializer
1256
    jeod::Vector3::decr( trans_init.position,
2✔
1257
                   sun_to_veh_pos);
1258
    jeod::Vector3::negate(sun_to_veh_pos);
2✔
1259
    /* Use this as the x-axis to generate the reference ref-frame orientation.
1260
       NOTE - this is not the vehicle orientation; we have Euler angles to
1261
       apply to the reference-ref-frame orientation to get vehicle
1262
       orientation.
1263
     The y-axis of the reference ref-frame is determined by a reference
1264
     direction (y = x cross ref-dir, then z = x cross y is generally away from
1265
     ref-dir).  That reference direction differs
1266
     between these two options. Use the following for the reference direction
1267
     - RITS_SolarPosPos:
1268
         the position of the vehicle with respect to the reference planet
1269
     - RITS_SolarPosEclipticPole:
1270
         the the ecliptic south-pole, which is at a constant position in
1271
         J2000, determined by the J2000 obliquity, 23.43929(1111) degrees.*/
1272
    double ref_dir[3] = {0.0, 0.397777155, -0.917482062}; // south pole
2✔
1273
    if (populate_rot_init_transform_source == RITS_SolarPosPos) {
2✔
1274
      jeod::Vector3::copy (trans_init.position, ref_dir);
1✔
1275
    }
1276
    MathUtils::generate_inrtl_to_reference ( sun_to_veh_pos,
2✔
1277
                                             ref_dir,
1278
                                             T_inrtl_reference);
2✔
1279

1280
    // Unsubscribe from the sun-inertial frame.  No longer needed here.
1281
    dyn_manager.unsubscribe_to_frame(*sun_inrtl);
2✔
1282
    break;
2✔
1283
  }
1284

1285
  // Applicable to RITS_SolarPosPos and RITS_VelPos.
1286
  // Default puts the z-axis "down", with y-axis along (x-axis cross pos)
1287
  // (negative angular momentum for case where x-axis defined by velocity).
1288
  // If it is desired for z-axis to be "up" (e.g. b/c windows at -z should
1289
  // be "down"), need to negate y- and z- axes.
1290
  if (z_axis_points_up) {
170✔
1291
    for (unsigned int ii = 1; ii < 3; ii++) {
6✔
1292
      for (unsigned int jj = 0; jj < 3; jj++) {
16✔
1293
        T_inrtl_reference[ii][jj] *= -1.0;
12✔
1294
      }
1295
    }
1296
  }
1297

1298
  if (populate_rot_init_transform_source != RITS_None) {
170✔
1299
    generate_rot_init_transform();
135✔
1300
  }
1301

1302
  // Attitude rate:
1303
  if (increment_rot_rate_init_with_pfix) {
170✔
1304
    double ang_vel_planet_wrt_inrtl_in_inrtl[3];
3✔
1305
    jeod::Vector3::transform_transpose( planet->pfix.state.rot.T_parent_this,
3✔
1306
                                  planet->pfix.state.rot.ang_vel_this,
3✔
1307
                                  ang_vel_planet_wrt_inrtl_in_inrtl);
1308
    jeod::Vector3::transform_incr( rot_init.orientation.trans, // inertial to body
3✔
1309
                             ang_vel_planet_wrt_inrtl_in_inrtl,
1310
                             rot_init.ang_velocity);
3✔
1311
  }
1312
}
170✔
1313

1314

1315

1316

1317
/*****************************************************************************
1318
generate_pfix_ref_point_state
1319
Purpose:(Generates a cartesian point state based off the specified alt/lat/lon
1320
         values for the reference point.)
1321
*****************************************************************************/
1322
void
1323
StateInitialize::generate_pfix_ref_point_state()
32✔
1324
{
1325
  pfix_ref_point_state.planet = planet;
32✔
1326
  pfix_ref_point.altitude = ref_point_altitude;
32✔
1327
  pfix_ref_point.latitude = ref_point_latitude;
32✔
1328
  pfix_ref_point.longitude = ref_point_longitude;
32✔
1329

1330

1331
  switch (pfix_ref_point_state.altlatlong_type) {
32✔
1332
   case jeod::NorthEastDown::spherical:
29✔
1333
     pfix_ref_point_state.update_from_spher (pfix_ref_point);
29✔
1334
     break;
29✔
1335

1336
   case jeod::NorthEastDown::elliptical:
3✔
1337
     pfix_ref_point_state.update_from_ellip (pfix_ref_point);
3✔
1338
     break;
3✔
1339

1340
   case jeod::NorthEastDown::undefined:
×
1341
   default:
1342
     CMLMessage::fail (
×
1343
        __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
1344
         action_identifier, " failed:\n"
×
1345
        "AltLatLong type option not recognized");
1346
  }
1347
  // Now have the position of the reference point relative to
1348
  // ECEF (planet-center), expressed in:
1349
  // cartesian coordinates : pfix_ref_point_state.ned_frame.state.trans.position
1350
  // cartesian coordinates : pfix_ref_point_state.cart_coords[3]
1351
  // spherical coordinates : pfix_ref_point_state.sphere_coords.
1352
  //                                              <altitude,latitude,longitude>
1353
  // elliptical coordinates: pfix_ref_point_state.ellip_coords.
1354
  //                                              <altitude,latitude,longitude>
1355

1356

1357
  // Generate the transformation from NED to pfix so that the position and
1358
  // velocity values can be converted from being expressed in NED to
1359
  // being expressed in PFIX (e.g. ECEF)
1360

1361
  pfix_ref_point_state.build_ned_orientation();
32✔
1362
  // produces pfix_ref_point_state.ned_frame.state.rot.T_parent_this
1363

1364
  pfix_ref_point_state_generated = true;
32✔
1365
}
32✔
1366

1367

1368
/*****************************************************************************
1369
generate_pfix_position
1370
Purpose:(Generates a pfix cartesian position of the vehicle from a reference
1371
         point and NED-expressed position relative to that reference point)
1372
*****************************************************************************/
1373
void
1374
StateInitialize::generate_pfix_position()
30✔
1375
{
1376
  if (!pfix_ref_point_state_generated) {
30✔
1377
    generate_pfix_ref_point_state();
30✔
1378
  }
1379

1380
  jeod::Vector3::transform_transpose(
30✔
1381
                  pfix_ref_point_state.ned_frame.state.rot.T_parent_this,
30✔
1382
                  position,
30✔
1383
                  pfix_position);
30✔
1384
  jeod::Vector3::incr(pfix_ref_point_state.cart_coords,
30✔
1385
                pfix_position);
30✔
1386
  populate_trans_init_pos_from_pfix = true;
30✔
1387
}
30✔
1388

1389

1390
/*****************************************************************************
1391
generate_pfix_velocity
1392
Purpose:(Generates a pfix cartesian velocity of the vehicle from a reference
1393
         point and NED-expressed velocity relative to that reference point)
1394
*****************************************************************************/
1395
void
1396
StateInitialize::generate_pfix_velocity()
29✔
1397
{
1398
  if (use_veh_position_as_reference) {
29✔
1399
    return;
×
1400
  }
1401

1402
  // Otherwise, use the defined reference point as the NED origin.
1403
  if (!pfix_ref_point_state_generated) {
29✔
1404
    generate_pfix_ref_point_state();
2✔
1405
  }
1406

1407
  jeod::Vector3::transform_transpose(
29✔
1408
                  pfix_ref_point_state.ned_frame.state.rot.T_parent_this,
29✔
1409
                  velocity,
29✔
1410
                  pfix_velocity);
29✔
1411
  populate_trans_init_vel_from_pfix = true;
29✔
1412
}
1413

1414

1415
/*****************************************************************************
1416
generate_pfix_velocity_from_veh_pos
1417
Purpose:(Generates the pfix velocity once the vehicle position is known)
1418
*****************************************************************************/
1419
void
1420
StateInitialize::generate_pfix_velocity_from_veh_pos()
7✔
1421
{
1422
  pfix_ref_point_state.planet = planet;
7✔
1423
  // Calculate cartesian position in the pfix frame
1424
  jeod::Vector3::transform( planet->pfix.state.rot.T_parent_this,
7✔
1425
                      trans_init.position,
7✔
1426
                      pfix_ref_point_state.cart_coords);
7✔
1427

1428
  // Compute velocity from target relative parameters
1429
  if (velocity_input_data_type==TR_InertialSpeedGammaLatang) {
7✔
1430
    TR_param.compute_velocity_from_params( speed,
15✔
1431
                                           flight_path_angle,
5✔
1432
                                           TR_Lambda,
5✔
1433
                                           pfix_ref_point_state.cart_coords,
5✔
1434
                                           pfix_velocity);
5✔
1435

1436
  // Otherwise, compute from NED velocity
1437
  } else {
1438

1439
    // Update other internal representations of pfix_ref_point_state
1440
    pfix_ref_point_state.update_from_cart(pfix_ref_point_state.cart_coords);
2✔
1441
    pfix_ref_point_state.build_ned_orientation();
2✔
1442

1443
    // vel_NED =   T_pfix->NED *  vel_pfix
1444
    // T_NED->pfix * vel_NED    = vel_pfix
1445
    jeod::Vector3::transform_transpose(
2✔
1446
                  pfix_ref_point_state.ned_frame.state.rot.T_parent_this,
2✔
1447
                  velocity,
2✔
1448
                  pfix_velocity);
2✔
1449
  }
1450
  populate_trans_init_vel_from_pfix = true;
7✔
1451
}
7✔
1452

1453
/*****************************************************************************
1454
generate_free_stream_velocity
1455
Purpose:(generates the velocity of the vehicle relative to the free stream,
1456
         expressed in the inertial RF.)
1457
Assumption:  (Input is the wind velocity relative to the planet expressed in
1458
              inertial.)
1459
*****************************************************************************/
1460
void
1461
StateInitialize::generate_free_stream_velocity(
8✔
1462
      double rel_wind_vel_inrtl[3])
1463
{
1464
  if (rel_wind_vel_inrtl == nullptr) {
8✔
1465
    CMLMessage::error(
×
1466
      __FILE__,__LINE__, jeod::BodyActionMessages::illegal_value, "\n",
1467
      "input vector is NULL.  Cannot process.\n"
1468
      "Aborting free-stream velocity generation.\n");
1469
    return;
×
1470
  }
1471

1472
  // Start with the vehicle inertial velocity,
1473
  //  - subtract off wxr to get the vehicle velocity relative to pfix expressed
1474
  //    in inertial.
1475
  //  - subtract off the (wind velocity relative to the planet expressed in
1476
  //    inertial)
1477
  // to get the (vehicle velocity relative to the wind expressed in inertial)
1478
  double omega_inrtl[3];
8✔
1479
  jeod::Vector3::transform_transpose( planet->pfix.state.rot.T_parent_this,
8✔
1480
                                planet->pfix.state.rot.ang_vel_this,
8✔
1481
                                omega_inrtl); //omega in inertial RF.
1482
  jeod::Vector3::cross(omega_inrtl,
8✔
1483
                 trans_init.position,
8✔
1484
                 omega_cross_r); // in inertial
8✔
1485
  jeod::Vector3::diff( trans_init.velocity,
8✔
1486
                 omega_cross_r,
8✔
1487
                 free_stream_velocity); // in inertial
8✔
1488
  jeod::Vector3::decr( rel_wind_vel_inrtl,
8✔
1489
                 free_stream_velocity); // in inertial
8✔
1490
}
1491

1492
/*****************************************************************************
1493
generate_rot_init_transform
1494
Purpose:(Generates the transformation matrix from inertial to the reference
1495
        frame)
1496
*****************************************************************************/
1497
void
1498
StateInitialize::generate_rot_init_transform()
139✔
1499
{
1500
  rot_init.orientation.data_source = jeod::Orientation::InputMatrix;
139✔
1501

1502
  jeod::Orientation::compute_matrix_from_euler_angles( ref_body_sequence,
139✔
1503
                                                 E_reference_body,
139✔
1504
                                                 T_reference_body);
139✔
1505
  jeod::Matrix3x3::product( T_reference_body,
139✔
1506
                      T_inrtl_reference,
139✔
1507
                      rot_init.orientation.trans);
139✔
1508
}
139✔
1509

1510

1511
/*****************************************************************************
1512
generate_inertial_velocity
1513
Purpose:(Generates a velocity-vector expressed in the inertial reference-frame
1514
         from a velocity-vector expressed in the planet-fixed reference-frame.
1515
         The planet-fixed velocity may be relative to either the inertial or
1516
         planet-fixed frames.)
1517
*****************************************************************************/
1518
void
1519
StateInitialize::generate_inertial_velocity()
36✔
1520
{
1521
  // We need velocity relative to inertial expressed in inertial.
1522
  // In some cases, the velocity is relative to inertial and in some it is
1523
  // relative to pfix.  In either, it is expressed in pfix, but we may
1524
  // need to add in the pfix relative to inertial.
1525
  if (!velocity_is_relative_to_inertial) {
36✔
1526
    jeod::Vector3::cross(planet->pfix.state.rot.ang_vel_this,
30✔
1527
                   pfix_ref_point_state.cart_coords,
30✔
1528
                   omega_cross_r);
30✔
1529
    jeod::Vector3::incr(omega_cross_r,
30✔
1530
                  pfix_velocity);
30✔
1531
  }
1532

1533
  jeod::Vector3::transform_transpose(planet->pfix.state.rot.T_parent_this,
36✔
1534
                               pfix_velocity,
36✔
1535
                               trans_init.velocity);
36✔
1536
}
36✔
1537

1538
/*****************************************************************************
1539
remove_from_trans_init
1540
Purpose:(Removes one set of initialization options from the state intializer)
1541
*****************************************************************************/
1542
void
1543
StateInitialize::remove_from_trans_init(
28✔
1544
      jeod::DynBodyInitTransState::StateItems remove_item)
1545
{
1546
  if (trans_init.state_items == jeod::DynBodyInitTransState::Both) {
28✔
1547
    if (remove_item == jeod::DynBodyInitTransState::Position) {
18✔
1548
      trans_init.state_items = jeod::DynBodyInitTransState::Velocity;
13✔
1549
    }
1550
    else if (remove_item == jeod::DynBodyInitTransState::Velocity) {
5✔
1551
      trans_init.state_items = jeod::DynBodyInitTransState::Position;
5✔
1552
    }
1553
  }
1554
  else if (trans_init.state_items == remove_item) {
10✔
1555
    use_trans_init = false;
10✔
1556
  }
1557
}
28✔
1558

1559
/*****************************************************************************
1560
remove_from_rot_init
1561
Purpose:(Removes one set of initialization options from the state intiializer)
1562
*****************************************************************************/
1563
void
1564
StateInitialize::remove_from_rot_init(
9✔
1565
      jeod::DynBodyInitRotState::StateItems remove_item)
1566
{
1567
  if (rot_init.state_items == jeod::DynBodyInitRotState::Both) {
9✔
1568
    if (remove_item == jeod::DynBodyInitRotState::Attitude) {
8✔
1569
      rot_init.state_items = jeod::DynBodyInitRotState::Rate;
5✔
1570
    }
1571
    else if (remove_item == jeod::DynBodyInitRotState::Rate) {
3✔
1572
      rot_init.state_items = jeod::DynBodyInitRotState::Attitude;
3✔
1573
    }
1574
  }
1575
  else if (rot_init.state_items == remove_item) {
1✔
1576
    use_rot_init = false;
1✔
1577
  }
1578
}
9✔
1579
/*****************************************************************************
1580
generate_random
1581
Purpose:(Generates a random unit vector and a random number)
1582
Note -- see documentatation for CorrelatedStateDispersion for demonstration of
1583
        why the individual axes should be distributed normally to generate a
1584
        unit sphere with uniform distribution across the surface.
1585
*****************************************************************************/
1586
void
1587
StateInitialize::generate_random(int seed)
2✔
1588
{
1589
  std::default_random_engine generator(seed);
2✔
1590
  std::normal_distribution<double> rand_norm(0.0, 1.0);
2✔
1591

1592
  for (unsigned int ii = 0; ii < 3; ii++) {
8✔
1593
    random_unit_vector[ii] = rand_norm(generator);
6✔
1594
  }
1595
  jeod::Vector3::normalize(random_unit_vector);
2✔
1596

1597
  std::uniform_real_distribution<double> rand_uniform(0.0, 1.0);
2✔
1598
  random_value = rand_uniform( generator);
2✔
1599
}
2✔
1600

1601
/*****************************************************************************
1602
overwrite_vel_from_free_stream
1603
Purpose:(Intended for post-application of this body action for cases that
1604
         require the free-stream-velocity, hence the wind velocity, for
1605
         computing the reference attitude.
1606
         This method will re-generate the inertial-to-reference transformation
1607
         matrix based on the free-stream velocity, rather than the pfix
1608
         velocity.
1609
         NOTE - this does not change the initialized velocity)
1610
*****************************************************************************/
1611
void
1612
StateInitialize::overwrite_attitude_from_free_stream(
5✔
1613
       double rel_wind_inrtl[3])
1614
{
1615
  if (!requires_free_stream_velocity) {
5✔
1616
    CMLMessage::warn (
1✔
1617
      __FILE__, __LINE__, jeod::BodyActionMessages::illegal_value, "\n",
1618
      "overwrite_vel_from_free_stream was called, but this is only a valid\n"
1619
      "call when the velocity was set for initialization with a free-stream"
1620
      "value.\nIgnoring call");
1621
    return;
1✔
1622
  }
1623

1624
  if (rel_wind_inrtl == nullptr) {
4✔
1625
    CMLMessage::error(
×
1626
      __FILE__,__LINE__, jeod::BodyActionMessages::illegal_value, "\n",
1627
      "input vector is NULL.  Cannot process.\n"
1628
      "Aborting attitude-overwrite.\n");
1629
    return;
×
1630
  }
1631

1632
  generate_free_stream_velocity( rel_wind_inrtl );
4✔
1633
  MathUtils::generate_inrtl_to_reference ( free_stream_velocity,
4✔
1634
                                           trans_init.position,
4✔
1635
                                           T_inrtl_reference);
4✔
1636
  generate_rot_init_transform();
4✔
1637
  // So now have the inrtial to body transformation matrix stuck in rot_init.
1638
  // Need to apply it to the body
1639
  // Cannot use apply() because this jeod::BodyAction has already been applied.
1640
  // This method is for post-application only.
1641

1642
  auto* dyn_body = get_subject_dyn_body();
4✔
1643
  if (dyn_body == nullptr) {
4✔
1644
    CMLMessage::fail(
×
1645
      __FILE__, __LINE__, "Invalid configuration\n",
1646
      "The subject provided must be a valid DynBody.");
NEW
1647
    return;
×
1648
  }
1649
  dyn_body->set_attitude_matrix(rot_init.orientation.trans,
8✔
1650
                                dyn_body->composite_body);
4✔
1651
}
1652

1653

1654
/*****************************************************************************
1655
verify_compatibility
1656
Purpose:( Some options must be consistent across pos-vel and across
1657
          att-att-rate.  This ensures that consistency)
1658
*****************************************************************************/
1659
void
1660
StateInitialize::verify_compatibility()
179✔
1661
{
1662
  if ((force_match_trans &&
179✔
1663
       (position_input_data_type != velocity_input_data_type))) {
14✔
1664
    CMLMessage::fail (
20✔
1665
      __FILE__, __LINE__,
1666
      "Action ", action_identifier, " failed:\n"
5✔
1667
      "Some options require similar usage between the partner initialize\n"
1668
      "methods.\n"
1669
      "For example, if using TransInit for position, then TransInit should\n"
1670
      "also be used for velocity (or turn the velocity option off).\n"
1671
      "Check the documentation for the requirements for the options that\n"
1672
      "have been selected.\n"
1673
      "Position: ", position_input_data_type, "\n"
5✔
1674
      "Velocity: ", velocity_input_data_type, "\n");
5✔
1675
  }
1676

1677
  if ((force_match_rot &&
174✔
1678
       (attitude_input_data_type != att_rate_input_data_type))) {
3✔
1679
    CMLMessage::fail (
8✔
1680
      __FILE__, __LINE__,
1681
      "Action ", action_identifier, " failed:\n"
2✔
1682
      "Some options require similar usage between the partner initialize "
1683
      "methods.\n"
1684
      "For example, if using RotInit for attitude, then RotInit should\n"
1685
      "also be used for attitude-rate (or turn it off).\n"
1686
      "Check the documentation for the requirements for the options that "
1687
      "have been selected.\n"
1688
      "Attitude: ", attitude_input_data_type, " \n"
2✔
1689
      "Att-Rate: ", att_rate_input_data_type, " \n");
2✔
1690
  }
1691
}
172✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc