ScoringFormulas: GAP2008_some_distance_score_code.txt

File GAP2008_some_distance_score_code.txt, 12.2 KB (added by Stein Tore Erdal, 10 years ago)

Some code related to distance score in GAP2008

Line 
1private 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
220private 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}