diff --git a/MES_Wind/frmMain.cs b/MES_Wind/frmMain.cs index 52549d510c443198eeba1e4ec784a7eb52b65229..21b2fb880880a4321e920631f2e70dca62a5f1b7 100644 --- a/MES_Wind/frmMain.cs +++ b/MES_Wind/frmMain.cs @@ -118,22 +118,25 @@ namespace MES_Wind return; } pwlLayer = map1.GetLineLayers()[0]; - //copy line layer FeatureSet + // copy line layer FeatureSet IFeatureSet pwlineSet = pwlLayer.DataSet; - //get the powerstations layer + // get the powerstations layer IMapPointLayer pwstLayer = default(IMapPointLayer); pwstLayer = map1.GetPointLayers()[0]; // copy point layer FeatureSet IFeatureSet pwpointsSet = pwstLayer.DataSet; - //Start to cast raster to PRM classes + // Start to cast raster to PRM classes // prognostic wind massives first - List<List<WindStressPRM.PrognosticCell>> prognosticWind = new List<List<WindStressPRM.PrognosticCell>>(); int rcountPrognostic = uRasterLayer.DataSet.NumRows; int ccountPrognostic = uRasterLayer.DataSet.NumColumns; - for (int i =0; i< rcountPrognostic; i++) + WindStressPRM.Matrix<WindStressPRM.PrognosticCell> prognosticMatrix = new WindStressPRM.Matrix<WindStressPRM.PrognosticCell>(); + prognosticMatrix.Cells = new WindStressPRM.PrognosticCell[rcountPrognostic, ccountPrognostic]; + prognosticMatrix.Size = new WindStressPRM.CellSize(uRasterLayer.DataSet.CellWidth, uRasterLayer.DataSet.CellHeight); + prognosticMatrix.AffineCoefficients = uRasterLayer.Bounds.AffineCoefficients; + // fill cells of prognostic matrix + for (int i = 0; i < rcountPrognostic; i++) { - List<WindStressPRM.PrognosticCell> progWindRow = new List<WindStressPRM.PrognosticCell>(); - for (int j =0; j< ccountPrognostic; j++ ) + for (int j = 0; j < ccountPrognostic; j++) { Coordinate dummyRCoords = uRasterLayer.Bounds.CellCenter_ToProj(i,j); WindStressPRM.Coordinate cellCoords =new WindStressPRM.Coordinate(dummyRCoords.X,dummyRCoords.Y); @@ -146,21 +149,19 @@ namespace MES_Wind vValue = Double.NaN; } WindStressPRM.PrognosticCell dummyPrognosticCell = new WindStressPRM.PrognosticCell(cellCoords, uValue, vValue); - progWindRow.Add(dummyPrognosticCell); + prognosticMatrix.Cells[i, j] = dummyPrognosticCell; } - prognosticWind.Add(progWindRow); - //prog_wind_row.Clear(); } - //Get cell info and Affine transform coefficients from prognostic wind rasters - WindStressPRM.CellSize progcellsize = new WindStressPRM.CellSize(uRasterLayer.DataSet.CellWidth, uRasterLayer.DataSet.CellHeight); - double[] prog_aff = uRasterLayer.Bounds.AffineCoefficients; //Now we create climate raster class - List<List<WindStressPRM.ClimateCell>> climWind = new List<List<WindStressPRM.ClimateCell>>(); int rowCountClim = clim5RasterLayer.DataSet.NumRows; int columnCountClim = clim5RasterLayer.DataSet.NumColumns; + WindStressPRM.Matrix<WindStressPRM.ClimateCell> climateMatrix = new WindStressPRM.Matrix<WindStressPRM.ClimateCell>(); + climateMatrix.Cells = new WindStressPRM.ClimateCell[rowCountClim, columnCountClim]; + climateMatrix.Size = new WindStressPRM.CellSize(clim5RasterLayer.DataSet.CellWidth, clim5RasterLayer.DataSet.CellHeight); + climateMatrix.AffineCoefficients = clim5RasterLayer.Bounds.AffineCoefficients; + // fill cells of climate matrix for (int i = 0; i < rowCountClim; i++) { - List<WindStressPRM.ClimateCell> climWindRow = new List<WindStressPRM.ClimateCell>(); for (int j = 0; j < columnCountClim; j++) { Coordinate dummyCellCoords = clim15RasterLayer.Bounds.CellCenter_ToProj(i,j); @@ -182,14 +183,9 @@ namespace MES_Wind clim15 = Double.NaN; } WindStressPRM.ClimateCell dummyClim = new WindStressPRM.ClimateCell(dummyClimCoords, clim5, clim10, clim15); - climWindRow.Add(dummyClim); + climateMatrix.Cells[i, j] = dummyClim; } - climWind.Add(climWindRow); - //clim_wind_row.Clear(); } - //Get cell info and affine transform coeff from climate rasters - WindStressPRM.CellSize climCellsize = new WindStressPRM.CellSize(clim5RasterLayer.DataSet.CellWidth, clim5RasterLayer.DataSet.CellHeight); - double[] climAffinecoeffs = clim5RasterLayer.Bounds.AffineCoefficients; // create PRM_line list to pass to PRM_wind from loaded line layer List<WindStressPRM.Powerline> powerlinesToPRM = new List<WindStressPRM.Powerline>(); foreach (IFeature feature in pwlineSet.Features) @@ -231,39 +227,34 @@ namespace MES_Wind MessageBox.Show("Some entities in Column IsSource of powerstation datatable are not strict ones or zeros"); } } - //casting stationtype - if (featureData["Sttype"].ToString().Trim().ToUpper() == "POLE") - { - dummystation.Stationtype = WindStressPRM.PowerStation.StationType.Pole; - } - else if (featureData["Sttype"].ToString().Trim().ToUpper() == "TRANS") - { - dummystation.Stationtype = WindStressPRM.PowerStation.StationType.Trans; - } - else if (featureData["Sttype"].ToString().Trim().ToUpper() == "ENDPOINT") - { - dummystation.Stationtype = WindStressPRM.PowerStation.StationType.Endstat; - } - else - { - throw new System.Exception("Point in powerstation layer has unrecognised type"); - } + //casting stationtype + if (featureData["Sttype"].ToString().Trim().ToUpper() == "POLE") + { + dummystation.Stationtype = WindStressPRM.PowerStation.StationType.Pole; + } + else if (featureData["Sttype"].ToString().Trim().ToUpper() == "TRANS") + { + dummystation.Stationtype = WindStressPRM.PowerStation.StationType.Trans; + } + else if (featureData["Sttype"].ToString().Trim().ToUpper() == "ENDPOINT") + { + dummystation.Stationtype = WindStressPRM.PowerStation.StationType.Endstat; + } + else + { + throw new System.Exception("Point in powerstation layer has unrecognised type"); + } IPoint featurepointcoords = featurepoint.BasicGeometry as IPoint; dummystation.Coordinate = DotspPointToPRM(featurepointcoords); powerpointsToPRM.Add(dummystation); - } //Create a PRM_wind class and add all the properties from above WindStressPRM.StressPowerChecker prmwind = new WindStressPRM.StressPowerChecker(); WindStressPRM.Input input = new WindStressPRM.Input(); input.PowerLines = powerlinesToPRM; input.PowerStations = powerpointsToPRM; - input.PrognosticCells = prognosticWind; - input.PrognosticCellSize = progcellsize; - input.PrognosticAffineCoefficients = prog_aff; - input.ClimateCells = climWind; - input.ClimateCellSize = climCellsize; - input.ClimateAffineCoefficients = climAffinecoeffs; + input.PrognosticCells = prognosticMatrix; + input.ClimateCells = climateMatrix; WindStressPRM.Output output = prmwind.CheckPower(input); // new FeatureSet for resulting disabled points IFeatureSet disabledPointSet = new FeatureSet(FeatureType.Point); @@ -310,17 +301,16 @@ namespace MES_Wind disabledLineLayer.Symbolizer = lineSymbol; disabledLineLayer.LegendText = "Disabled Lines"; + // new FeatureSet for resulting broken powerlines + //IFeatureSet brklineSet = new FeatureSet(FeatureType.Line); + //DataTable dt = pwlineSet.DataTable; + //IFeatureSet brk_info = new FeatureSet(FeatureType.Line); + //brk_info = main_layer_function(pwlLayer, pwlineSet, u_rasterLayer, v_rasterLayer, clim15_rasterLayer, clim10_rasterLayer, clim5_rasterLayer); - // new FeatureSet for resulting broken powerlines - //IFeatureSet brklineSet = new FeatureSet(FeatureType.Line); - //DataTable dt = pwlineSet.DataTable; - //IFeatureSet brk_info = new FeatureSet(FeatureType.Line); - //brk_info = main_layer_function(pwlLayer, pwlineSet, u_rasterLayer, v_rasterLayer, clim15_rasterLayer, clim10_rasterLayer, clim5_rasterLayer); - - //IMapLineLayer brk_info_layer = (MapLineLayer)map1.Layers.Add(brk_info); - //LineSymbolizer symbol = new LineSymbolizer(Color.Red, 3); - //brk_info_layer.Symbolizer = symbol; - //brk_info_layer.LegendText = "Broken powerlines"; + //IMapLineLayer brk_info_layer = (MapLineLayer)map1.Layers.Add(brk_info); + //LineSymbolizer symbol = new LineSymbolizer(Color.Red, 3); + //brk_info_layer.Symbolizer = symbol; + //brk_info_layer.LegendText = "Broken powerlines"; } } public class CheckPoint diff --git a/WindStressPRM/DTO/Input.cs b/WindStressPRM/DTO/Input.cs new file mode 100644 index 0000000000000000000000000000000000000000..d8f3193f900ff301d7482069be1dfd04b7a64f17 --- /dev/null +++ b/WindStressPRM/DTO/Input.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WindStressPRM +{ + /// <summary> + /// DTO for input + /// </summary> + public class Input + { + /// <summary> + /// prognistic raster info + /// массив прогностического ветра + /// </summary> + public Matrix<PrognosticCell> PrognosticCells { get; set; } + + /// <summary> + /// climate raster array + /// массив климатических полей скорости ветра заданной повторяемости + /// </summary> + public Matrix<ClimateCell> ClimateCells { get; set; } + + /// <summary> + /// lines list + /// список ЛЭП + /// </summary> + public List<Powerline> PowerLines { get; set; } + /// <summary> + /// stations/poles list + /// список точечных объектов - трансформаторных подстанций/столбов/понижающих(конечных) подстанций + /// </summary> + public List<PowerStation> PowerStations { get; set; } + /// <summary> + /// maximum distance for line segment, meters + /// максимальное расстояние между точками ЛЭП, для которых проверяется сломаются/несломаются под действием ветра + /// </summary> + public double DistThreshold + { + get + { + return 500; + } + } + } +} diff --git a/WindStressPRM/DTO/Output.cs b/WindStressPRM/DTO/Output.cs new file mode 100644 index 0000000000000000000000000000000000000000..62cb72ca4c17d497af768f7814101182ee2299e4 --- /dev/null +++ b/WindStressPRM/DTO/Output.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WindStressPRM +{ + /// <summary> + /// Output + /// </summary> + public class Output + { + /// <summary> + /// stations list without power + /// Список подстанций на которые не поступит питание в результате предсказанных поломок ЛЭП в сети + /// </summary> + public List<PowerStation> DisabledStations { get; set; } + /// <summary> + /// broken lines list + /// Список прогнозируемых сломанных ЛЭП в результате ветрового воздействия + /// </summary> + public List<Powerline> DisabledLines { get; set; } + } +} diff --git a/WindStressPRM/Objects/ClimateCell.cs b/WindStressPRM/Objects/ClimateCell.cs new file mode 100644 index 0000000000000000000000000000000000000000..446828d9c9917b757fca4e27dc5c77bc23311c6f --- /dev/null +++ b/WindStressPRM/Objects/ClimateCell.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WindStressPRM +{ + /// <summary> + /// Cell obj for climate wind regular data + /// Объект - ячейка полей ветра определенной повторяемости на 10м на регулярной сетке + /// </summary> + public class ClimateCell + { + /// <summary> + /// once-in-5-years frequency wind, m/s + /// скорость ветра повторяемости один раз в 5 лет, м/с + /// </summary> + public double Wind5; + /// <summary> + /// once-in-10-years frequency wind, m/s + /// скорость ветра повторяемости один раз в 10 лет, м/с + /// </summary> + public double Wind10 { get; private set; } + /// <summary> + /// once-in-15-years frequency wind, m/s + /// скорость ветра повторяемости один раз в 15 лет, м/с + /// </summary> + public double Wind15 { get; private set; } + /// <summary> + /// Cell center coordinate pair + /// Координаты центра ячейки + /// </summary> + public Coordinate Coordinate { get; private set; } + /// <summary> + /// designated constructor + /// </summary> + /// <param name="coord"></param> + /// <param name="w5"></param> + /// <param name="w10"></param> + /// <param name="w15"></param> + public ClimateCell(Coordinate coord, double w5, double w10, double w15) + { + this.Coordinate = coord; + this.Wind5 = w5; + this.Wind10 = w10; + this.Wind15 = w15; + if (!(this.CheckValue())) + { + throw new System.ArgumentException("Climate wind value is not correct"); + } + } + /// <summary> + /// Провекра валидности полей класса + /// </summary> + /// <returns></returns> + public bool CheckValue() + { + double w5 = Wind5; + double w10 = Wind10; + double w15 = Wind15; + if (Double.IsNaN(w5)) // if is Nan - zerofied it. + { + w5 = 0; + } + if (Double.IsNaN(w10)) + { + w10 = 0; + } + if (Double.IsNaN(w15)) + { + w15 = 0; + } + // ветер по модулю не должен превышать 70м/с + return Math.Abs(w5) < 70 && Math.Abs(w10) < 70 && Math.Abs(w15) < 70; + } + } +} diff --git a/WindStressPRM/Objects/PowerStation.cs b/WindStressPRM/Objects/PowerStation.cs new file mode 100644 index 0000000000000000000000000000000000000000..9a130623d433bb9201aeb316c70230ecc3e96b8d --- /dev/null +++ b/WindStressPRM/Objects/PowerStation.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WindStressPRM +{ + /// <summary> + /// powerstation/pole point class + /// класс для трансформаторных подстанций/столбов/понижающих(конечных) подстанций + /// </summary> + public class PowerStation + { + /// <summary> + /// unique id + /// уникальный идентификатор подстанции/столба + /// </summary> + public int Identifier { get; set; } + /// <summary> + /// Coordinates + /// </summary> + public Coordinate Coordinate { get; set; } + /// <summary> + /// station name field + /// название подстанции + /// </summary> + public string Name { get; set; } + /// <summary> + /// power, kW + /// мощность, кВ + /// </summary> + public int Power { get; set; } + /// <summary> + /// type of point - trans/pole/endpoint + /// тип станции - трансформаторная подстанция/столб/понижающая(конечная)подстанция + /// </summary> + public enum StationType + { + Pole, Trans, Endstat + }; + /// <summary> + /// тип подстанции + /// </summary> + public StationType Stationtype { get; set; } + /// <summary> + /// is point a source? + /// является ли подстаниция источником питания (в случае ТЭЦ или питания от внешних для рассматриваемой цепи ЛЭП) + /// </summary> + public bool IsSource { get; set; } + /// <summary> + /// power on switch + /// поступает (true) или нет (false) на подстанцию питание + /// </summary> + public bool IsON { get; set; } + /// <summary> + /// asigned powerlines list + /// список оканчивающихся/начинающихся на подстанции ЛЭП + /// </summary> + public IList<Powerline> LineList { get; set; } + public PowerStation() + { + //default constructor + } + /// <summary> + /// designated constructor + /// </summary> + /// <param name="crds"></param> + /// <param name="id"></param> + /// <param name="stname"></param> + /// <param name="stpower"></param> + /// <param name="sttype"></param> + /// <param name="issource"></param> + /// <param name="ison"></param> + public PowerStation(Coordinate crds, int id, string stname, int stpower, StationType sttype, bool issource) + { + this.Coordinate = crds; + this.Identifier = id; + this.Name = stname; + this.Power = stpower; + this.Stationtype = sttype; + this.IsSource = issource; + this.IsON = false; + } + public bool CheckValue() + { + bool checker = Identifier >= 0 && Power > 0 && Power < 1000; + return checker; + } + } +} diff --git a/WindStressPRM/Objects/Powerline.cs b/WindStressPRM/Objects/Powerline.cs new file mode 100644 index 0000000000000000000000000000000000000000..171a3ce2f0b17190427d4230618ce1e2f2cc1c4e --- /dev/null +++ b/WindStressPRM/Objects/Powerline.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WindStressPRM +{ + /// <summary> + /// power line object + /// объект - ЛЭП + /// </summary> + public class Powerline + { + /// <summary> + /// unique id + /// уникальный идентификатор + /// </summary> + public int Identifier { get; set; } + /// <summary> + /// year of construction + /// год постройки ЛЭП + /// </summary> + public int Year { get; set; } + /// <summary> + /// average height of cable span between two poles, meters + /// средняя высота пролета, м + /// </summary> + public double Height { get; set; } + /// <summary> + /// power kV for switches + /// Напряжение ЛЭП, кВ + /// </summary> + public int Power { get; set; } + /// <summary> + /// Line vertices coordinate list + /// список координат вершин ЛЭП как линейного объекта + /// </summary> + public IList<Coordinate> Coordinates { get; set; } + /// <summary> + /// assigned powerstation/pole + /// идентификатор соответсвующего конца/начала линии (столб, трансформаторная подстанция, понижающая подстанция) + /// </summary> + public int PointFromID { get; set; } + /// <summary> + /// assigned powerstation/pole + /// идентификатор соответсвующего конца/начала линии (столб, трансформаторная подстанция, понижающая подстанция) + /// </summary> + public int PointToID { get; set; } + /// <summary> + /// broken/not broken switch + /// сломана (true) или нет (false) линяя + /// </summary> + public bool IsBroken { get; set; } + /// <summary> + /// power on switch + /// получает (true) или нет (false) линия питание + /// </summary> + public bool IsON { get; set; } + + public Powerline() + { + //default constructor body + } + /// <summary> + /// designated constructor + /// </summary> + /// <param name="coord"></param> + /// <param name="id"></param> + /// <param name="yer"></param> + /// <param name="h"></param> + /// <param name="pw"></param> + /// <param name="isbrkn"></param> + /// <param name="ison"></param> + /// <param name="toID"></param> + /// <param name="fromID"></param> + public Powerline(IList<Coordinate> coordinates, int id, int year, double height, int power, int toID, int fromID) + { + this.Coordinates = coordinates; + this.Identifier = id; + this.Year = year; + this.Height = height; + this.Power = power; + this.IsBroken = false; + this.IsON = false; + this.PointFromID = fromID; + this.PointToID = toID; + if (!(this.CheckValue())) + { + throw new System.ArgumentException("Powerline object wasn't initialized correctly"); + } + } + /// <summary> + /// проверка валидности полей + /// </summary> + /// <returns></returns> + public bool CheckValue() + { + bool checker = + Identifier >= 0 && Math.Abs(Year - 1985) < 45 && + Math.Abs(Height - 15) < 15 && Power > 0 && Power < 1000 && + PointFromID >= 0 && PointToID >= 0; + return checker; + } + } +} diff --git a/WindStressPRM/Objects/PrognosticCell.cs b/WindStressPRM/Objects/PrognosticCell.cs new file mode 100644 index 0000000000000000000000000000000000000000..b1fb9923d46f7efad24c69c541994327f33b56c6 --- /dev/null +++ b/WindStressPRM/Objects/PrognosticCell.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WindStressPRM +{ + /// <summary> + /// Cell obj for regular prognostic wind field + /// Объект ячейки для поля прогностического ветра на высоте 10м на регулярной сетке + /// </summary> + public class PrognosticCell + { + /// <summary> + /// U - component of wind velocity, m/s + /// U - компонента скорости ветра, м/с + /// </summary> + public double VelocityX { get; private set; } + /// <summary> + /// V - component of wind velocity, m/s + /// V - компонента скорости ветра, м/с + /// </summary> + public double VelocityY { get; private set; } + /// <summary> + /// Cell center coordinates + /// Координаты центра ячейки + /// </summary> + public Coordinate Coordinate { get; private set; } + /// <summary> + /// designated constructor + /// </summary> + /// <param name="coord"> Coordinate pair</param> + /// <param name="vX"> U component</param> + /// <param name="vY"> V component</param> + public PrognosticCell(Coordinate coord, double vX, double vY) + { + this.Coordinate = coord; + this.VelocityX = vX; + this.VelocityY = vY; + if (!(this.CheckValue())) + { + throw new System.ArgumentException("Prognostic wind velocities are incorrect"); + } + } + /// <summary> + /// Проверка полей на валидность + /// </summary> + /// <returns></returns> + public bool CheckValue() + { + bool res1 = Double.IsNaN(VelocityX); + bool res2 = Double.IsNaN(VelocityY); + if (res1 != res2) + { + return false; + } + // пустые данные + if (res1 == res2 == true) + { + return true; + } + ///Скорость ветра на высоте 10м от поверхности на Земле не может превышать 70м/c + return Math.Abs(Math.Pow(VelocityX, 2) + Math.Pow(VelocityY, 2)) <= 4900; + } + } +} diff --git a/WindStressPRM/Utils/CellSize.cs b/WindStressPRM/Utils/CellSize.cs new file mode 100644 index 0000000000000000000000000000000000000000..0a76f253eb009c9424660d7492fb90c712b274ac --- /dev/null +++ b/WindStressPRM/Utils/CellSize.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WindStressPRM +{ + /// <summary> + /// Cell Sizes + /// Параметры ячейки (регулярной сетки) + /// </summary> + public class CellSize + { + /// <summary> + /// ширина ячейки (расстояние между соседними по широте центрами ячеек) + /// </summary> + public double Width { get; set; } + /// <summary> + /// высота ячейки (расстояние между соседними по долготе центрами ячеек) + /// </summary> + public double Height { get; set; } + /// <summary> + /// designated constructor + /// </summary> + /// <param name="wdh">Cell Width</param> + /// <param name="hgh">Cell Height</param> + public CellSize(double wdh, double hgh) + { + this.Width = wdh; + this.Height = hgh; + if (!(this.CheckValue())) + { + throw new System.ArgumentException("Cell width or height values are incorrect!"); + } + } + /// <summary> + /// Проверка валидности полей + /// </summary> + /// <returns></returns> + public bool CheckValue() + { + return Width > 0 && Height > 0; + } + } +} diff --git a/WindStressPRM/Utils/Coordinate.cs b/WindStressPRM/Utils/Coordinate.cs new file mode 100644 index 0000000000000000000000000000000000000000..07a764f9400cf185284a8d05a8a217f7909104a5 --- /dev/null +++ b/WindStressPRM/Utils/Coordinate.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; + +namespace WindStressPRM +{ + /// <summary> + /// Coordinate pair + /// </summary> + public class Coordinate + { + /// <summary> + /// easting coordinate + /// Координата по широте + /// </summary> + public double X { get; private set; } + /// <summary> + /// northing coordinate + /// Координата по долготе + /// </summary> + public double Y { get; private set; } + /// <summary> + /// designated constructor + /// Основной конструктор + /// </summary> + /// <param name="X"></param> + /// <param name="Y"></param> + public Coordinate(double X, double Y) + { + this.X = X; + this.Y = Y; + if (!(this.CheckValue())) + { + throw new System.ArgumentException("Passed coordinates are not valid!"); + } + } + /// <summary> + /// Проверка на валидность значений + /// </summary> + /// <returns></returns> + public bool CheckValue() + { + return !Double.IsNaN(X) && !Double.IsInfinity(X) && !Double.IsNaN(Y) && !Double.IsInfinity(Y); + } + } +} diff --git a/WindStressPRM/Utils/Index.cs b/WindStressPRM/Utils/Index.cs new file mode 100644 index 0000000000000000000000000000000000000000..e115fee98672a7dfb64489e98e1cde97f9d0ff58 --- /dev/null +++ b/WindStressPRM/Utils/Index.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace WindStressPRM +{ + /// <summary> + /// Index class for raster lists in list + /// Индекс-класс для растровых массивов + /// </summary> + public class Index + { + /// <summary> + /// Outer index + /// Внешний индекс + /// </summary> + public int Row { get; set; } + /// <summary> + /// Inner index + /// Внутренний индекс + /// </summary> + public int Col { get; set; } + /// <summary> + /// designated constructor + /// </summary> + /// <param name="Row">row index</param> + /// <param name="Col">column index</param> + public Index(int Row, int Col) + { + if (Row <= -1 || Col <= -1) + { + throw new System.ArgumentOutOfRangeException("Index must be initialized with nonegative integer value"); + } + this.Row = Row; + this.Col = Col; + } + } +} diff --git a/WindStressPRM/Utils/Matrix.cs b/WindStressPRM/Utils/Matrix.cs new file mode 100644 index 0000000000000000000000000000000000000000..494d4a4b5db6831b749067dfca39329300661b29 --- /dev/null +++ b/WindStressPRM/Utils/Matrix.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +namespace WindStressPRM +{ + /// <summary> + /// Generic Matrix of type T + /// </summary> + /// <typeparam name="T"></typeparam> + public class Matrix<T> + { + /// <summary> + /// AffineCoefficients for matrix from raster projection + /// </summary> + public double[] AffineCoefficients { get; set; } + /// <summary> + /// Size of cell. In meters + /// </summary> + public CellSize Size { get; set; } + /// <summary> + /// Cells Container + /// </summary> + public T[,] Cells { get; set; } + /// <summary> + /// Number of rows in matrix + /// </summary> + /// <returns></returns> + public int RowsCount() + { + return Cells.Rank > 0 ? Cells.GetLength(0) : 0; + } + /// <summary> + /// Number of columns + /// </summary> + /// <returns></returns> + public int ColumnCount() + { + return Cells.Rank > 1 ? Cells.GetLength(1) : 0; + } + } +} diff --git a/WindStressPRM/WindStressPRM.cs b/WindStressPRM/WindStressPRM.cs index 3e63db283dd50ae879315d121fbf089cec302ffe..cc8a808af31e9341249723e9a8c1667690d9915e 100644 --- a/WindStressPRM/WindStressPRM.cs +++ b/WindStressPRM/WindStressPRM.cs @@ -3,411 +3,6 @@ using System.Collections.Generic; namespace WindStressPRM { - /// <summary> - /// Index class for raster lists in list - /// Индекс-класс для растровых массивов - /// </summary> - public class Index - { - /// <summary> - /// Outer index - /// Внешний индекс - /// </summary> - public int Row { get; set; } - /// <summary> - /// Inner index - /// Внутренний индекс - /// </summary> - public int Col { get; set; } - /// <summary> - /// designated constructor - /// </summary> - /// <param name="Row">row index</param> - /// <param name="Col">column index</param> - public Index(int Row, int Col) - { - if (Row <= -1 || Col <= -1) { - throw new System.ArgumentOutOfRangeException("Index must be initialized with nonegative integer value"); - } - this.Row = Row; - this.Col = Col; - } - } - /// <summary> - /// Coordinate pair - /// </summary> - public class Coordinate - { - /// <summary> - /// easting coordinate - /// Координата по широте - /// </summary> - public double X { get; private set;} - /// <summary> - /// northing coordinate - /// Координата по долготе - /// </summary> - public double Y { get; private set; } - /// <summary> - /// designated constructor - /// Основной конструктор - /// </summary> - /// <param name="X"></param> - /// <param name="Y"></param> - public Coordinate(double X, double Y) - { - this.X = X; - this.Y = Y; - if (!(this.CheckValue())) - { - throw new System.ArgumentException("Passed coordinates are not valid!"); - } - } - /// <summary> - /// Проверка на валидность значений - /// </summary> - /// <returns></returns> - public bool CheckValue() - { - return !Double.IsNaN(X) && !Double.IsInfinity(X) && !Double.IsNaN(Y) && !Double.IsInfinity(Y); - } - } - /// <summary> - /// Cell obj for regular prognostic wind field - /// Объект ячейки для поля прогностического ветра на высоте 10м на регулярной сетке - /// </summary> - public class PrognosticCell - { - /// <summary> - /// U - component of wind velocity, m/s - /// U - компонента скорости ветра, м/с - /// </summary> - public double VelocityX { get; private set; } - /// <summary> - /// V - component of wind velocity, m/s - /// V - компонента скорости ветра, м/с - /// </summary> - public double VelocityY { get; private set; } - /// <summary> - /// Cell center coordinates - /// Координаты центра ячейки - /// </summary> - public Coordinate Coordinate { get; private set; } - /// <summary> - /// designated constructor - /// </summary> - /// <param name="coord"> Coordinate pair</param> - /// <param name="vX"> U component</param> - /// <param name="vY"> V component</param> - public PrognosticCell(Coordinate coord, double vX, double vY) - { - this.Coordinate = coord; - this.VelocityX = vX; - this.VelocityY = vY; - if (!(this.CheckValue())) - { - throw new System.ArgumentException("Prognostic wind velocities are incorrect"); - } - } - /// <summary> - /// Проверка полей на валидность - /// </summary> - /// <returns></returns> - public bool CheckValue() - { - bool res1 = Double.IsNaN(VelocityX); - bool res2 = Double.IsNaN(VelocityY); - if (res1 != res2) { - return false; - } - // пустые данные - if (res1) { - return true; - } - ///Скорость ветра на высоте 10м от поверхности на Земле не может превышать 70м/c - return Math.Abs(Math.Pow(VelocityX, 2) + Math.Pow(VelocityY, 2)) <= 4900; - } - } - /// <summary> - /// Cell obj for climate wind regular data - /// Объект - ячейка полей ветра определенной повторяемости на 10м на регулярной сетке - /// </summary> - public class ClimateCell - { - /// <summary> - /// once-in-5-years frequency wind, m/s - /// скорость ветра повторяемости один раз в 5 лет, м/с - /// </summary> - public double Wind5; - /// <summary> - /// once-in-10-years frequency wind, m/s - /// скорость ветра повторяемости один раз в 10 лет, м/с - /// </summary> - public double Wind10 { get; private set; } - /// <summary> - /// once-in-15-years frequency wind, m/s - /// скорость ветра повторяемости один раз в 15 лет, м/с - /// </summary> - public double Wind15 { get; private set; } - /// <summary> - /// Cell center coordinate pair - /// Координаты центра ячейки - /// </summary> - public Coordinate Coordinate { get; private set; } - /// <summary> - /// designated constructor - /// </summary> - /// <param name="coord"></param> - /// <param name="w5"></param> - /// <param name="w10"></param> - /// <param name="w15"></param> - public ClimateCell(Coordinate coord, double w5, double w10, double w15) - { - this.Coordinate = coord; - this.Wind5 = w5; - this.Wind10 = w10; - this.Wind15 = w15; - if (!(this.CheckValue())) - { - throw new System.ArgumentException("Climate wind value is not correct"); - } - } - /// <summary> - /// Провекра валидности полей класса - /// </summary> - /// <returns></returns> - public bool CheckValue() - { - bool c5 = Double.IsNaN(Wind5); - bool c10 = Double.IsNaN(Wind10); - bool c15 = Double.IsNaN(Wind15); - if (c5 != c10 || c5 != c15 || c5 != c10) { - return false; - } - if (c5) { - return true; - } - // ветер по модулю не должен превышать 70м/с - return Math.Abs(Wind5) < 70 && Math.Abs(Wind10) < 70 && Math.Abs(Wind15) < 70; - } - } - /// <summary> - /// Cell Size parameters - /// Параметры ячейки (регулярной сетки) - /// </summary> - public class CellSize - { - /// <summary> - /// ширина ячейки (расстояние между соседними по широте центрами ячеек) - /// </summary> - public double Width { get; set; } - /// <summary> - /// высота ячейки (расстояние между соседними по долготе центрами ячеек) - /// </summary> - public double Height { get; set; } - /// <summary> - /// designated constructor - /// </summary> - /// <param name="wdh">Cell Width</param> - /// <param name="hgh">Cell Height</param> - public CellSize(double wdh, double hgh) - { - this.Width = wdh; - this.Height = hgh; - if (!(this.CheckValue())) - { - throw new System.ArgumentException("Cell width or height values are incorrect!"); - } - } - /// <summary> - /// Проверка валидности полей - /// </summary> - /// <returns></returns> - public bool CheckValue() - { - return Width > 0 && Height > 0; - } - } - /// <summary> - /// power line object - /// объект - ЛЭП - /// </summary> - public class Powerline - { - /// <summary> - /// unique id - /// уникальный идентификатор - /// </summary> - public int Identifier { get; set; } - /// <summary> - /// year of construction - /// год постройки ЛЭП - /// </summary> - public int Year { get; set; } - /// <summary> - /// average height of cable span between two poles, meters - /// средняя высота пролета, м - /// </summary> - public double Height { get; set; } - /// <summary> - /// power kV for switches - /// Напряжение ЛЭП, кВ - /// </summary> - public int Power { get; set; } - /// <summary> - /// Line vertices coordinate list - /// список координат вершин ЛЭП как линейного объекта - /// </summary> - public IList<Coordinate> Coordinates { get; set; } - /// <summary> - /// assigned powerstation/pole - /// идентификатор соответсвующего конца/начала линии (столб, трансформаторная подстанция, понижающая подстанция) - /// </summary> - public int PointFromID { get; set; } - /// <summary> - /// assigned powerstation/pole - /// идентификатор соответсвующего конца/начала линии (столб, трансформаторная подстанция, понижающая подстанция) - /// </summary> - public int PointToID { get; set; } - /// <summary> - /// broken/not broken switch - /// сломана (true) или нет (false) линяя - /// </summary> - public bool IsBroken { get; set; } - /// <summary> - /// power on switch - /// получает (true) или нет (false) линия питание - /// </summary> - public bool IsON { get; set; } - - public Powerline() - { - //default constructor body - } - /// <summary> - /// designated constructor - /// </summary> - /// <param name="coord"></param> - /// <param name="id"></param> - /// <param name="yer"></param> - /// <param name="h"></param> - /// <param name="pw"></param> - /// <param name="isbrkn"></param> - /// <param name="ison"></param> - /// <param name="toID"></param> - /// <param name="fromID"></param> - public Powerline(IList<Coordinate> coordinates, int id, int year, double height, int power, int toID, int fromID) - { - this.Coordinates = coordinates; - this.Identifier = id; - this.Year = year; - this.Height = height; - this.Power = power; - this.IsBroken = false; - this.IsON = false; - this.PointFromID = fromID; - this.PointToID = toID; - if (!(this.CheckValue())) - { - throw new System.ArgumentException("Powerline object wasn't initialized correctly"); - } - } - /// <summary> - /// проверка валидности полей - /// </summary> - /// <returns></returns> - public bool CheckValue() - { - bool checker = - Identifier >= 0 && Math.Abs(Year - 1985) < 45 && - Math.Abs(Height - 15) < 15 && Power > 0 && Power < 1000 && - PointFromID >= 0 && PointToID >= 0; - return checker; - } - } - /// <summary> - /// powerstation/pole point class - /// класс для трансформаторных подстанций/столбов/понижающих(конечных) подстанций - /// </summary> - public class PowerStation - { - /// <summary> - /// unique id - /// уникальный идентификатор подстанции/столба - /// </summary> - public int Identifier { get; set; } - /// <summary> - /// Coordinates - /// </summary> - public Coordinate Coordinate { get; set; } - /// <summary> - /// station name field - /// название подстанции - /// </summary> - public string Name { get; set; } - /// <summary> - /// power, kW - /// мощность, кВ - /// </summary> - public int Power { get; set; } - /// <summary> - /// type of point - trans/pole/endpoint - /// тип станции - трансформаторная подстанция/столб/понижающая(конечная)подстанция - /// </summary> - public enum StationType - { - Pole, Trans, Endstat - }; - /// <summary> - /// тип подстанции - /// </summary> - public StationType Stationtype { get; set; } - /// <summary> - /// is point a source? - /// является ли подстаниция источником питания (в случае ТЭЦ или питания от внешних для рассматриваемой цепи ЛЭП) - /// </summary> - public bool IsSource { get; set; } - /// <summary> - /// power on switch - /// поступает (true) или нет (false) на подстанцию питание - /// </summary> - public bool IsON { get; set; } - /// <summary> - /// asigned powerlines list - /// список оканчивающихся/начинающихся на подстанции ЛЭП - /// </summary> - public IList<Powerline> LineList { get; set; } - public PowerStation() - { - //default constructor - } - /// <summary> - /// designated constructor - /// </summary> - /// <param name="crds"></param> - /// <param name="id"></param> - /// <param name="stname"></param> - /// <param name="stpower"></param> - /// <param name="sttype"></param> - /// <param name="issource"></param> - /// <param name="ison"></param> - public PowerStation(Coordinate crds, int id, string stname, int stpower, StationType sttype, bool issource) - { - this.Coordinate = crds; - this.Identifier = id; - this.Name = stname; - this.Power = stpower; - this.Stationtype = sttype; - this.IsSource = issource; - this.IsON = false; - } - public bool CheckValue() - { - bool checker = Identifier >=0 && Power >0 && Power < 1000; - return checker; - } - } - enum FunctionType { FunctionVelocityX = 0, @@ -417,81 +12,6 @@ namespace WindStressPRM FunctionClimate15 = 4 } /// <summary> - /// DTO for input - /// </summary> - public class Input - { - /// <summary> - /// prognistic raster info - /// массив прогностического ветра - /// </summary> - public List<List<PrognosticCell>> PrognosticCells { get; set; } - /// <summary> - /// prognostic raster cell info - /// параметры ячеек регулярной сетки прогностического ветра - /// </summary> - public CellSize PrognosticCellSize { get; set; } - /// <summary> - /// affine coefficients from prognostic raster projections - /// коэффициенты аффиного проеобразования из проекции массива прогностического ветра - /// </summary> - public double[] PrognosticAffineCoefficients { get; set; } - - /// <summary> - /// climate raster array - /// массив климатических полей скорости ветра заданной повторяемости - /// </summary> - public List<List<ClimateCell>> ClimateCells { get; set; } - /// <summary> - /// climate raster cell info - /// параметры ячеек регулярной сетки климатических полей скорости ветра заданной повторяемости - /// </summary> - public CellSize ClimateCellSize { get; set; } - /// <summary> - /// affine coefficients from climate raster projection - /// коэффициенты аффинного преобразования из проекции массива климатических полей скорости ветра заданной повторяемости - /// </summary> - public double[] ClimateAffineCoefficients { get; set; } - - /// <summary> - /// lines list - /// список ЛЭП - /// </summary> - public List<Powerline> PowerLines { get; set; } - /// <summary> - /// stations/poles list - /// список точечных объектов - трансформаторных подстанций/столбов/понижающих(конечных) подстанций - /// </summary> - public List<PowerStation> PowerStations { get; set; } - /// <summary> - /// maximum distance for line segment, meters - /// максимальное расстояние между точками ЛЭП, для которых проверяется сломаются/несломаются под действием ветра - /// </summary> - public double DistThreshold - { - get - { - return 500; - } - } - } - /// <summary> - /// Output - /// </summary> - public class Output - { - /// <summary> - /// stations list without power - /// Список подстанций на которые не поступит питание в результате предсказанных поломок ЛЭП в сети - /// </summary> - public List<PowerStation> DisabledStations { get; set; } - /// <summary> - /// broken lines list - /// Список прогнозируемых сломанных ЛЭП в результате ветрового воздействия - /// </summary> - public List<Powerline> DisabledLines { get; set; } - } - /// <summary> /// main calculations class /// </summary> public class StressPowerChecker @@ -523,14 +43,7 @@ namespace WindStressPRM //fill output Output output = new Output(); output.DisabledStations = new List<PowerStation>(); - output.DisabledLines = new List<Powerline>(); - foreach (Powerline line in input.PowerLines) - { - if (line.IsBroken) - { - output.DisabledLines.Add(line); - } - } + output.DisabledLines = prmBrokenLines; foreach (PowerStation powerStation in input.PowerStations) { //stations of type pole can be disabled if the line is broken @@ -720,6 +233,13 @@ namespace WindStressPRM double uwind = interpol(coords, FunctionType.FunctionVelocityX); double vwind = interpol(coords, FunctionType.FunctionVelocityY); double climwind = interpol(coords, climateType); + if (Double.IsNaN(uwind) || Double.IsNaN(vwind) || Double.IsNaN(climwind)) + { + // interpolation fail. we can't say everything about here + // discussion: also we can save these points for detail analysis + res = false; + continue; + } double umod = Math.Sqrt(uwind * uwind + vwind * vwind); ; double angleline = Math.Atan2((coord2.Y - coord1.Y), (coord2.X - coord1.X)); double anglewind = Math.Atan2(vwind, uwind) - angleline; @@ -765,13 +285,13 @@ namespace WindStressPRM case FunctionType.FunctionVelocityX: case FunctionType.FunctionVelocityY: { - return Input.PrognosticAffineCoefficients; + return Input.PrognosticCells.AffineCoefficients; } case FunctionType.FunctionClimate5: case FunctionType.FunctionClimate10: case FunctionType.FunctionClimate15: { - return Input.ClimateAffineCoefficients; + return Input.ClimateCells.AffineCoefficients; } default: break; @@ -821,13 +341,13 @@ namespace WindStressPRM case FunctionType.FunctionVelocityX: case FunctionType.FunctionVelocityY: { - return Input.PrognosticCells[index.Row][index.Col].Coordinate; + return Input.PrognosticCells.Cells[index.Row, index.Col].Coordinate; } case FunctionType.FunctionClimate5: case FunctionType.FunctionClimate10: case FunctionType.FunctionClimate15: { - return Input.ClimateCells[index.Row][index.Col].Coordinate; + return Input.ClimateCells.Cells[index.Row, index.Col].Coordinate; } default: break; @@ -842,13 +362,13 @@ namespace WindStressPRM case FunctionType.FunctionVelocityX: case FunctionType.FunctionVelocityY: { - return forRows ? Input.PrognosticCells.Count : Input.PrognosticCells[0].Count; + return forRows ? Input.PrognosticCells.RowsCount() : Input.PrognosticCells.ColumnCount(); } case FunctionType.FunctionClimate5: case FunctionType.FunctionClimate10: case FunctionType.FunctionClimate15: { - return forRows ? Input.ClimateCells.Count : Input.ClimateCells[0].Count; + return forRows ? Input.ClimateCells.RowsCount() : Input.ClimateCells.ColumnCount(); } default: break; @@ -862,23 +382,23 @@ namespace WindStressPRM { case FunctionType.FunctionVelocityX: { - return Input.PrognosticCells[index.Row][index.Col].VelocityX; + return Input.PrognosticCells.Cells[index.Row, index.Col].VelocityX; } case FunctionType.FunctionVelocityY: { - return Input.PrognosticCells[index.Row][index.Col].VelocityY; + return Input.PrognosticCells.Cells[index.Row, index.Col].VelocityY; } case FunctionType.FunctionClimate5: { - return Input.ClimateCells[index.Row][index.Col].Wind5; + return Input.ClimateCells.Cells[index.Row, index.Col].Wind5; } case FunctionType.FunctionClimate10: { - return Input.ClimateCells[index.Row][index.Col].Wind10; + return Input.ClimateCells.Cells[index.Row, index.Col].Wind10; } case FunctionType.FunctionClimate15: { - return Input.ClimateCells[index.Row][index.Col].Wind15; + return Input.ClimateCells.Cells[index.Row, index.Col].Wind15; } default: break; @@ -893,13 +413,13 @@ namespace WindStressPRM case FunctionType.FunctionVelocityX: case FunctionType.FunctionVelocityY: { - return Input.PrognosticCellSize; + return Input.PrognosticCells.Size; } case FunctionType.FunctionClimate5: case FunctionType.FunctionClimate10: case FunctionType.FunctionClimate15: { - return Input.ClimateCellSize; + return Input.ClimateCells.Size; } default: break; @@ -954,7 +474,8 @@ namespace WindStressPRM // tests indicates that value at test-cell is missed. if (testTopRight && testTopLeft && testBotLeft && testBotRight) { - throw new Exception("Current value in such a bad place, you need to fill these place with raster values"); + // Current value in such a bad place, you need to fill these place with raster values + return Double.NaN; } int count = 0; if (testBotLeft) diff --git a/WindStressPRM/WindStressPRM.csproj b/WindStressPRM/WindStressPRM.csproj index 91e4f655339764de6896b998653193f5308d382e..81b36dad75ce37b388e1a836c5637ec045fe49f2 100644 --- a/WindStressPRM/WindStressPRM.csproj +++ b/WindStressPRM/WindStressPRM.csproj @@ -8,8 +8,8 @@ <ProjectGuid>{599B5E9B-293A-4866-A50F-6BB7DC36A81C}</ProjectGuid> <OutputType>Library</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>PRMLibrary</RootNamespace> - <AssemblyName>PRMLibrary</AssemblyName> + <RootNamespace>WindStressPRM</RootNamespace> + <AssemblyName>WindStressPRM</AssemblyName> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> </PropertyGroup> @@ -35,6 +35,16 @@ <Reference Include="Microsoft.CSharp" /> </ItemGroup> <ItemGroup> + <Compile Include="DTO\Input.cs" /> + <Compile Include="DTO\Output.cs" /> + <Compile Include="Objects\ClimateCell.cs" /> + <Compile Include="Utils\CellSize.cs" /> + <Compile Include="Utils\Coordinate.cs" /> + <Compile Include="Utils\Index.cs" /> + <Compile Include="Utils\Matrix.cs" /> + <Compile Include="Objects\Powerline.cs" /> + <Compile Include="Objects\PowerStation.cs" /> + <Compile Include="Objects\PrognosticCell.cs" /> <Compile Include="WindStressPRM.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup>