internal static void UpdateThreatScores(List <PointPrediction> pointPredictions, Prediction prediction)
        {
            Set <Thread> threads = new Set <Thread>();

            for (int i = 0; i < Configuration.ProcessorCount; ++i)
            {
                Thread t = new Thread(new ParameterizedThreadStart(core =>
                {
                    int pointsPerBatch    = 1000;
                    int pointNum          = 0;
                    NpgsqlCommand cmd     = DB.Connection.NewCommand("");
                    StringBuilder cmdText = new StringBuilder();
                    string table          = GetTableName(prediction);
                    for (int j = (int)core; j < pointPredictions.Count; j += Configuration.ProcessorCount)
                    {
                        PointPrediction pointPrediction = pointPredictions[j];
                        string labels, scores;
                        GetLabelsScoresSQL(pointPrediction.IncidentScore, out labels, out scores);

                        cmdText.Append("UPDATE " + table + " " +
                                       "SET " + Columns.Labels + "=" + labels + "," +
                                       Columns.ThreatScores + "=" + scores + "," +
                                       Columns.TotalThreat + "=" + pointPrediction.IncidentScore.Values.Sum() + " " +
                                       "WHERE " + Columns.Id + "=" + pointPrediction.Id + ";");

                        if (++pointNum >= pointsPerBatch)
                        {
                            cmd.CommandText = cmdText.ToString();
                            cmd.ExecuteNonQuery();
                            pointNum = 0;
                            cmdText.Clear();
                        }
                    }

                    if (pointNum > 0)
                    {
                        cmd.CommandText = cmdText.ToString();
                        cmd.ExecuteNonQuery();
                    }

                    DB.Connection.Return(cmd.Connection);
                }));

                t.Start(i);
                threads.Add(t);
            }

            foreach (Thread t in threads)
            {
                t.Join();
            }
        }
        public void Delete()
        {
            ReleaseAllLazyLoadedData();

            try { DB.Connection.ExecuteNonQuery("DELETE FROM " + Table + " WHERE " + Columns.Id + "=" + _id); }
            catch (Exception ex) { Console.Out.WriteLine("Failed to delete prediction from table:  " + ex.Message); }

            try { Point.DeleteTable(this); }
            catch (Exception ex) { Console.Out.WriteLine("Failed to delete point table:  " + ex.Message); }

            try { PointPrediction.DeleteTable(this); }
            catch (Exception ex) { Console.Out.WriteLine("Failed to delete point prediction table:  " + ex.Message); }

            try { Model.Delete(); }
            catch (Exception ex) { Console.Out.WriteLine("Failed to delete model for prediction:  " + ex.Message); }

            VacuumTable();
        }
        public Prediction Copy(string newName, bool newRun, bool vacuum)
        {
            NpgsqlCommand cmd = DB.Connection.NewCommand(null);

            Prediction copiedPrediction = null;

            try
            {
                copiedPrediction = new Prediction(Model.Copy(), newRun, newName, _predictionArea, _predictionPointSpacing, _predictionStartTime, _predictionEndTime, false);

                string copiedPointTable = Point.CreateTable(copiedPrediction, PredictionArea.Shapefile.SRID);
                cmd.CommandText = "INSERT INTO " + copiedPointTable + " (" + Point.Columns.Insert + ") " +
                                  "SELECT " + Point.Columns.Insert + " " +
                                  "FROM " + Point.GetTableName(this) + " " +
                                  "ORDER BY " + Point.Columns.Id + " ASC";
                cmd.ExecuteNonQuery();

                string copiedPointPredictionTable = PointPrediction.CreateTable(copiedPrediction);
                cmd.CommandText = "INSERT INTO " + copiedPointPredictionTable + " (" + PointPrediction.Columns.Insert + ") " +
                                  "SELECT " + PointPrediction.Columns.Insert + " " +
                                  "FROM " + PointPrediction.GetTableName(this) + " " +
                                  "ORDER BY " + PointPrediction.Columns.Id + " ASC";
                cmd.ExecuteNonQuery();

                foreach (string path in Directory.GetFiles(Model.ModelDirectory))
                {
                    File.Copy(path, Path.Combine(copiedPrediction.Model.ModelDirectory, Path.GetFileName(path)));
                }

                copiedPrediction.SmoothingDetails = _smoothingDetails;
                copiedPrediction.Done             = true;
            }
            catch (Exception ex)
            {
                Console.Out.WriteLine("Failed to copy prediction:  " + ex.Message);

                if (copiedPrediction != null)
                {
                    try { copiedPrediction.Delete(); }
                    catch (Exception ex2) { Console.Out.WriteLine("Failed to delete copied prediction:  " + ex2.Message); }
                }

                throw ex;
            }
            finally
            {
                DB.Connection.Return(cmd.Connection);

                if (vacuum)
                {
                    try { VacuumTable(); }
                    catch (Exception ex) { Console.Out.WriteLine("Failed to vacuum prediction table:  " + ex.Message); }
                    try { Point.VacuumTable(copiedPrediction); }
                    catch (Exception ex) { Console.Out.WriteLine("Failed to vacuum point table for prediction \"" + copiedPrediction.Id + "\":  " + ex.Message); }
                    try { PointPrediction.VacuumTable(copiedPrediction); }
                    catch (Exception ex) { Console.Out.WriteLine("Failed to vacuum point prediction table for prediction \"" + copiedPrediction.Id + "\":  " + ex.Message); }
                }
            }

            return(copiedPrediction);
        }