예제 #1
0
파일: reports.go 프로젝트: hugoh/complaints
func serfr1AtReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	meta := ReportMetadata{}
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{flightdb.KTagSERFR1}

	pos := sfo.KFixes[opt.Waypoint]
	out := []ReportRow{}

	iter := fdb.NewIter(fdb.QueryTimeRangeByTags(tags, s, e))
	nSerfr1 := 0
	for {
		f, err := iter.NextWithErr()
		if err != nil {
			fdb.C.Errorf("serfr1AtReport iterator failed: %v", err)
			return nil, nil, err
		} else if f == nil {
			break // We've hit EOF
		}
		nSerfr1++

		if _, exists := f.Tracks["ADSB"]; exists == true {
			meta["[B] with data from "+f.Tracks["ADSB"].LongSource()]++
		}
		if _, exists := f.Tracks["FA"]; exists == true {
			meta["[B] with data from "+f.Tracks["FA"].LongSource()]++
		} else {
			meta["[B] with data from "+f.Track.LongSource()]++
		}

		if itp, err := f.BestTrack().PointOfClosestApproach(pos); err != nil {
			c.Infof("Skipping flight %s: err=%v", f, err)
		} else {
			url := template.HTML(fmt.Sprintf("%s&waypoint=%s", flight2Url(*f), opt.Waypoint))
			f.Tracks = nil // avoid running out of F1 RAM!
			row := SERFR1AtRow{url, *f, itp}
			out = append(out, row)
		}
	}

	meta["[A] Total SERFR1 flights "] = float64(nSerfr1)

	return out, meta, nil
}
예제 #2
0
파일: reports.go 프로젝트: hugoh/complaints
func serfr1Report(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)

	meta := ReportMetadata{}
	out := []ReportRow{}

	idspecs := []string{}

	reportFunc := func(f *flightdb.Flight) {
		classBViolation := f.HasTag(flightdb.KTagReliableClassBViolation)
		hasAdsb := false
		if _, exists := f.Tracks["ADSB"]; exists == true {
			meta["[B] with data from "+f.Tracks["ADSB"].LongSource()]++
			idspecs = append(idspecs, fmt.Sprintf("%s@%d", f.Id.ModeS, f.EnterUTC.Unix()))
		}
		if t, exists := f.Tracks["FA"]; exists == true {
			meta["[B] with data from "+f.Tracks["FA"].LongSource()]++
			hasAdsb = t.IsFromADSB()
		} else {
			meta["[B] with data from "+f.Track.LongSource()]++
		}

		fClone := f.ShallowCopy()

		row := SERFR1Row{flight2Url(*fClone), *fClone, hasAdsb, classBViolation}
		out = append(out, row)
	}

	tags := []string{flightdb.KTagSERFR1}
	if err := fdb.IterWith(fdb.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
		return nil, nil, err
	}

	approachUrl := fmt.Sprintf("http://ui-dot-serfr0-fdb.appspot.com/fdb/approach?idspec=%s",
		strings.Join(idspecs, ","))

	meta[fmt.Sprintf("[Z] %s", approachUrl)] = 1

	meta["[A] Total SERFR1 flights "] = float64(len(out))
	return out, meta, nil
}
예제 #3
0
func report3Handler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("rep") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
			"Reports":   report.ListReports(),
			"FormUrl":   "/report3/",
			"Waypoints": sfo.ListWaypoints(),
		}
		if err := templates.ExecuteTemplate(w, "report3-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	rep, err := report.SetupReport(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.FormValue("debug") != "" {
		str := fmt.Sprintf("Report Options\n\n%s\n", rep.Options)
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte(fmt.Sprintf("OK\n\n%s\n", str)))
		return
	}

	//airframes := ref.NewAirframeCache(c)
	client := newurlfetch.Client(newappengine.NewContext(r))
	metars, err := metar.FetchFromNOAA(client, "KSFO",
		rep.Start.AddDate(0, 0, -1), rep.End.AddDate(0, 0, 1))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	v1idspecs := []string{}
	v2idspecs := []string{}

	v1idspecComplement := []string{}

	reportFunc := func(oldF *oldfdb.Flight) {
		newF, err := oldF.V2()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		} else {
			newF.ComputeIndicatedAltitudes(metars)
			if included, err := rep.Process(newF); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			} else if included {
				v1idspecs = append(v1idspecs, oldF.UniqueIdentifier())
				v2idspecs = append(v2idspecs, newF.IdSpec())
			} else {
				v1idspecComplement = append(v1idspecComplement, oldF.UniqueIdentifier())
			}
		}
	}

	tags := tagList(rep.Options)

	db := oldfgae.FlightDB{C: oldappengine.Timeout(oldappengine.NewContext(r), 600*time.Second)}
	s, e := rep.Start, rep.End
	if err := db.LongIterWith(db.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	postButtons := ButtonPOST(fmt.Sprintf("%d Matches as a VectorMap", len(v1idspecs)),
		fmt.Sprintf("/fdb/trackset2?%s", rep.ToCGIArgs()), v1idspecs)
	postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as a VectorMap", len(v1idspecComplement)),
		fmt.Sprintf("/fdb/trackset2?%s", rep.ToCGIArgs()), v1idspecComplement)
	if rep.Name == "sfoclassb" {
		postButtons += ButtonPOST(fmt.Sprintf("%d Matches as ClassBApproaches", len(v1idspecs)),
			fmt.Sprintf("/fdb/approach2?%s", rep.ToCGIArgs()), v1idspecs)
		// This is kinda useless, as it isn't limited to SERFR1 things
		postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as ClassBApproaches", len(v1idspecComplement)),
			fmt.Sprintf("/fdb/approach2?%s", rep.ToCGIArgs()), v1idspecComplement)

		postButtons += ButtonPOST(fmt.Sprintf("%d Matches as ClassBApproaches (delta)",
			len(v1idspecs)), fmt.Sprintf("/fdb/approach2?%s&colorby=delta", rep.ToCGIArgs()), v1idspecs)
		// This is kinda useless, as it isn't limited to SERFR1 things
		postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as ClassBApproaches (delta)",
			len(v1idspecComplement)), fmt.Sprintf("/fdb/approach2?%s&colorby=delta",
			rep.ToCGIArgs()), v1idspecComplement)
	}

	var params = map[string]interface{}{
		"R":           rep,
		"Metadata":    rep.MetadataTable(),
		"PostButtons": template.HTML(postButtons),
		"OptStr":      template.HTML(fmt.Sprintf("<pre>%s</pre>\n", rep.Options)),
		"IdSpecs":     template.HTML(strings.Join(v1idspecs, ",")),
	}
	if err := templates.ExecuteTemplate(w, "report3-results", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
예제 #4
0
파일: reports.go 프로젝트: hugoh/complaints
func serfr1ComplaintsReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	cdb := complaintdb.ComplaintDB{C: c, Memcache: true}
	meta := ReportMetadata{}

	memKey := fmt.Sprintf("serfr1complaintsreport:%s:%d-%d", s.Unix(), e.Unix())

	if rows, meta, err := reportFromMemcache(c, memKey); err == nil {
		return rows, meta, err
	}

	if complaints, err := cdb.GetComplaintsInSpan(s, e); err != nil {
		return nil, nil, err

	} else {
		meta["[B] Total disturbance reports"] = float64(len(complaints))

		nFlights := 0
		nFpC := map[string]int{} // num flights per carrier
		nCpC := map[string]int{} // num complaints per carrier

		// Aggregate complaints per flightnumber (as seen from complaints)
		nC, nSB, nWC := map[string]int{}, map[string]int{}, map[string]int{}
		for _, comp := range complaints {
			if k := comp.AircraftOverhead.FlightNumber; k != "" {
				nC[k] += 1
				nWC[k] += comp.Loudness
				if comp.HeardSpeedbreaks {
					nSB[k] += 1
					nWC[k] += 4
				}
			}
		}

		rows := []SCRow{}
		reportFunc := func(f *flightdb.Flight) {
			nFlights++

			carrier := f.Id.Designator.IATAAirlineDesignator
			if carrier != "" {
				nFpC[carrier] += 1
			}

			if k := f.Id.Designator.String(); k != "" {
				if carrier != "" {
					nCpC[carrier] += nC[k]
				}
				fClone := f.ShallowCopy()
				scRow := SCRow{
					NumComplaints:      nC[k],
					NumSpeedbrakes:     nSB[k],
					WeightedComplaints: nWC[k],
					F:                  *fClone,
				}
				rows = append(rows, scRow)
				meta["[B] SERFR1 disturbance reports"] += float64(nC[k])
			}
		}

		tags := []string{flightdb.KTagSERFR1}
		if err := fdb.IterWith(fdb.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
			return nil, nil, err
		}

		meta["[A] Total flights we saw on SERFR1"] += float64(nFlights)
		meta["[C] Average number of reports per overflight"] =
			float64(int64(float64(len(complaints)) / float64(nFlights)))

		sort.Sort(SCRowByNumComplaints(rows))
		out := []ReportRow{}
		for _, r := range rows {
			out = append(out, r)
		}

		bestCarrier, worstCarrier := "", ""
		bestScore, worstScore := 999, -1
		for carrier, nFlights := range nFpC {
			if nFlights < 3 {
				continue
			}
			cPerFlight := nCpC[carrier] / nFlights
			if cPerFlight < bestScore {
				bestCarrier, bestScore = carrier, cPerFlight
			}
			if cPerFlight > worstScore {
				worstCarrier, worstScore = carrier, cPerFlight
			}
		}

		meta["[D] Worst airline (average reports per overflight) - "+worstCarrier] = float64(worstScore)
		meta["[E] Best airline (average reports per overflight) - "+bestCarrier] = float64(bestScore)

		// reportToMemcache(c, out, meta, memKey)
		return out, meta, nil
	}
}
예제 #5
0
파일: reports.go 프로젝트: hugoh/complaints
func classbReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{
		flightdb.KTagReliableClassBViolation,
		flightdb.KTagLocalADSBClassBViolation,
	}

	meta := ReportMetadata{}
	h := histogram.Histogram{} // Only use it for the stats
	rows := []ReportRow{}

	seen := map[string]bool{} // Because we do two passes, we might see same flight twice.

	metars, err := metar.FetchFromNOAA(urlfetch.Client(c), "KSFO",
		s.Add(-6*time.Hour), e.Add(6*time.Hour))
	if err != nil {
		return rows, meta, err
	}

	reportFunc := func(f *flightdb.Flight) {
		if _, exists := seen[f.UniqueIdentifier()]; exists {
			return
		} else {
			seen[f.UniqueIdentifier()] = true
		}

		bestTrack := "FA"
		if f.HasTag(flightdb.KTagLocalADSBClassBViolation) {
			bestTrack = "ADSB"
		}

		_, cbt := f.SFOClassB(bestTrack, metars)

		tmpRows := []ReportRow{}

		seq := 0
		for _, cbtp := range cbt {
			if cbtp.A.IsViolation() {
				fClone := f.ShallowCopy()
				tmpRows = append(tmpRows, CBRow{seq, flight2Url(*fClone), *fClone, cbtp.TP, cbtp.A})
				seq++
			}
		}

		if len(tmpRows) == 0 {
			return
		}

		worstCBRow := tmpRows[0].(CBRow)
		if seq > 0 {
			// Select the worst row
			n, belowBy := 0, 0.0
			for i, row := range tmpRows {
				if row.(CBRow).A.BelowBy > belowBy {
					n, belowBy = i, row.(CBRow).A.BelowBy
				}
			}
			worstCBRow = tmpRows[n].(CBRow)
			worstCBRow.Seq = 0 // fake this out for the webpage
		}

		if opt.ClassB_LocalDataOnly && !f.HasTag(flightdb.KTagLocalADSBClassBViolation) {
			meta["[C] -- Skippped; not local - "+worstCBRow.TP.LongSource()]++
		} else {
			meta["[C] -- Detected via "+worstCBRow.TP.LongSource()]++
			h.Add(histogram.ScalarVal(worstCBRow.A.BelowBy))

			if opt.ClassB_OnePerFlight {
				rows = append(rows, worstCBRow)
			} else {
				rows = append(rows, tmpRows...)
			}
		}
	}

	// Need to do multiple passes, because of tagA-or-tagB sillness
	// In each case, limit to SERFR1 flights
	for _, tag := range tags {
		theseTags := []string{tag, flightdb.KTagSERFR1}
		if err := fdb.IterWith(fdb.QueryTimeRangeByTags(theseTags, s, e), reportFunc); err != nil {
			return nil, nil, err
		}
	}

	if n, err := fdb.CountTimeRangeByTags([]string{flightdb.KTagSERFR1}, s, e); err != nil {
		return nil, nil, err
	} else {
		meta["[A] Total SERFR1 Flights"] = float64(n)
	}

	if stats, valid := h.Stats(); valid {
		meta["[B] Num violating flights"] = float64(stats.N)
		meta["[D] Mean violation below Class B floor"] = float64(int(stats.Mean))
		meta["[D] Stddev"] = float64(int(stats.Stddev))
	} else {
		meta["[B] Num violating flights"] = 0.0
	}

	return rows, meta, nil
}