FACT++  1.0
makeschedule.cc
Go to the documentation of this file.
1 #include "externals/Prediction.h"
2 
3 #include <boost/algorithm/string/join.hpp>
4 
5 #include "Database.h"
6 
7 #include "tools.h"
8 #include "Time.h"
9 #include "Configuration.h"
10 
11 using namespace std;
12 using namespace Nova;
13 
14 // -----------------------------------------------------------------------
15 
17 {
18  po::options_description control("Makeschedule");
19  control.add_options()
20  ("date", var<string>(), "SQL time (UTC), e.g. '2016-12-24' (equiv. '2016-12-24 12:00:00' to '2016-12-25 11:59:59')")
21  ("source-database", var<string>()->required(), "Database link as in\n\tuser:password@server[:port]/database.")
22  ("schedule-database", var<string>(), "Database link as in\n\tuser:password@server[:port]/database.")
23  ("max-current", var<double>(90), "Global maximum current limit in uA")
24  ("max-zd", var<double>(75), "Global zenith distance limit in degree")
25  ("source", vars<string>(), "List of all TeV sources to be included, names according to the database")
26  ("setup.*", var<double>(), "Setup for the sources to be observed")
27  ("preobs.*", vars<string>(), "Prescheduled observations")
28  ("startup.offset", var<double>(15), "Determines how many minutes the startup is scheduled before data-taking.start [0;120]")
29  ("data-taking.start", var<double>(-12), "Begin of data-taking in degree of sun below horizon")
30  ("data-taking.end", var<double>(-13.75), "End of data-taking in degree of sun below horizon")
31  ("enter-schedule-into-database", var<bool>(), "Enter schedule into database (required schedule-database, false: dry-run)")
32  ;
33 
34  po::positional_options_description p;
35  p.add("date", 1); // The first positional options
36 
37  conf.AddOptions(control);
38  conf.SetArgumentPositions(p);
39 }
40 
41 void PrintUsage()
42 {
43  cout <<
44  "makeschedule - Creates an automatic schedule\n"
45  "\n"
46  "Usage: makeschedule [yyyy-mm-dd]\n";
47  cout << endl;
48 }
49 
50 void PrintHelp()
51 {
52 #ifdef HAVE_ROOT
53  cout <<
54  "First for each minute of the night a list is calculated of all "
55  "selected sources fulfiling all global and all source specific "
56  "constraints, e.g. on the zenith distance or the current.\n"
57  "\n"
58  "The remaining source list is sorted by the relative threshold, "
59  "while the threshold is weighted with a user defined source "
60  "specific penalty. The first source of the list is taken to "
61  "be observed.\n"
62  "\n"
63  "In a next step the first and last source of the resulting schedule "
64  "are evaluated. If their observation time is below 40', it is tried "
65  "to extend it to 40min. If this violates one of the criteria mentioned "
66  "above or gives an observation time for the neighbouring source of "
67  "less than 40min, try to replace it by the neighbouring source. "
68  "If this also does not fulfil the requirements, the original "
69  "schedule remains unchanged.\n"
70  "\n"
71  "Now a similar check is run for all intermediate sources. They are "
72  "checked (from the beginning to the end, one by one), if they have "
73  "an observation time of less than 40min. In this case, it is tried "
74  "to remove them. The observation of the two neighbouring sources is "
75  "extended to their penalized point of equal relative threshold. "
76  "If this solution would not fulfil all criteria, no change is made.\n"
77  "\n"
78  "In a last step, all remaining sources with less than 5min "
79  "observation time are replaced with sleep and sleep after startup "
80  "or before shutdown are removed.\n"
81  "\n"
82  "\n"
83  "Examples:\n"
84  "\n"
85  " makeschedule 2016-12-24\n"
86  "\n"
87  "Calculate the Christmas schedule for 2016 using all TeV sources from the\n"
88  "database. If the date is omitted the current date is used.\n"
89  "\n"
90  " makeschedule --source='Mrk 421' --source='Mrk 501' --source='Crab'\n"
91  "\n"
92  "Use only the mentioned sources to calculate the schedule.\n"
93  "\n"
94  " makeschedule --source=Crab --setup.Crab.max-zd=30\n"
95  "\n"
96  "Limit the zenith distance of Crab into the range [0;30]deg.\n"
97  "\n"
98  " makeschedule --source=Crab --setup.Crab.max-current=50\n"
99  "\n"
100  "Limit the maximum estimated current of Crab at 50uA.\n"
101  "\n"
102  " makeschedule --source='IC 310' '--setup.IC 310.penalty=1.2'\n"
103  "\n"
104  "Multiply IC310's estimated relative threshold by a factor 1.2\n"
105  "\n";
106  cout << endl;
107 #endif
108 }
109 
110 
111 struct MyDouble
112 {
113  double val;
114  bool valid;
115  MyDouble(Configuration &conf, const string &str) : val(0)
116  {
117  valid = conf.Has(str);
118  if (valid)
119  val = conf.Get<double>(str);
120  }
121  MyDouble() : val(0), valid(false) {}
122 };
123 
124 /*
125 struct MinMax
126 {
127  MyDouble min;
128  MyDouble max;
129  MinMax(Configuration &conf, const string &str)
130  {
131  min = MyDouble(conf, str+".min");
132  max = MyDouble(conf, str+".max");
133  }
134  MinMax() {}
135 };
136 */
137 
138 struct Source
139 {
140  // Global limits
141  static double max_current;
142  static double max_zd;
143 
144  // Source descrition
145  string name;
146  uint16_t key;
148 
149  // Source specific limits
152  double penalty;
153 
154  // Possible observation time
155  double begin;
156  double end;
157 
158  // Threshold (sorting reference)
159  double threshold;
160 
161  double duration() const { return end-begin; };
162 
163  // Pre-observations (e.g. ratescan)
164  vector<string> preobs;
165 
166  Source(const string &n="", uint16_t k=-1) : name(n), key(k), begin(0), threshold(std::numeric_limits<double>::max()) { }
167 
168  //bool IsSpecial() const { return threshold==std::numeric_limits<double>::max(); }
169 
170  double zd(const double &jd) const
171  {
172  return 90-GetHrzFromEqu(equ, jd).alt;
173  }
174 
175  bool valid(const SolarObjects &so) const
176  {
177  const HrzPosn hrz = GetHrzFromEqu(equ, so.fJD);
178  const double current = FACT::PredictI(so, equ);
179 
180  if (current>max_current)
181  return false;
182 
183  if (hrz.alt<=0 || 90-hrz.alt>max_zd)
184  return false;
185 
186  if (maxzd.valid && 90-hrz.alt>maxzd.val)
187  return false;
188 
189  if (maxcurrent.valid && current>maxcurrent.val)
190  return false;
191 
192  return true;
193  }
194 
195  bool IsRangeValid(const double &jd_begin, const double &jd_end) const
196  {
197  const uint32_t n = nearbyint((jd_end-jd_begin)*24*60);
198  for (uint32_t i=0; i<n; i++)
199  if (!valid(SolarObjects(jd_begin+i/24./60.)))
200  return false;
201 
202  return true;
203  }
204 
205  double getThreshold(const SolarObjects &so) const
206  {
207  const HrzPosn hrz = GetHrzFromEqu(equ, so.fJD);
208  const double current = FACT::PredictI(so, equ);
209 
210  const double ratio = pow(cos((90-hrz.alt)*M_PI/180), -2.664);
211 
212  return penalty*ratio*pow(current/6.2, 0.394);
213  }
214 
215  bool calcThreshold(const SolarObjects &so)
216  {
217  const HrzPosn hrz = GetHrzFromEqu(equ, so.fJD);
218  const double current = FACT::PredictI(so, equ);
219 
220  if (current>max_current)
221  return false;
222 
223  if (hrz.alt<=0 || 90-hrz.alt>max_zd)
224  return false;
225 
226  if (maxzd.valid && 90-hrz.alt>maxzd.val)
227  return false;
228 
229  if (maxcurrent.valid && current>maxcurrent.val)
230  return false;
231 
232  const double ratio = pow(cos((90-hrz.alt)*M_PI/180), -2.664);
233  threshold = penalty*ratio*pow(current/6.2, 0.394);
234 
235  return true;
236  }
237 };
238 
239 double Source::max_zd;
240 double Source::max_current;
241 
242 bool SortByThreshold(const Source &i, const Source &j) { return i.threshold<j.threshold; }
243 
244 bool RescheduleFirstSources(vector<Source> &obs)
245 {
246  if (obs.size()<2 || obs[0].duration()>=40./24/60 || obs[0].name=="SLEEP" || obs[1].name=="SLEEP")
247  return false;
248 
249  cout << "First source [" << obs[0].name << "] detected < 40min" << endl;
250 
251  const double obs1_duration = obs[1].end - obs[0].begin - 40./24/60;
252  const double obs0_end = obs[0].begin + 40./24/60;
253 
254  // Check that:
255  // - the duration for the shrunken source obs[1] is still above 40min
256  // - obs[0] does not exceed 60deg at the end of its new window
257  // - obs[0] does not exceed any limit within the new window
258 
259  if (obs1_duration>=40./24/60 && obs[0].IsRangeValid(obs[0].end, obs0_end))
260  {
261  obs[0].end = obs0_end;
262  obs[1].begin = obs0_end;
263 
264  cout << "First source [" << obs[0].name << "] extended to 40min" << endl;
265 
266  return false;
267  }
268 
269  // Try to remove the first source, check if second source fullfills all limits
270  if (obs[1].IsRangeValid(obs[0].begin, obs[0].end))
271  {
272  cout << "First source [" << obs[0].name << "] removed" << endl;
273 
274  obs[1].begin = obs[0].begin;
275  obs.erase(obs.begin());
276 
277  return true;
278  }
279 
280  // Try to remove the second source, check if the first source fullfills all limits
281  if (obs[0].IsRangeValid(obs[1].begin, obs[1].end))
282  {
283  cout << "Second source [" << obs[1].name << "] removed" << endl;
284 
285  obs[0].end = obs[1].end;
286  obs.erase(obs.begin()+1);
287 
288  if (obs.size()==0 || obs[0].name!=obs[1].name)
289  return true;
290 
291  obs[0].end = obs[1].end;
292  obs.erase(obs.begin()+1);
293 
294  cout << "Combined first two indentical sources [" << obs[0].name << "] into one observation" << endl;
295 
296  return true;
297  }
298 
299  cout << "No reschedule possible within limit." << endl;
300 
301  return false;
302 }
303 
304 bool RescheduleLastSources(vector<Source> &obs)
305 {
306  // If observation time is smaller than 40min for the first source
307  // extend it to 40min if zenith angle will not go above 60deg.
308  const int last = obs.size()-1;
309  if (obs.size()<2 || obs[last].duration()>=40./24/60 || obs[last].name=="SLEEP" || obs[last-1].name=="SLEEP")
310  return false;
311 
312  cout << "Last source [" << obs[last].name << "] detected < 40min" << endl;
313 
314  const double obs1_duration = obs[last].end - 40./24/60 - obs[last-1].begin;
315  const double obs0_begin = obs[last].end - 40./24/60;
316 
317  // Check that:
318  // - the duration for the shrunken source obs[1] is still above 40min
319  // - obs[0] does not exceed 60deg at the end of its new window
320  // - obs[0] does not exceed any limit within the new window
321 
322  if (obs1_duration>=40./24/60 && obs[last].IsRangeValid(obs0_begin, obs[last].begin))
323  {
324  obs[last].begin = obs0_begin;
325  obs[last-1].end = obs0_begin;
326 
327  cout << "Last source [" << obs[last].name << "] extended to 40min" << endl;
328 
329  return false;
330  }
331 
332  // Try to remove the last source, check if second source fullfills all limits
333  if (obs[last-1].IsRangeValid(obs[last].begin, obs[last].end))
334  {
335  cout << "Last source [" << obs[last].name << "] removed" << endl;
336 
337  obs[last-1].end = obs[last].end;
338  obs.pop_back();
339 
340  return true;
341  }
342 
343  // Try to remove the second last source, check if the first source fullfills all limits
344  if (obs[last].IsRangeValid(obs[last-1].begin, obs[last-1].end))
345  {
346  cout << "Second last source [" << obs[last-1].name << "] removed" << endl;
347 
348  obs[last].begin = obs[last-1].begin;
349  obs.erase(obs.begin()+obs.size()-2);
350 
351  if (obs.size()==0 || obs[last-1].name!=obs[last-2].name)
352  return true;
353 
354  obs[last-2].end = obs[last-1].end;
355  obs.pop_back();
356 
357  cout << "Combined last two indentical sources [" << obs[last-1].name << "] into one observation" << endl;
358 
359  return true;
360  }
361 
362  cout << "No reschedule possible within limit." << endl;
363 
364  return false;
365 }
366 
367 bool RescheduleIntermediateSources(vector<Source> &obs)
368 {
369  for (size_t i=1; i<obs.size()-1; i++)
370  {
371  if (obs[i].duration()>=40./24/60)
372  continue;
373 
374  if (obs[i-1].name=="SLEEP" && obs[i+1].name=="SLEEP")
375  continue;
376 
377  cout << "Intermediate source [" << obs[i].name << "] detected < 40min" << endl;
378 
379  double intersection = -1;
380 
381  if (obs[i-1].name=="SLEEP")
382  intersection = obs[i].begin;
383 
384  if (obs[i+1].name=="SLEEP")
385  intersection = obs[i].end;
386 
387  if (obs[i-1].name==obs[i+1].name)
388  intersection = obs[i].begin;
389 
390  if (intersection<0)
391  {
392  const uint32_t n = nearbyint((obs[i].end-obs[i].begin)*24*60);
393  for (uint32_t ii=0; ii<n; ii++)
394  {
395  const double jd = obs[i].begin+ii/24./60.;
396 
397  const SolarObjects so(jd);
398  if (obs[i-1].getThreshold(so)>=obs[i+1].getThreshold(so))
399  {
400  intersection = jd;
401  break;
402  }
403  }
404  }
405 
406  if ((obs[i-1].name!="SLEEP" && !obs[i-1].IsRangeValid(obs[i-1].end, intersection)) ||
407  (obs[i+1].name!="SLEEP" && !obs[i+1].IsRangeValid(intersection, obs[i+1].begin)))
408  {
409  cout << "No reschedule possible within limits." << endl;
410  continue;
411  }
412 
413  cout << "Intermediate source [" << obs[i].name << "] removed" << endl;
414 
415  const bool underflow = obs[i-1].duration()*24*60<40 || obs[i+1].duration()*24*60<40;
416 
417  obs[i-1].end = intersection;
418  obs[i+1].begin = intersection;
419  obs.erase(obs.begin()+i);
420 
421  i--;
422 
423  if (obs.size()>1 && obs[i].name==obs[i+1].name)
424  {
425  obs[i].end = obs[i+1].end;
426  obs.erase(obs.begin()+i+1);
427 
428  cout << "Combined two surrounding indentical sources [" << obs[i].name << "] into one observation" << endl;
429 
430  i--;
431 
432  continue;
433  }
434 
435  if (underflow)
436  cout << "WARNING - Neighbor source < 40min as well." << endl;
437  }
438  return false;
439 }
440 
441 void RemoveMiniSources(vector<Source> &obs)
442 {
443  for (size_t i=1; i<obs.size()-1; i++)
444  {
445  if (obs[i].duration()>=5./24/60)
446  continue;
447 
448  if (obs[i-1].name=="SLEEP" && obs[i+1].name=="SLEEP")
449  continue;
450 
451  cout << "Mini source [" << obs[i].name << "] detected < 5min" << endl;
452 
453  if (obs[i-1].name=="SLEEP" && obs[i+1].name=="SLEEP")
454  {
455  obs[i-1].end = obs[i+2].begin;
456 
457  obs.erase(obs.begin()+i+1);
458  obs.erase(obs.begin()+i);
459 
460  i -= 2;
461 
462  cout << "Combined two surrounding sleep into one" << endl;
463 
464  continue;
465  }
466 
467  if (obs[i-1].name=="SLEEP")
468  {
469  obs[i-1].end = obs[i+1].begin;
470  obs.erase(obs.begin()+i);
471  i--;
472 
473  cout << "Extended previous sleep" << endl;
474 
475  continue;
476  }
477 
478  if (obs[i+1].name=="SLEEP")
479  {
480  obs[i+1].begin = obs[i-1].end;
481  obs.erase(obs.begin()+i);
482 
483  cout << "Extended following sleep" << endl;
484 
485  i--;
486  continue;
487  }
488  }
489 }
490 
491 void CheckStartupAndShutdown(vector<Source> &obs)
492 {
493  if (obs.front().name=="SLEEP")
494  {
495  obs.erase(obs.begin());
496  cout << "Detected sleep after startup... removed." << endl;
497  }
498 
499  if (obs.back().name=="SLEEP")
500  {
501  obs.pop_back();
502  cout << "Detected sleep before shutdown... removed." << endl;
503  }
504 }
505 
506 void Print(const vector<Source> &obs, double startup_offset)
507 {
508  cout << Time(obs[0].begin-startup_offset).GetAsStr() << " STARTUP\n";
509  for (const auto& src: obs)
510  {
511  string tm = Time(src.begin).GetAsStr();
512  if (src.preobs.size()>0)
513  {
514  for (const auto& pre: src.preobs)
515  {
516  cout << tm << " " << pre << "\n";
517  tm = " ";
518  }
519  }
520 
521  cout << tm << " " << src.name << " [";
522  cout << src.duration()*24*60 << "'";
523  if (src.name!="SLEEP")
524  cout << Tools::Form("; %.1f/%.1f", src.zd(src.begin), src.zd(src.end));
525  cout << "]";
526 
527  if (src.duration()*24*60<40)
528  cout << " (!)";
529 
530  cout << "\n";
531  }
532  cout << Time(obs.back().end).GetAsStr() << " SHUTDOWN" << endl;
533 }
534 
535 int FillSql(Database &db, int enter, const vector<Source> &obs, double startup_offset)
536 {
537  const string query0 = "SELECT COUNT(*) FROM Schedule WHERE DATE(ADDTIME(fStart, '-12:00')) = '"+Time(obs[0].begin).GetAsStr("%Y-%m-%d")+"'";
538 
539  const mysqlpp::StoreQueryResult res0 = db.query(query0).store();
540 
541  if (res0.num_rows()!=1)
542  {
543  cout << "Check for schedule size failed." << endl;
544  return 10;
545  }
546 
547  if (uint32_t(res0[0][0])!=0)
548  {
549  cout << "Schedule not empty." << endl;
550  return 11;
551  }
552 
553  const mysqlpp::StoreQueryResult res1 = db.query("SELECT fMeasurementTypeName, fMeasurementTypeKEY FROM MeasurementType").store();
554  map<string, uint32_t> types;
555  for (const auto &row: res1)
556  types.insert(make_pair(string(row[0]), uint32_t(row[1])));
557 
558  ostringstream str;
559  str << "INSERT INTO Schedule (fStart, fUser, fMeasurementID, fMeasurementTypeKEY, fSourceKEY) VALUES ";
560 
561  str << "('" << Time(obs[0].begin-startup_offset).GetAsStr() << "', 'auto', 0, " << types["Startup"] << ", NULL),\n"; // [Startup]\n";
562  for (const auto& src: obs)
563  {
564  string tm = Time(src.begin).GetAsStr();
565 
566  /*
567  if (src.preobs.size()>0)
568  {
569  for (const auto& pre: src.preobs)
570  {
571  str << tm << " " << pre << "\n";
572  tm = " ";
573  }
574  }*/
575 
576  if (src.name!="SLEEP")
577  str << "('" << tm << "', 'auto', 0, " << types["Data"] << ", " << src.key << "),\n"; // [Data: " << src.name << "]\n";
578  else
579  str << "('" << tm << "', 'auto', 0, " << types["Sleep"] << ", NULL),\n"; // [Sleep]\n";
580  }
581 
582  str << "('" << Time(obs.back().end).GetAsStr() << "', 'auto', 0, " << types["Shutdown"] << ", NULL)";// [Shutdown]";
583 
584  if (enter<0)
585  {
586  cout << str.str() << endl;
587  return 0;
588  }
589 
590  db.query(str.str()).exec();
591 
592  cout << "Schedule entered successfully into database." << endl;
593  return 0;
594 }
595 
596 int main(int argc, const char* argv[])
597 {
598 // gROOT->SetBatch();
599 
600  Configuration conf(argv[0]);
602  SetupConfiguration(conf);
603 
604  if (!conf.DoParse(argc, argv, PrintHelp))
605  return 127;
606 
607  // ------------------ Eval config ---------------------
608 
609  const int enter = conf.Has("enter-schedule-into-database") ? (conf.Get<bool>("enter-schedule-into-database") ? 1 : -1) : 0;
610  if (enter && !conf.Has("schedule-database"))
611  throw runtime_error("enter-schedule-into-database required schedule-database.");
612 
613  Time time;
614  if (conf.Has("date"))
615  time.SetFromStr(conf.Get<string>("date")+" 12:00:00");
616 
617  if (enter && floor(time.JD())<ceil(Time().JD()))
618  throw runtime_error("Only future schedules can be entered into the database.");
619 
620  Source::max_current = conf.Get<double>("max-current");
621  Source::max_zd = conf.Get<double>("max-zd");
622 
623  const double startup_offset = conf.Get<double>("startup.offset")/60/24;
624 
625  const double angle_sun_set = conf.Get<double>("data-taking.start");
626  const double angle_sun_rise = conf.Get<double>("data-taking.end");
627 
628  if (startup_offset<0 || startup_offset>120)
629  throw runtime_error("Only values [0;120] are allowed for startup.offset");
630 
631  if (angle_sun_set>-6)
632  throw runtime_error("datataking.start not allowed before sun at -6deg");
633 
634  if (angle_sun_rise>-6)
635  throw runtime_error("datataking.end not allowed after sun at -6deg");
636 
637  // -12: nautical
638  // Sun set with the same date than th provided date
639  // Sun rise on the following day
640  const RstTime sun_set = GetSolarRst(floor(time.JD())-0.5, angle_sun_set);
641  const RstTime sun_rise = GetSolarRst(floor(time.JD())+0.5, angle_sun_rise);
642 
643  const double sunset = ceil(sun_set.set*24*60) /24/60 + 1e-9;
644  const double sunrise = floor(sun_rise.rise*24*60)/24/60 + 1e-9;
645 
646  cout << "\n";
647 
648  cout << "Date: " << Time(floor(sunset)).GetAsStr() << "\n";
649  cout << "Set: " << Time(sunset).GetAsStr() << " [" << Time(sun_set.set) << "]\n";
650  cout << "Rise: " << Time(sunrise).GetAsStr() << " [" << Time(sun_rise.rise) << "]\n";
651 
652  cout << "\n";
653 
654  cout << "Global maximum current: " << Source::max_current << " uA/pix\n";
655  cout << "Global zenith distance: " << Source::max_zd << " deg\n";
656 
657  cout << "\n";
658 
659  // ------------- Get Sources from databasse ---------------------
660 
661  const vector<string> ourcenames = conf.Vec<string>("source");
662  const vector<string> sourcenames = conf.Vec<string>("source");
663  cout << "Nsources = " << sourcenames.size() << "\n";
664 
665  string query = "SELECT fSourceName, fSourceKEY, fRightAscension, fDeclination FROM Source WHERE fSourceTypeKEY=1";
666  if (sourcenames.size()>0)
667  query += " AND fSourceName IN ('" + boost::algorithm::join(sourcenames, "', '")+"')";
668 
669  const string sourcedb = conf.Get<string>("source-database");
670  const mysqlpp::StoreQueryResult res =
671  Database(sourcedb).query(query).store();
672 
673  // ------------------ Eval config ---------------------
674 
675  vector<Source> sources;
676  for (const auto &row: res)
677  {
678  const string name = string(row[0]);
679 
680  Source src(name, row[1]);
681 
682  src.equ.ra = double(row[2])*15;
683  src.equ.dec = double(row[3]);
684 
685  src.maxzd = MyDouble(conf, "setup."+name+".max-zd");
686  src.maxcurrent = MyDouble(conf, "setup."+name+".max-current");
687  src.penalty = conf.Has("setup."+name+".penalty") ?
688  conf.Get<double>("setup."+name+".penalty") : 1;
689 
690  src.preobs = conf.Vec<string>("preobs."+name);
691 
692 
693  cout << "[" << name << "]";
694 
695  if (src.maxzd.valid)
696  cout << " Zd<" << src.maxzd.val;
697  if (src.penalty!=1)
698  cout << " Penalty=" << src.penalty;
699 
700  cout << " " << boost::algorithm::join(src.preobs, "+") << endl;
701 
702  /*
703  RstTime t1 = GetObjectRst(floor(sunset)-1, src.equ);
704  RstTime t2 = GetObjectRst(floor(sunset), src.equ);
705 
706  src.rst.transit = t1.transit<floor(sunset) ? t2.transit : t1.transit;
707  src.rst.rise = t1.rise>src.rst.transit ? t2.rise : t1.rise;
708  src.rst.set = t1.set <src.rst.transit ? t2.set : t1.set;
709  */
710 
711  sources.emplace_back(src);
712  }
713  cout << endl;
714 
715  // -------------------------------------------------------------------------
716 
717  vector<Source> obs;
718 
719  const uint32_t n = nearbyint((sunrise-sunset)*24*60);
720  for (uint32_t i=0; i<n; i++)
721  {
722  const double jd = sunset + i/24./60.;
723 
724  const SolarObjects so(jd);
725 
726  vector<Source> vis;
727  for (auto& src: sources)
728  {
729  if (src.calcThreshold(so))
730  vis.emplace_back(src);
731  }
732 
733  // In case no source was found, add a sleep source
734  Source src("SLEEP");
735  vis.emplace_back(src);
736 
737  // Source has higher priority if minimum observation time not yet fullfilled
738  sort(vis.begin(), vis.end(), SortByThreshold);
739 
740  if (obs.size()>0 && obs.back().name==vis[0].name)
741  continue;
742 
743  vis[0].begin = jd;
744  obs.emplace_back(vis[0]);
745  }
746 
747  if (obs.size()==0)
748  {
749  cout << "No source found." << endl;
750  return 1;
751  }
752 
753  // -------------------------------------------------------------------------
754 
755  for (auto it=obs.begin(); it<obs.end()-1; it++)
756  it[0].end = it[1].begin;
757  obs.back().end = sunrise;
758 
759  // -------------------------------------------------------------------------
760 
761  Print(obs, startup_offset);
762  cout << endl;
763 
764  // -------------------------------------------------------------------------
765 
766  while (RescheduleFirstSources(obs));
767  while (RescheduleLastSources(obs));
768  while (RescheduleIntermediateSources(obs));
769 
770  RemoveMiniSources(obs);
772 
773  // ---------------------------------------------------------------------
774 
775  cout << endl;
776  Print(obs, startup_offset);
777  cout << endl;
778 
779  // ---------------------------------------------------------------------
780 
781  if (!enter)
782  return 0;
783 
784  const string scheduledb = conf.Get<string>("schedule-database");
785 
786  Database db(scheduledb);
787 
788  if (enter>0)
789  db.query("LOCK TABLES Schedule WRITE");
790 
791  const int rc = FillSql(db, enter, obs, startup_offset);
792 
793  if (enter>0)
794  db.query("UNLOCK TABLES");
795 
796  // ---------------------------------------------------------------------
797 
798  return rc;
799 }
bool RescheduleFirstSources(vector< Source > &obs)
void Print(const vector< Source > &obs, double startup_offset)
int main(int argc, const char *argv[])
bool RescheduleIntermediateSources(vector< Source > &obs)
uint16_t key
bool SortByThreshold(const Source &i, const Source &j)
double begin
void PrintHelp()
Definition: makeschedule.cc:50
MyDouble(Configuration &conf, const string &str)
int i
Definition: db_dim_client.c:21
Adds some functionality to boost::posix_time::ptime for our needs.
Definition: Time.h:30
char str[80]
Definition: test_client.c:7
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
static double max_zd
Source(const string &n="", uint16_t k=-1)
void PrintUsage()
Definition: makeschedule.cc:41
STL namespace.
double begin
MyDouble maxzd
std::vector< T > Vec(const std::string &var)
void SetArgumentPositions(const po::positional_options_description &desc)
bool valid(const SolarObjects &so) const
EquPosn equ
void CheckStartupAndShutdown(vector< Source > &obs)
double JD() const
Definition: Time.h:87
bool calcThreshold(const SolarObjects &so)
bool Has(const std::string &var)
void AddOptions(const po::options_description &opt, bool visible=true)
Definition: Configuration.h:92
double zd(const double &jd) const
bool valid() const
Definition: HeadersFTM.h:271
Warning because the service this data corrsponds to might have been last updated longer ago than Local time
Definition: smartfact.txt:92
void RemoveMiniSources(vector< Source > &obs)
double end
MyDouble maxcurrent
Commandline parsing, resource file parsing and database access.
Definition: Configuration.h:9
double fJD
Definition: nova.h:162
void SetFromStr(const std::string &str, const char *fmt="%Y-%m-%d %H:%M:%S")
Definition: Time.cc:273
std::string Form(const char *fmt,...)
Definition: tools.cc:45
int FillSql(Database &db, int enter, const vector< Source > &obs, double startup_offset)
RstTime GetSolarRst(double jd, const LnLatPosn &obs, double hrz=LN_SOLAR_STANDART_HORIZON)
Definition: nova.h:97
HrzPosn GetHrzFromEqu(const EquPosn &equ, const LnLatPosn &obs, double jd)
Definition: nova.h:75
static double max_current
double penalty
vector< string > preobs
double val
Definition: nova.h:10
ln_rst_time RstTime
Definition: nova.h:13
void SetupConfiguration(Configuration &conf)
Definition: makeschedule.cc:16
double getThreshold(const SolarObjects &so) const
std::string GetAsStr(const char *fmt="%Y-%m-%d %H:%M:%S") const
Definition: Time.cc:240
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
double PredictI(const Nova::SolarObjects &so, const Nova::EquPosn &srcEqu)
Definition: Prediction.h:10
double threshold
double end
bool RescheduleLastSources(vector< Source > &obs)
bool IsRangeValid(const double &jd_begin, const double &jd_end) const