# ScoringFormulas: GAP2008_some_distance_score_code.txt

File GAP2008_some_distance_score_code.txt, 12.2 KB (added by , 10 years ago) |
---|

Line | |
---|---|

1 | private static FsTaskScoreParams CalcScoreParams(Task t, ScoreFormulaGAP sfg, Participant[] ps) |

2 | { |

3 | FsTaskScoreParams sp = new FsTaskScoreParams(); |

4 | double min_dist = sfg.Min_dist; |

5 | double task_distance = t.DistanceExact; // http://fs.fai.org/ticket/103 |

6 | sp.Task_distance = task_distance; |

7 | sp.Ss_distance = t.Ss_distance; |

8 | |

9 | double[] times = new double[ps.Length]; |

10 | int i = 0; |

11 | foreach (Participant p in ps) |

12 | { |

13 | // present |

14 | sp.No_of_pilots_present++; |

15 | |

16 | // flying |

17 | if (p._flew) sp.No_of_pilots_flying++; |

18 | |

19 | // sum dist over task min dist |

20 | if (p._distance > min_dist) sp.Sum_dist_over_min += p._distance - min_dist; |

21 | |

22 | // no pilots landing out |

23 | if (p._flew && (p._distance < task_distance || task_distance == 0)) sp.No_of_pilots_LO++; |

24 | //if (p._flew && p._finished_ss == null) sp.No_of_pilots_LO++; |

25 | |

26 | // no pilots reaching ES |

27 | if (p._flew && p._finished_ss != null) sp.No_of_pilots_reaching_ES++; |

28 | |

29 | if (p._flew && p._distance >= task_distance && task_distance > 0) sp.No_of_pilots_reaching_goal++; // not used? |

30 | |

31 | // best distance |

32 | if (p._distance > sp.Best_dist) |

33 | { |

34 | // ERDAL20090907 in response to http://fs.fai.org/ticket/198 |

35 | if (t.DistanceExact > 0 && p._distance > t.DistanceExact) sp.Best_dist = t.DistanceExact; |

36 | else sp.Best_dist = p._distance; |

37 | //if (t.Distance > 0 && p._distance > t.Distance) sp.Best_dist = t.Distance; |

38 | //else sp.Best_dist = p._distance; |

39 | } |

40 | |

41 | // those reaching end of speedsection ... |

42 | double time = p.Result.Ss_Time_Dec_Hours; |

43 | if (time > 0) |

44 | { |

45 | // http://fs.fai.org/ticket/35 |

46 | if (sp.First_start_time == null || p.Result.Started_ss.Utc_time < sp.First_start_time.Utc_time) |

47 | sp.First_start_time = p.Result.Started_ss; |

48 | |

49 | // http://fs.fai.org/ticket/16 |

50 | // store time (will sort ascending to use later for time validity calculations) |

51 | // (not using Best_time anymore) |

52 | times[i++] = time; |

53 | |

54 | // best time (given time) |

55 | if (time < sp.Best_time || sp.Best_time == 0) sp.Best_time = time; |

56 | |

57 | // first finish time |

58 | Time finishedTaskSs = p.Result.Finished_ss; |

59 | if (sp.First_finish_time == null || finishedTaskSs.Utc_time < sp.First_finish_time.Utc_time) |

60 | sp.First_finish_time = finishedTaskSs; |

61 | } |

62 | } |

63 | |

64 | // http://fs.fai.org/ticket/16 |

65 | // time_validity_based_on_pilot_with_speed_rank |

66 | // default is time of first pilot at ES |

67 | // time_validity_based_on_pilot_with_speed_rank = 1 if not specified in the scoring formula params. |

68 | Array.Sort<double>(times); |

69 | i = 0; |

70 | while (i < times.Length && times[i] == 0) i++; |

71 | i += sfg.Time_validity_based_on_pilot_no - 1; |

72 | double time_validity_time = 0; // if no one at ES time used is 0 |

73 | if (i < times.Length) time_validity_time = times[i]; // pilot no x reached ES so we use that time |

74 | else if (times.Length > 0) time_validity_time = times[times.Length - 1]; // pilot no x did not reach ES so we use the last one to reach ES. |

75 | |

76 | double time_validity = CalcTimeValidity(time_validity_time, sfg.Nom_time, sp.Best_dist, sfg.Nom_dist); |

77 | double launch_validity = CalcLaunchValidity(sp.No_of_pilots_flying, sp.No_of_pilots_present); |

78 | double distance_validity = CalcDistanceValidity(sp.Sum_dist_over_min, sp.No_of_pilots_flying, sfg.Nom_goal, sfg.Nom_dist, sfg.Min_dist, sp.Best_dist); |

79 | double day_quality = CalcDayQuality(time_validity, launch_validity, distance_validity); |

80 | |

81 | sp.Time_validity = time_validity; |

82 | sp.Launch_validity = launch_validity; |

83 | sp.Distance_validity = distance_validity; |

84 | sp.Day_quality = day_quality; |

85 | |

86 | //ERDAL20090517 |

87 | if (sfg.Day_quality > 0) |

88 | { |

89 | //sp.Time_validity = 0; |

90 | //sp.Launch_validity = 0; |

91 | //sp.Distance_validity = 0; |

92 | sp.Day_quality = sfg.Day_quality; |

93 | } |

94 | |

95 | // Distance points (depends, among other things, on ratio of pilots at ES and flying) |

96 | if (sfg.Use_distance_points) |

97 | { |

98 | sp.K = 0; // if not using time points: K=0 giving Distance_weight=0.9 |

99 | if (sp.Best_time > 0 && sfg.Use_time_points) |

100 | { |

101 | sp.Max_time_to_get_time_points = sp.Best_time + Math.Sqrt(sp.Best_time); |

102 | foreach (Participant p in ps) |

103 | { |

104 | double time = p.Result.Ss_Time_Dec_Hours; |

105 | if (time > 0 && time < sp.Max_time_to_get_time_points) |

106 | sp.No_of_pilots_with_time_points++; |

107 | } |

108 | sp.K = sp.No_of_pilots_with_time_points * 1.0 / sp.No_of_pilots_flying; |

109 | } |

110 | sp.Distance_weight = 0.9 - 1.665 * sp.K + 1.713 * Math.Pow(sp.K, 2) - 0.587 * Math.Pow(sp.K, 3); |

111 | } |

112 | |

113 | double dummy_arr_weight = 0; |

114 | // Arrival time points (OzGAP2005) |

115 | if (sfg.Use_arrival_time_points) |

116 | { |

117 | // a quart of what's left after distance got it's share |

118 | dummy_arr_weight = (1.0 - sp.Distance_weight) / 4.0; |

119 | if (sfg.If_use_arrival_time_points_div_by != 0) // ERDAL20090529 adapted to PWC2009. Note probably an error by Ulric ... probably missed the diff. btw. modOzGap2005.bas and modGAP.bas |

120 | dummy_arr_weight = dummy_arr_weight / sfg.If_use_arrival_time_points_div_by; |

121 | } |

122 | // or Arrival position points (Normal <= GAP2002) |

123 | // ERDAL20090513 http://fs.fai.org/ticket/179 |

124 | else // if (sfg.Use_arrival_position_points) |

125 | { |

126 | // an eight of what's left after distance got it's share |

127 | dummy_arr_weight = (1.0 - sp.Distance_weight) / 8.0; |

128 | } |

129 | |

130 | // Arrival (time or pos) and Departure points only if someone reached ES |

131 | if (sp.No_of_pilots_reaching_ES > 0) |

132 | { |

133 | if (sfg.Use_arrival_time_points || sfg.Use_arrival_position_points) |

134 | { |

135 | sp.Arrival_weight = dummy_arr_weight; |

136 | } |

137 | |

138 | // Departure points based on time enroute |

139 | if (sfg.Use_departure_points) |

140 | { |

141 | sp.Departure_weight = dummy_arr_weight * 1.4; |

142 | } |

143 | // or Leading Out points based on area of time/distance graph |

144 | else if (sfg.Use_leading_points) |

145 | { |

146 | sp.Leading_weight = dummy_arr_weight * 1.4; |

147 | // ERDAL20110417 PWC2010... http://fs.fai.org/ticket/219 if not using arrival points put them into leading points instead of time points |

148 | if (!sfg.Use_arrival_time_points && !sfg.Use_arrival_position_points) sp.Leading_weight += dummy_arr_weight; |

149 | } |

150 | |

151 | // Time points |

152 | if (sfg.Use_time_points) |

153 | { |

154 | sp.Time_weight |

155 | = (1 - sp.Distance_weight) |

156 | - sp.Arrival_weight |

157 | - sp.Departure_weight |

158 | - sp.Leading_weight; |

159 | } |

160 | } |

161 | else // no one reaching end of speedsection, |

162 | // hence no allocation of time, arrival, nor departure points (based on time enroute) |

163 | // Only distance points and leading points make sense here. |

164 | { |

165 | // Leading points |

166 | if (sfg.Use_leading_points) |

167 | { |

168 | sp.Leading_weight = dummy_arr_weight * 1.4; // http://fs.fai.org/ticket/88 |

169 | } |

170 | } |

171 | |

172 | // now sum of all weights should be 1. |

173 | // if it is less than 1 we add to distance weight |

174 | // ERDAL20090701 restored this again but set default value to true so it is not in user interface (yet) but can be set directly in fsdb |

175 | // ERDAL20090518 http://fs.fai.org/ticket/180 TODO: remove option all together (unless reaction is that it is needed) |

176 | if (sfg.Use_1000_points_for_max_day_quality) |

177 | sp.Distance_weight = 1 - sp.Time_weight - sp.Leading_weight - sp.Departure_weight - sp.Arrival_weight; |

178 | |

179 | // adjust for day quality |

180 | sp.Available_points_distance = 1000 * sp.Day_quality * sp.Distance_weight; |

181 | sp.Available_points_arrival = 1000 * sp.Day_quality * sp.Arrival_weight; |

182 | sp.Available_points_departure = 1000 * sp.Day_quality * sp.Departure_weight; |

183 | sp.Available_points_leading = 1000 * sp.Day_quality * sp.Leading_weight; |

184 | sp.Available_points_time = 1000 * sp.Day_quality * sp.Time_weight; |

185 | |

186 | // smallest_leading_coefficient |

187 | if (sfg.Use_departure_points |

188 | || sfg.Use_leading_points) |

189 | { |

190 | // smallest leading coefficient |

191 | sp.Smallest_leading_coefficient = 0; |

192 | double smallest_leading_coefficient = double.MaxValue; |

193 | if (sfg.Use_departure_points && sp.No_of_pilots_reaching_ES > 0) |

194 | { |

195 | foreach (Participant p in ps) |

196 | { |

197 | double lc = Gap.LcUsingDeparturePoints(p, t, sp); |

198 | if (lc > 0 && lc < smallest_leading_coefficient) smallest_leading_coefficient = lc; |

199 | } |

200 | } |

201 | else if (sfg.Use_leading_points) |

202 | { |

203 | foreach (Participant p in ps) |

204 | { |

205 | if (p._lc > 0 && (p._lc < smallest_leading_coefficient || smallest_leading_coefficient == 0)) |

206 | { |

207 | smallest_leading_coefficient = p._lc; |

208 | } |

209 | } |

210 | } |

211 | if (smallest_leading_coefficient != double.MaxValue) |

212 | sp.Smallest_leading_coefficient = smallest_leading_coefficient; |

213 | } // -- smallest_leading_coefficient |

214 | |

215 | return sp; |

216 | } |

217 | |

218 | |

219 | |

220 | private static DistanseScoreData100m[] CreateDistanceScoreData100mArray(Task t, FsTaskScoreParams sp, ScoreFormulaGAP sfg, Participant[] ps) |

221 | { |

222 | // Save info for every 100 meters of the task |

223 | |

224 | DistanseScoreData100m[] da = null; |

225 | |

226 | double best_dist = sp.Best_dist; |

227 | if (best_dist < sfg.Min_dist) best_dist = sfg.Min_dist; |

228 | if (best_dist == 0) return da; |

229 | int best_dist_kmx10 = (int)(best_dist * 10); |

230 | int best_dist_kmx10r = (best_dist_kmx10 + 10) / 10 * 10; // eg if kmx10 = 517, best_dist_kmx10r = 520 |

231 | da = new DistanseScoreData100m[best_dist_kmx10r + 1]; |

232 | |

233 | // For each 100m of task count no of landed pilots |

234 | foreach (Participant p in ps) |

235 | { |

236 | // ERDAL20090907 in response to http://fs.fai.org/ticket/198 |

237 | //double dist = p._distance; |

238 | //if (dist < sfg.Min_dist) dist = sfg.Min_dist; |

239 | //else if (t.Distance > 0 && dist > t.Distance) dist = t.Distance; |

240 | //// if landed out (ERDAL20080303-1940: not counting those in goal!!) http://fs.fai.org/ticket/60 |

241 | //if (p._flew && dist < t.Distance) da[(int)(dist * 10)]._landed++; |

242 | //// TODO: check ... for open dist. tasks it is vital that t.Distance is set to distance of the best pilot + 1 meter.!!! |

243 | |

244 | double dist = p._distance; |

245 | if (dist < sfg.Min_dist) dist = sfg.Min_dist; |

246 | else if (t.DistanceExact > 0 && dist > t.DistanceExact) dist = t.DistanceExact; |

247 | if (p._flew && dist < t.DistanceExact) da[(int)(dist * 10)]._landed++; |

248 | } |

249 | |

250 | // For each kilometer of the task find no of pilots having landed in the past kilometer |

251 | int j = 0; |

252 | for (int i = 0; i <= best_dist_kmx10r; i++) |

253 | { |

254 | // add up pilots having landed for each 100 meters |

255 | j += da[i]._landed; |

256 | // if a whole km is reached |

257 | if (Math.IEEERemainder(i, 10) == 0) |

258 | { |

259 | // pilots having landed in the past kilometer |

260 | da[i]._landed_full_km = j; |

261 | // start over for the next kilometer |

262 | j = 0; |

263 | } |

264 | } |

265 | |

266 | // Compute difficulty for each 100 meters of the task: |

267 | // find no of landed pilots up ahead ... |

268 | // 100 pilots landing out in 100km -> we look at the next 3 km. |

269 | // 10 pilots landing out in 100km -> we look at the next 30 km. |

270 | int look_ahead_dist_kmx10 = 30; // look at least 3km ahead |

271 | if (sp.No_of_pilots_LO > 0 && best_dist > sp.No_of_pilots_LO) |

272 | look_ahead_dist_kmx10 |

273 | = (int)Math.Round(look_ahead_dist_kmx10 * best_dist / sp.No_of_pilots_LO, |

274 | MidpointRounding.AwayFromZero); |

275 | for (int i = 0; i <= best_dist_kmx10; i++) |

276 | for (j = i; j < i + look_ahead_dist_kmx10 && j <= best_dist_kmx10; j++) |

277 | da[i]._difficulty += da[j]._landed; |

278 | |

279 | // sum of all difficulty |

280 | double sum_difficulty = 0; |

281 | for (int i = 0; i <= best_dist_kmx10; i++) |

282 | sum_difficulty += da[i]._difficulty; |

283 | |

284 | // Difficulty relative to sum of all difficulty |

285 | if (sum_difficulty > 0) |

286 | { |

287 | for (int i = 0; i <= best_dist_kmx10; i++) |

288 | { |

289 | da[i]._rel_diff = da[i]._difficulty / (2.0 * sum_difficulty); |

290 | } |

291 | } |

292 | |

293 | // Compute distance score % |

294 | // accumulated relative difficulty per 100 meters. |

295 | double sum_rel_difficulty = 0; |

296 | for (int i = 0; i <= best_dist_kmx10; i++) |

297 | { |

298 | sum_rel_difficulty += da[i]._rel_diff; |

299 | da[i]._score_percent = sum_rel_difficulty; |

300 | } |

301 | |

302 | // ERDAL20090518 making sure we 0.5 (sum of _rel_diff can end up at 0.49999999999999978 or similar, should not make visible diff but...) |

303 | for (int i = best_dist_kmx10; i <= best_dist_kmx10r; i++) |

304 | { |

305 | da[i]._score_percent = 0.5; |

306 | } |

307 | |

308 | // set score to all distances below or equal minimum distance |

309 | int min_dist_kmx10 = (int)(sfg.Min_dist * 10); |

310 | if (min_dist_kmx10 < da.Length) |

311 | { |

312 | for (int i = 0; i <= min_dist_kmx10; i++) |

313 | { |

314 | da[i]._score_percent = da[min_dist_kmx10]._score_percent; |

315 | } |

316 | } |

317 | return da; |

318 | } |