flightanalysis 0.2.13__tar.gz → 0.2.15__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/PKG-INFO +3 -3
  2. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/f3a_criteria_maker.py +12 -12
  3. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/analysis/el_analysis.py +2 -2
  4. flightanalysis-0.2.15/flightanalysis/analysis/manoeuvre_analysis/__init__.py +14 -0
  5. flightanalysis-0.2.15/flightanalysis/analysis/manoeuvre_analysis/alignment.py +104 -0
  6. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/analysis/manoeuvre_analysis/analysis.py +8 -8
  7. flightanalysis-0.2.15/flightanalysis/analysis/manoeuvre_analysis/basic.py +131 -0
  8. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/analysis/manoeuvre_analysis/complete.py +9 -12
  9. flightanalysis-0.2.15/flightanalysis/analysis/manoeuvre_analysis/scored.py +50 -0
  10. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/analysis/sch_analysis.py +44 -52
  11. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/__init__.py +1 -1
  12. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/mandef.py +3 -0
  13. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/manparm.py +2 -2
  14. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/scheddef.py +2 -2
  15. flightanalysis-0.2.15/flightanalysis/definition/scheduleinfo.py +72 -0
  16. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/element.py +6 -6
  17. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/exponential.py +8 -6
  18. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/f3a_criteria.py +13 -12
  19. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/inter/combination.py +1 -1
  20. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/inter/comparison.py +1 -1
  21. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/intra/bounded.py +3 -3
  22. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/intra/continuous.py +3 -3
  23. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/intra/single.py +4 -5
  24. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/downgrade.py +7 -12
  25. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/measurement.py +3 -3
  26. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/results.py +64 -18
  27. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scripts/collect_scores.py +3 -3
  28. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis.egg-info/PKG-INFO +3 -3
  29. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis.egg-info/SOURCES.txt +2 -4
  30. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis.egg-info/requires.txt +2 -2
  31. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/requirements-dev.txt +1 -1
  32. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/requirements.txt +1 -1
  33. flightanalysis-0.2.13/examples/scoring/temp.py +0 -24
  34. flightanalysis-0.2.13/flightanalysis/analysis/manoeuvre_analysis/__init__.py +0 -8
  35. flightanalysis-0.2.13/flightanalysis/analysis/manoeuvre_analysis/alignment.py +0 -81
  36. flightanalysis-0.2.13/flightanalysis/analysis/manoeuvre_analysis/basic.py +0 -86
  37. flightanalysis-0.2.13/flightanalysis/analysis/manoeuvre_analysis/scored.py +0 -27
  38. flightanalysis-0.2.13/flightanalysis/definition/scheduleinfo.py +0 -45
  39. flightanalysis-0.2.13/tests/test_schedule/test_element/test_split_optimiser.py +0 -15
  40. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/.github/workflows/publish_pypi.yml +0 -0
  41. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/.gitignore +0 -0
  42. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/LICENSE +0 -0
  43. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/MANIFEST.in +0 -0
  44. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/README.md +0 -0
  45. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/__init__.py +0 -0
  46. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/data/__init__.py +0 -0
  47. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/data/manual_F3A_F23_22_04_28_00000231.json +0 -0
  48. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/data/manual_F3A_P23_22_05_31_00000350.json +0 -0
  49. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/data/manual_F3A_P23_23_08_11_00000094.json +0 -0
  50. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/__init__.py +0 -0
  51. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/judging.py +0 -0
  52. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/manoeuvres/__init__.py +0 -0
  53. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/manoeuvres/inter_analysis.py +0 -0
  54. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/manoeuvres/intra_analysis.py +0 -0
  55. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/manoeuvres/mans/__init__.py +0 -0
  56. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/manoeuvres/mans/extract_mans.py +0 -0
  57. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/manoeuvres/mans/tHat.json +0 -0
  58. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/examples/scoring/manoeuvres/positioning_analysis.py +0 -0
  59. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/__init__.py +0 -0
  60. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/analysis/__init__.py +0 -0
  61. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/IMAC_Unlimited2024_schedule.json +0 -0
  62. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/__init__.py +0 -0
  63. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/f3a_a25_schedule.json +0 -0
  64. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/f3a_f25_schedule.json +0 -0
  65. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/f3a_p23_schedule.json +0 -0
  66. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/f3a_p25_schedule.json +0 -0
  67. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/f3auk_clubman_schedule.json +0 -0
  68. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/data/f3auk_inter_schedule.json +0 -0
  69. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/builders/__init__.py +0 -0
  70. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/builders/elbuilders.py +0 -0
  71. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/builders/lines.py +0 -0
  72. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/builders/manbuilder.py +0 -0
  73. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/collectors.py +0 -0
  74. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/eldef.py +0 -0
  75. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/maninfo.py +0 -0
  76. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/manoption.py +0 -0
  77. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/operations/__init__.py +0 -0
  78. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/operations/funopp.py +0 -0
  79. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/operations/itemopp.py +0 -0
  80. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/operations/mathopp.py +0 -0
  81. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/definition/operations/operation.py +0 -0
  82. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/__init__.py +0 -0
  83. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/autorotation.py +0 -0
  84. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/line.py +0 -0
  85. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/loop.py +0 -0
  86. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/nose_drop.py +0 -0
  87. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/pitch_break.py +0 -0
  88. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/recovery.py +0 -0
  89. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/elements/stall_turn.py +0 -0
  90. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/manoeuvre.py +0 -0
  91. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/schedule.py +0 -0
  92. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/__init__.py +0 -0
  93. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/__init__.py +0 -0
  94. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/criteria.py +0 -0
  95. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/inter/__init__.py +0 -0
  96. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scoring/criteria/intra/__init__.py +0 -0
  97. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scripts/batch_analyse.py +0 -0
  98. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis/scripts/plot_scores.py +0 -0
  99. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis.egg-info/dependency_links.txt +0 -0
  100. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis.egg-info/entry_points.txt +0 -0
  101. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/flightanalysis.egg-info/top_level.txt +0 -0
  102. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/pyproject.toml +0 -0
  103. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/AMA_Intermediate2024.py +0 -0
  104. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/__init__.py +0 -0
  105. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/create_all.py +0 -0
  106. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/f3a_a25.py +0 -0
  107. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/f3a_f25.py +0 -0
  108. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/f3a_p23.py +0 -0
  109. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/f3a_p25.py +0 -0
  110. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/f3auk_clubman.py +0 -0
  111. /flightanalysis-0.2.13/scripts/f3auk_Intermediate.py → /flightanalysis-0.2.15/scripts/f3auk_intermediate.py +0 -0
  112. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/imac_sport2024.py +0 -0
  113. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/imac_unlim2024.py +0 -0
  114. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/make_manoeuvre.py +0 -0
  115. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/scripts/nsrca_inter2024.py +0 -0
  116. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/setup.cfg +0 -0
  117. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/EmailedBox.f3a +0 -0
  118. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/__init__.py +0 -0
  119. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/conftest.py +0 -0
  120. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/data/manual_F3A_P23.json +0 -0
  121. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/data/p23.BIN +0 -0
  122. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/data/p23_box.f3a +0 -0
  123. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/data/p23_fc.json +0 -0
  124. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/data/p23_flight.json +0 -0
  125. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_criiteria.py +0 -0
  126. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_data.py +0 -0
  127. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/__init__.py +0 -0
  128. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_definition/__init__.py +0 -0
  129. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_definition/test_definition_eldef.py +0 -0
  130. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_definition/test_definition_manparm.py +0 -0
  131. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_definition/test_definition_mpopp.py +0 -0
  132. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_definition/test_schedule_definition.py +0 -0
  133. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_definition/test_schedule_definition_maninfo.py +0 -0
  134. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/__init__.py +0 -0
  135. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/loop_analysis.json +0 -0
  136. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/p23_th_e0.csv +0 -0
  137. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/p23_th_e0.json +0 -0
  138. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/p23_th_e0_template.csv +0 -0
  139. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/test_schedule_element.py +0 -0
  140. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/test_schedule_element_line.py +0 -0
  141. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/test_schedule_element_loop.py +0 -0
  142. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/test_schedule_element_nose_drop.py +0 -0
  143. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/test_schedule_element_pitch_break.py +0 -0
  144. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/test_schedule_element_recovery.py +0 -0
  145. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_element/test_schedule_element_stallturn.py +0 -0
  146. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_measurement.py +0 -0
  147. {flightanalysis-0.2.13 → flightanalysis-0.2.15}/tests/test_schedule/test_schedule_manoeuvre.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flightanalysis
3
- Version: 0.2.13
3
+ Version: 0.2.15
4
4
  Summary: A package for analysing flight data
5
5
  Author-email: Thomas David <thomasdavid0@gmail.com>
6
6
  License: GNU GPL v3
@@ -16,7 +16,7 @@ Requires-Dist: simplejson
16
16
  Requires-Dist: loguru
17
17
  Requires-Dist: joblib
18
18
  Requires-Dist: pfc-geometry>=0.2.6
19
- Requires-Dist: flightdata>=0.2.11
19
+ Requires-Dist: flightdata>=0.2.14
20
20
  Provides-Extra: dev
21
21
  Requires-Dist: numpy; extra == "dev"
22
22
  Requires-Dist: pandas; extra == "dev"
@@ -26,7 +26,7 @@ Requires-Dist: simplejson; extra == "dev"
26
26
  Requires-Dist: loguru; extra == "dev"
27
27
  Requires-Dist: joblib; extra == "dev"
28
28
  Requires-Dist: pfc-geometry>=0.2.6; extra == "dev"
29
- Requires-Dist: flightdata>=0.2.11; extra == "dev"
29
+ Requires-Dist: flightdata>=0.2.14; extra == "dev"
30
30
  Requires-Dist: ardupilot_log_reader>=0.3.1; extra == "dev"
31
31
  Requires-Dist: pymavlink; extra == "dev"
32
32
 
@@ -1,20 +1,20 @@
1
1
  from flightanalysis.scoring.criteria import Single, Exponential, ContAbs, ContRat, InsideBound, MaxBound, Comparison, free, OutsideBound
2
2
  import numpy as np
3
- from itertools import chain
3
+
4
4
 
5
5
  f3a=dict(
6
6
  single=dict(
7
- track=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 100)),
8
- roll=Single(Exponential.fit_points(np.radians([30, 90]), [1, 6], 100)),
9
- angle=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 100)),
7
+ track=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 6)),
8
+ roll=Single(Exponential.fit_points(np.radians([30, 90]), [1, 6], 6)),
9
+ angle=Single(Exponential.fit_points(np.radians([30, 90]), [2, 6], 6)),
10
10
  # distance = Single(Exponential.fit_points([20, 40], [0.5, 1]))
11
11
  ),
12
12
  intra=dict(
13
- track=ContAbs(Exponential.fit_points(np.radians([30, 90]), [2, 6])),
14
- roll=ContAbs(Exponential.fit_points(np.radians([30, 90]), [1.5, 6])),
15
- radius=ContRat(Exponential.fit_points([1,5], [0.5, 4], 2)),
13
+ track=ContAbs(Exponential.fit_points(np.radians([30, 90]), [2, 6], 6)),
14
+ roll=ContAbs(Exponential.fit_points(np.radians([30, 90]), [1.5, 6], 6)),
15
+ radius=ContRat(Exponential.fit_points([1,5], [0.5, 4], 3)),
16
16
  speed=ContRat(Exponential.fit_points([1,5], [0.15, 0.75], 1)),
17
- roll_rate=ContRat(Exponential.fit_points([1,5], [0.15, 0.75], 1)),
17
+ roll_rate=ContRat(Exponential.fit_points([1,5], [0.15, 0.75], 2)),
18
18
  stallturn_speed=InsideBound(Exponential.fit_points([2, 5], [0.3,1.5]), [-2,2]),
19
19
  stallturn_width=InsideBound(Exponential.fit_points([2, 5], [0.5,2.5]), [-2,2]),
20
20
  spin_entry_length=InsideBound(Exponential.fit_points([2, 5], [0.3,1.5]), [-5,5]),
@@ -25,10 +25,10 @@ f3a=dict(
25
25
  depth=MaxBound(Exponential.fit_points([20, 40], [0.5, 1]), 170)
26
26
  ),
27
27
  inter=dict(
28
- radius=Comparison(Exponential.fit_points([1,2], [1.5, 3])),
29
- speed=Comparison(Exponential.fit_points([1,5], [0.25, 1.0])),
30
- roll_rate=Comparison(Exponential.fit_points([1,5], [0.25, 1.5])),
31
- length=Comparison(Exponential.fit_points([1,2], [1.5, 3])),
28
+ radius=Comparison(Exponential.fit_points([1,2], [1, 2], 2)),
29
+ speed=Comparison(Exponential.fit_points([1,2], [0.25, 0.5], 1)),
30
+ roll_rate=Comparison(Exponential.fit_points([1,2], [0.25, 0.5], 1)),
31
+ length=Comparison(Exponential.fit_points([1,2], [1, 2], 2)),
32
32
  free=Comparison(free),
33
33
  )
34
34
  )
@@ -16,9 +16,9 @@ class ElementAnalysis:
16
16
  tp: State
17
17
  ref_frame: g.Transformation
18
18
 
19
- def plot_3d(self, origin=False, **kwargs):
19
+ def plot_3d(self, **kwargs):
20
20
  from flightplotting import plotsec
21
- return plotsec([self.fl, self.tp], 2, 5, origin=origin, **kwargs)
21
+ return plotsec([self.fl, self.tp], **kwargs)
22
22
 
23
23
  def to_dict(self):
24
24
  return {k: v.to_dict() for k, v in self.__dict__.items()}
@@ -0,0 +1,14 @@
1
+ from .analysis import Analysis
2
+ from .basic import Basic
3
+ from .alignment import Alignment
4
+ from .complete import Complete, Scored
5
+
6
+
7
+ def parse_dict(data: dict) -> Analysis:
8
+ return Scored.from_dict(data)
9
+
10
+ def parse(data: dict) -> Basic | Alignment | Complete | Scored:
11
+ if 'parameters' in data:
12
+ return Basic.from_mindict(data).proceed()
13
+ else:
14
+ return parse_dict(data).proceed()
@@ -0,0 +1,104 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from flightdata import State
4
+ from flightanalysis.manoeuvre import Manoeuvre
5
+ from loguru import logger
6
+ from .basic import Basic
7
+ from flightanalysis.definition import ManDef, ScheduleInfo
8
+ from ..el_analysis import ElementAnalysis
9
+
10
+ @dataclass
11
+ class Alignment(Basic):
12
+ manoeuvre: Manoeuvre | None
13
+ template: State | None
14
+
15
+ def __getattr__(self, name) -> ElementAnalysis:
16
+ return ElementAnalysis(
17
+ self.mdef.data[name],
18
+ self.mdef.mps,
19
+ self.manoeuvre.elements.data[name],
20
+ self.flown.get_element(name),
21
+ self.template.get_element(name),
22
+ self.template.get_element(name)[0].transform
23
+ )
24
+
25
+ def run_all(self, optimise_aligment=True, force=False) -> Alignment | Complete | Scored:
26
+ if self.__class__.__name__ == 'Scored' and force:
27
+ self = self.downgrade()
28
+ new = self
29
+ while self.__class__.__name__ != 'Scored':
30
+ new = self.run(optimise_aligment) if isinstance(self, Complete) else self.run()
31
+ if new.__class__.__name__ == self.__class__.__name__:
32
+ break
33
+ self = new
34
+ return new
35
+
36
+ @staticmethod
37
+ def from_dict(data: dict, fallback=True):
38
+ ia = Basic.from_dict(data)
39
+ try:
40
+ ia = Alignment(
41
+ manoeuvre=Manoeuvre.from_dict(data['manoeuvre']),
42
+ template=State.from_dict(data['template']),
43
+ **ia.__dict__
44
+ )
45
+ except Exception as e:
46
+ if fallback:
47
+ logger.debug(f'Failed to parse Alignment {repr(e)}')
48
+ else:
49
+ raise e
50
+ return ia
51
+
52
+ def run(self) -> Alignment | Complete:
53
+ if 'element' not in self.flown.data.columns:
54
+ try:
55
+ self = self._run(True)[1]
56
+ except Exception as e:
57
+ logger.error(f'Failed to run alignment stage 1: {repr(e)}')
58
+ return self
59
+ try:
60
+ return self._run(False)[1].proceed()
61
+ except Exception as e:
62
+ logger.error(f'Failed to run alignment stage 2: {repr(e)}')
63
+ return self
64
+
65
+ def _run(self, mirror=False, radius=10) -> Alignment:
66
+ dist, aligned = State.align(self.flown, self.template, radius, mirror)
67
+ return dist, self.update(aligned)
68
+
69
+ def update(self, aligned: State) -> Alignment:
70
+ man, tp = self.manoeuvre.match_intention(self.template[0], aligned)
71
+ mdef = ManDef(self.mdef.info, self.mdef.mps.update_defaults(man), self.mdef.eds)
72
+ return Alignment(self.id, mdef, aligned, self.direction, man, tp)
73
+
74
+ def _proceed(self) -> Complete:
75
+ if 'element' in self.flown.data.columns:
76
+ correction = self.mdef.create(self.template[0].transform)
77
+ return Complete(
78
+ self.id, self.mdef, self.flown, self.direction,
79
+ self.manoeuvre, self.template, correction,
80
+ correction.create_template(self.template[0], self.flown)
81
+ )
82
+ else:
83
+ return self
84
+
85
+ def to_mindict(self, sinfo: ScheduleInfo=None, full=False):
86
+ data = dict(
87
+ els = self.flown.label_ranges('element').to_dict('records')
88
+ )
89
+ if full:
90
+ data = dict(
91
+ **super().to_mindict(sinfo),
92
+ **data
93
+ )
94
+ return data
95
+
96
+ def fcj_results(self):
97
+ df = self.flown.label_ranges('element').iloc[:,:3]
98
+ df.columns = ['name', 'start', 'stop']
99
+ return dict(
100
+ els=df.to_dict('records')
101
+ )
102
+
103
+ from .complete import Complete # noqa: E402
104
+ from .scored import Scored # noqa: E402
@@ -1,16 +1,16 @@
1
1
  from __future__ import annotations
2
2
  from dataclasses import dataclass
3
-
4
- class AlinmentStage:
5
- SETUP=0
6
- PRELIM=1
7
- SECONDARY=2
8
- OPTIMISED=3
9
-
3
+ from flightanalysis.definition import ScheduleInfo
10
4
 
11
5
  @dataclass
12
6
  class Analysis:
7
+ id: int
8
+
13
9
  def to_dict(self):
14
10
  return {k: (v.to_dict() if hasattr(v, 'to_dict') else v) for k, v in self.__dict__.items()}
15
11
 
16
-
12
+ def to_mindict(self, sinfo: ScheduleInfo):
13
+ return {
14
+ "sinfo": sinfo.__dict__,
15
+ }
16
+
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from flightdata import State, Flight, Origin
4
+ from flightanalysis.definition import ManDef, SchedDef, ManOption
5
+ import geometry as g
6
+ from json import load
7
+ from .analysis import Analysis
8
+ from flightanalysis.definition.scheduleinfo import ScheduleInfo
9
+ import numpy as np
10
+ import pandas as pd
11
+
12
+
13
+ @dataclass
14
+ class Basic(Analysis):
15
+ mdef: ManDef | ManOption
16
+ flown: State
17
+ direction: int
18
+
19
+ @property
20
+ def name(self):
21
+ return self.mdef.uid
22
+
23
+ def run_all(self, optimise_aligment=True, force=False) -> Scored:
24
+ """Run the analysis to the final stage, for the case where the elements have not been labelled"""
25
+ drs = [r._run(True) for r in self.run()]
26
+
27
+ dr = drs[np.argmin([dr[0] for dr in drs])]
28
+
29
+ return dr[1].run_all(optimise_aligment, force)
30
+
31
+ def proceed(self) -> Complete:
32
+ """Proceed the analysis to the final stage for the case where the elements have already been labelled"""
33
+ if 'element' not in self.flown.data.columns:
34
+ return self
35
+ mopt = ManOption([self.mdef]) if isinstance(self.mdef, ManDef) else self.mdef
36
+ elnames = self.flown.data.element.unique()
37
+ for md in mopt:
38
+ if np.all(elnames[1:-1] == list( md.eds.data.keys())):
39
+ mdef = md
40
+ break
41
+ else:
42
+ raise ValueError(f"{self.mdef.info.short_name} element sequence doesn't agree with {self.flown.data.element.unique()}")
43
+
44
+ itrans = self.create_itrans()
45
+ man, tp = mdef.create(itrans).add_lines().match_intention(
46
+ State.from_transform(itrans),
47
+ self.flown
48
+ )
49
+ mdef = ManDef(mdef.info, mdef.mps.update_defaults(man), mdef.eds)
50
+ corr = mdef.create(itrans).add_lines()
51
+ return Complete(
52
+ self.id, mdef, self.flown, self.direction,
53
+ man, tp, corr, corr.create_template(itrans, self.flown)
54
+ )
55
+
56
+ @classmethod
57
+ def from_dict(Cls, data:dict) -> Basic:
58
+ return Basic(
59
+ -1,
60
+ ManDef.from_dict(data["mdef"]),
61
+ State.from_dict(data["flown"]),
62
+ data['direction']
63
+ )
64
+
65
+ def create_itrans(self) -> g.Transformation:
66
+ return g.Transformation(
67
+ self.flown[0].pos,
68
+ self.mdef.info.start.initial_rotation(self.direction)
69
+ )
70
+
71
+ @staticmethod
72
+ def from_fcj(file: str, mid: int):
73
+ with open(file, 'r') as f:
74
+ data = load(f)
75
+ flight = Flight.from_fc_json(data)
76
+ box = Origin.from_fcjson_parmameters(data["parameters"])
77
+
78
+ sdef = SchedDef.load(data["parameters"]["schedule"][1])
79
+
80
+ state = State.from_flight(flight, box).splitter_labels(
81
+ data["mans"],
82
+ [m.info.short_name for m in sdef]
83
+ )
84
+ mdef= sdef[mid]
85
+ return Basic(mid, mdef, state.get_manoeuvre(mdef.uid))
86
+
87
+ def run(self) -> list[Alignment]:
88
+ itrans = self.create_itrans()
89
+ mopt = ManOption([self.mdef]) if isinstance(self.mdef, ManDef) else self.mdef
90
+
91
+ als = []
92
+ for mdef in mopt:
93
+ man = mdef.create(itrans).add_lines()
94
+ als.append(Alignment(
95
+ self.id, mdef, self.flown, self.direction,
96
+ man, man.create_template(itrans)
97
+ ))
98
+ return als
99
+
100
+ def to_mindict(self, sinfo: ScheduleInfo):
101
+ data = dict(
102
+ **super().to_mindict(sinfo),
103
+ name=self.name,
104
+ id=self.id,
105
+ data=self.flown._create_json_data().to_dict('records'),
106
+ direction=self.direction,
107
+ )
108
+ return data
109
+
110
+ @staticmethod
111
+ def from_mindict(data: dict):
112
+ info = ScheduleInfo.from_str(data["parameters"]["schedule"][1])
113
+
114
+ st = State.from_flight(
115
+ Flight.from_fc_json(data),
116
+ Origin.from_fcjson_parmameters(data["parameters"])
117
+ )
118
+
119
+ mdef = SchedDef.load(info)[data['id']]
120
+
121
+ if 'els' in data:
122
+ df = pd.DataFrame(data['els'])
123
+ df.columns = ['name', 'start', 'stop', 'length']
124
+ st = st.splitter_labels(df.to_dict('records'), target_col='element').label(manoeuvre=data['name'])
125
+
126
+ return Basic(data['id'], mdef, st, data['direction'])
127
+
128
+
129
+ from .alignment import Alignment # noqa: E402
130
+ from .complete import Complete # noqa: E402
131
+ from .scored import Scored # noqa: E402
@@ -2,13 +2,13 @@ from __future__ import annotations
2
2
  from dataclasses import dataclass
3
3
  from ..el_analysis import ElementAnalysis
4
4
  from flightdata import State
5
- from flightanalysis.definition import ManDef
5
+ from flightanalysis.definition import ManDef, ScheduleInfo
6
6
  from flightanalysis.manoeuvre import Manoeuvre
7
7
  from flightanalysis.scoring import Results, ManoeuvreResults, Measurement
8
8
  from flightanalysis.scoring.criteria.f3a_criteria import F3A
9
9
  from flightanalysis.definition.maninfo import Position
10
10
  import numpy as np
11
- from .alignment import Alignment, AlinmentStage
11
+ from .alignment import Alignment
12
12
  from loguru import logger
13
13
 
14
14
 
@@ -34,7 +34,7 @@ class Complete(Alignment):
34
34
  return pa
35
35
 
36
36
  def run(self, optimise_aligment=True) -> Scored:
37
- if self.stage < AlinmentStage.OPTIMISED and optimise_aligment:
37
+ if optimise_aligment:
38
38
  self = self.optimise_alignment()
39
39
  self = self.update_templates()
40
40
  return Scored(**self.__dict__,
@@ -63,6 +63,7 @@ class Complete(Alignment):
63
63
  tp = el.get_data(self.template).relocate(st.pos[0])
64
64
  return ElementAnalysis(edef, self.mdef.mps, el, st, tp, el.ref_frame(tp))
65
65
 
66
+
66
67
  def update_templates(self):
67
68
  if not np.all(self.flown.element == self.template.element):
68
69
  manoeuvre, template = self.manoeuvre.match_intention(self.template[0], self.flown)
@@ -70,8 +71,9 @@ class Complete(Alignment):
70
71
  correction = mdef.create(self.template[0].transform).add_lines()
71
72
 
72
73
  return Complete(
73
- mdef, self.flown, self.direction, AlinmentStage.OPTIMISED, self.dist,
74
- manoeuvre, template, correction, correction.create_template(template[0])
74
+ self.id, mdef, self.flown, self.direction,
75
+ manoeuvre, template, correction,
76
+ correction.create_template(template[0])
75
77
  )
76
78
  else:
77
79
  return self
@@ -127,13 +129,6 @@ class Complete(Alignment):
127
129
  Measurement.depth(self.flown)
128
130
  )
129
131
 
130
- # val = self.flown.pos.y.mean()
131
- # id = np.abs(self.flown.pos.y - val).argmin()
132
- # m = Measurement.depth(self.flown[id])
133
- # error = np.maximum(m.value, 170) - 170
134
- # dist_dg = F3A.single.distance.lookup(error) * m.visibility
135
- # return Result("distance", m, m.value, error, dist_dg, [id])
136
-
137
132
  def intra(self):
138
133
  return self.manoeuvre.analyse(self.flown, self.template)
139
134
 
@@ -160,4 +155,6 @@ class Complete(Alignment):
160
155
  fig = plotdtw(self.flown, self.flown.data.element.unique())
161
156
  return plotsec(self.flown, color="blue", nmodels=20, fig=fig, **kwargs)
162
157
 
158
+
159
+
163
160
  from .scored import Scored # noqa: E402
@@ -0,0 +1,50 @@
1
+ from dataclasses import dataclass
2
+ from .complete import Complete
3
+ from flightanalysis.scoring import ManoeuvreResults
4
+ from flightanalysis.definition.scheduleinfo import ScheduleInfo
5
+ from loguru import logger
6
+
7
+
8
+ @dataclass
9
+ class Scored(Complete):
10
+ scores: ManoeuvreResults
11
+
12
+ def downgrade(self) -> Complete:
13
+ return Complete(
14
+ self.id, self.mdef, self.flown, self.direction,
15
+ self.manoeuvre, self.template, self.corrected,
16
+ self.corrected_template
17
+ )
18
+
19
+ @staticmethod
20
+ def from_dict(data:dict, fallback=True):
21
+ ca = Complete.from_dict(data, fallback)
22
+ try:
23
+ ca = Scored(
24
+ **ca.__dict__,
25
+ scores=ManoeuvreResults.from_dict(data["scores"])
26
+ )
27
+ except Exception as e:
28
+ if fallback:
29
+ logger.debug(f"Failed to read scores, {repr(e)}")
30
+ else:
31
+ raise e
32
+ return ca
33
+
34
+ def to_mindict(self, sinfo: ScheduleInfo=None, full=False):
35
+ data = dict(
36
+ **super().to_mindict(sinfo, full),
37
+ scores=dict(
38
+ **self.scores.summary(),
39
+ total=self.scores.score(),
40
+ k=self.mdef.info.k
41
+ )
42
+ )
43
+
44
+ return data
45
+
46
+ def fcj_results(self):
47
+ return dict(
48
+ **super().fcj_results(),
49
+ results=self.scores.fcj_results()
50
+ )
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
  from typing import Self, Union
3
- from json import load
3
+ from json import load, dump
4
4
  from flightdata import Flight, State, Origin, Collection
5
5
  from flightanalysis.definition import SchedDef, ScheduleInfo
6
6
  from . import manoeuvre_analysis as analysis
@@ -9,7 +9,7 @@ from joblib import Parallel, delayed
9
9
  import os
10
10
  import pandas as pd
11
11
  from importlib.metadata import version
12
- import geometry as g
12
+ from packaging import version as pkgversion
13
13
 
14
14
 
15
15
  class ScheduleAnalysis(Collection):
@@ -22,10 +22,8 @@ class ScheduleAnalysis(Collection):
22
22
 
23
23
  @staticmethod
24
24
  def from_fcj(file: Union[str, dict], info: ScheduleInfo=None) -> ScheduleAnalysis:
25
- if isinstance(file, str):
26
- data = load(open(file, 'r'))
27
- else:
28
- data = file
25
+ data = load(open(file, 'r')) if isinstance(file, str) else file
26
+
29
27
  flight = Flight.from_fc_json(data)
30
28
 
31
29
  if info is None:
@@ -33,26 +31,50 @@ class ScheduleAnalysis(Collection):
33
31
 
34
32
  sdef = SchedDef.load(info)
35
33
  box = Origin.from_fcjson_parmameters(data["parameters"])
36
- state = State.from_flight(flight, box).splitter_labels(
37
- data["mans"],
38
- sdef.uids
39
- )
34
+ state = State.from_flight(flight, box).splitter_labels(data["mans"],sdef.uids)
40
35
  direction = -state.get_manoeuvre(1)[0].direction()[0]
41
36
 
42
- return ScheduleAnalysis(
43
- [analysis.Basic(
44
- mdef,
45
- state.get_manoeuvre(mdef.uid),
46
- direction,
47
- analysis.AlinmentStage.SETUP
48
- ) for mdef in sdef],
49
- info
50
- )
37
+ if 'fcs_scores' in data:
38
+ versions = [pkgversion.parse(res['fa_version']) for res in data['fcs_scores']]
39
+ ilatest = versions.index(max(versions))
40
+
41
+ mas = []
42
+ for i, mdef in enumerate(sdef):
43
+ st = state.get_manoeuvre(mdef.uid)
44
+
45
+ if 'fcs_scores' in data and len(data['fcs_scores']) > 0:
46
+ df = pd.DataFrame(data['fcs_scores'][ilatest]['manresults'][i+1]['els'])
47
+ st = st.splitter_labels(df.to_dict('records'), target_col='element')
48
+
49
+ mas.append(analysis.Basic(i, mdef, st, direction).proceed())
50
+
51
+ return ScheduleAnalysis(mas,info)
51
52
 
52
- def run_all(self) -> Self:
53
+ def append_scores_to_fcj(self, file: Union[str, dict]) -> dict:
54
+ data = load(open(file, 'r')) if isinstance(file, str) else file
55
+
56
+ new_results = dict(
57
+ fa_version = version('flightanalysis'),
58
+ manresults = [None] + \
59
+ [man.fcj_results() if hasattr(man, 'fcj_results') else None for man in self]
60
+ )
61
+
62
+ if 'fcs_scores' not in data:
63
+ data['fcs_scores'] = []
53
64
 
65
+ for res in data['fcs_scores']:
66
+ if res['fa_version'] == new_results['fa_version']:
67
+ res['manresults'] = new_results['manresults']
68
+ break
69
+ else:
70
+ data['fcs_scores'].append(new_results)
71
+
72
+ return data
73
+
74
+
75
+ def run_all(self) -> Self:
54
76
  def parse_analyse_serialise(pad):
55
- res = analysis.Basic.from_dict(pad).run_all()
77
+ res = analysis.parse_dict(pad).run_all()
56
78
  logger.info(f'Completed {res.name}')
57
79
  return res.to_dict()
58
80
 
@@ -67,7 +89,6 @@ class ScheduleAnalysis(Collection):
67
89
 
68
90
  def parse_analyse_serialise(mad):
69
91
  an = analysis.Complete.from_dict(mad)
70
- an.stage = analysis.AlinmentStage.SECONDARY
71
92
  return an.run_all().to_dict()
72
93
 
73
94
  logger.info(f'Starting {os.cpu_count()} alinment optimisation processes')
@@ -75,23 +96,6 @@ class ScheduleAnalysis(Collection):
75
96
  madicts = Parallel(n_jobs=os.cpu_count())(delayed(parse_analyse_serialise)(mad) for mad in inmadicts)
76
97
  return ScheduleAnalysis([analysis.Scored.from_dict(mad) for mad in madicts], self.sinfo)
77
98
 
78
- @staticmethod
79
- def from_fcscore(file: Union[str, dict], fallback=True) -> ScheduleAnalysis:
80
- if isinstance(file, str) or isinstance(file, os.PathLike):
81
- data = load(open(file, 'r'))
82
- else:
83
- data = file
84
- sinfo = ScheduleInfo(**data['sinfo'])
85
- sdef = SchedDef.load(sinfo)
86
-
87
- mas = []
88
- for mdef in sdef:
89
- mas.append(analysis.Scored.from_dict(
90
- data['data'][mdef.info.short_name],
91
- fallback
92
- ))
93
-
94
- return ScheduleAnalysis(mas, sinfo)
95
99
 
96
100
  def scores(self):
97
101
  scores = {}
@@ -103,16 +107,4 @@ class ScheduleAnalysis(Collection):
103
107
  def summarydf(self):
104
108
  return pd.DataFrame([ma.scores.summary() if hasattr(ma, 'scores') else {} for ma in self])
105
109
 
106
- def to_fcscore(self, name: str) -> dict:
107
- total, scores = self.scores()
108
-
109
- odata = dict(
110
- name = name,
111
- client_version = 'Py',
112
- server_version = version('flightanalysis'),
113
- sinfo = self.sinfo.__dict__,
114
- score = total,
115
- manscores = scores,
116
- data = self.to_dict()
117
- )
118
- return odata
110
+
@@ -12,6 +12,6 @@ from .manparm import ManParm, ManParms, DummyMPs
12
12
  from .eldef import ElDef, ElDefs
13
13
  from .mandef import ManDef
14
14
  from .manoption import ManOption
15
- from .scheduleinfo import ScheduleInfo, fcj_schedule_names, schedule_library
15
+ from .scheduleinfo import ScheduleInfo, schedule_library
16
16
  from .scheddef import SchedDef
17
17
  from .builders.manbuilder import ManBuilder, f3amb, MBTags, centred, imacmb, r, c45, dp
@@ -34,6 +34,9 @@ class ManDef:
34
34
  self.mps: ManParms = ManParms.create_defaults_f3a() if mps is None else mps
35
35
  self.eds: ElDefs = ElDefs() if eds is None else eds
36
36
 
37
+ def __repr__(self):
38
+ return f"ManDef({self.info.name})"
39
+
37
40
  @property
38
41
  def uid(self):
39
42
  return self.info.short_name
@@ -25,7 +25,7 @@ class ManParm(Opp):
25
25
 
26
26
  """
27
27
  criteria: Criteria
28
- defaul:Any=None
28
+ defaul:Number=None
29
29
  collectors:Collectors=field(default_factory=lambda : Collectors())
30
30
 
31
31
 
@@ -78,7 +78,7 @@ class ManParm(Opp):
78
78
  [c(els) for c in self.collectors],
79
79
  self.defaul,
80
80
  direction,
81
- [vis[0]] + [max(va, vb) for va, vb in zip(vis[:-1], vis[1:])],
81
+ np.array([vis[0]] + [max(va, vb) for va, vb in zip(vis[:-1], vis[1:])]),
82
82
  [str(c) for c in self.collectors]
83
83
  )
84
84
 
@@ -1,4 +1,4 @@
1
- from . import ManDef, ManInfo, ManOption, ScheduleInfo, fcj_schedule_names
1
+ from . import ManDef, ManInfo, ManOption, ScheduleInfo
2
2
  from flightdata import State
3
3
  from typing import Tuple, Union, Self
4
4
  from geometry import Transformation
@@ -95,7 +95,7 @@ class SchedDef(Collection):
95
95
  fcj = self.label_exit_lines(template).create_fc_json(
96
96
  [0] + [man.info.k for man in self] + [0],
97
97
  sname,
98
- fcj_schedule_names[kind.lower()][-1]
98
+ kind.lower()
99
99
  )
100
100
 
101
101
  with open(path, 'w') as f: