Newer
Older
using System;
using System.Collections.Generic;
/// <summary>
/// Index class for raster lists in list

Debolskiy Andrey
committed
/// Индекс-класс для растровых массивов

Антон Кудряшов
committed
{

Debolskiy Andrey
committed
/// Outer index
/// Внешний индекс
/// <summary>
/// Inner index

Debolskiy Andrey
committed
/// Внутренний индекс
/// <summary>
/// designated constructor
/// </summary>
/// <param name="Row">row index</param>
/// <param name="Col">column index</param>

Антон Кудряшов
committed
{
throw new System.ArgumentOutOfRangeException("Index must be initialized with nonegative integer value");

Антон Кудряшов
committed
this.Row = Row;
this.Col = Col;
}
}
/// <summary>
/// Coordinate pair
/// </summary>
/// <summary>
/// easting coordinate

Debolskiy Andrey
committed
/// Координата по широте
/// <summary>
/// northing coordinate

Debolskiy Andrey
committed
/// Координата по долготе
/// <summary>
/// designated constructor

Debolskiy Andrey
committed
/// Основной конструктор
/// </summary>
/// <param name="X"></param>
/// <param name="Y"></param>

Debolskiy Andrey
committed
if (!(this.CheckValue()))

Debolskiy Andrey
committed
throw new System.ArgumentException("Passed coordinates are not valid!");
}
}

Debolskiy Andrey
committed
/// <summary>
/// Проверка на валидность значений
/// </summary>
/// <returns></returns>

Debolskiy Andrey
committed
public bool CheckValue()
{
return !Double.IsNaN(X) && !Double.IsInfinity(X) && !Double.IsNaN(Y) && !Double.IsInfinity(Y);
/// <summary>
/// Cell obj for regular prognostic wind field

Debolskiy Andrey
committed
/// Объект ячейки для поля прогностического ветра на высоте 10м на регулярной сетке

Debolskiy Andrey
committed
/// U - component of wind velocity, m/s
/// U - компонента скорости ветра, м/с

Debolskiy Andrey
committed
/// V - component of wind velocity, m/s
/// V - компонента скорости ветра, м/с
/// <summary>
/// Cell center coordinates

Debolskiy Andrey
committed
/// Координаты центра ячейки
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;

Debolskiy Andrey
committed
if (!(this.CheckValue()))
{
throw new System.ArgumentException("Prognostic wind velocities are incorrect");
}
}

Debolskiy Andrey
committed
/// <summary>
/// Проверка полей на валидность
/// </summary>
/// <returns></returns>

Debolskiy Andrey
committed
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

Debolskiy Andrey
committed
/// Объект - ячейка полей ветра определенной повторяемости на 10м на регулярной сетке

Debolskiy Andrey
committed
/// once-in-5-years frequency wind, m/s
/// скорость ветра повторяемости один раз в 5 лет, м/с

Debolskiy Andrey
committed
/// once-in-10-years frequency wind, m/s
/// скорость ветра повторяемости один раз в 10 лет, м/с

Debolskiy Andrey
committed
/// once-in-15-years frequency wind, m/s
/// скорость ветра повторяемости один раз в 15 лет, м/с
/// <summary>
/// Cell center coordinate pair

Debolskiy Andrey
committed
/// Координаты центра ячейки
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;

Debolskiy Andrey
committed
if (!(this.CheckValue()))
{
throw new System.ArgumentException("Climate wind value is not correct");
}
}

Debolskiy Andrey
committed
/// <summary>
/// Провекра валидности полей класса
/// </summary>
/// <returns></returns>

Debolskiy Andrey
committed
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;
// ветер по модулю не должен превышать 70м/с
return Math.Abs(Wind5) < 70 && Math.Abs(Wind10) < 70 && Math.Abs(Wind15) < 70;
/// <summary>
/// Cell Size parameters

Debolskiy Andrey
committed
/// Параметры ячейки (регулярной сетки)

Debolskiy Andrey
committed
/// <summary>
/// ширина ячейки (расстояние между соседними по широте центрами ячеек)
/// </summary>

Debolskiy Andrey
committed
/// <summary>
/// высота ячейки (расстояние между соседними по долготе центрами ячеек)
/// </summary>

Debolskiy Andrey
committed
/// <summary>
/// designated constructor
/// </summary>
/// <param name="wdh">Cell Width</param>
/// <param name="hgh">Cell Height</param>
public CellSize(double wdh, double hgh)

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
if (!(this.CheckValue()))
{
throw new System.ArgumentException("Cell width or height values are incorrect!");
}
}

Debolskiy Andrey
committed
/// <summary>
/// Проверка валидности полей
/// </summary>
/// <returns></returns>

Debolskiy Andrey
committed
public bool CheckValue()
{

Debolskiy Andrey
committed
}
/// <summary>
/// power line object

Debolskiy Andrey
committed
/// объект - ЛЭП
/// <summary>
/// unique id

Debolskiy Andrey
committed
/// уникальный идентификатор
/// <summary>
/// year of construction

Debolskiy Andrey
committed
/// год постройки ЛЭП

Debolskiy Andrey
committed
/// average height of cable span between two poles, meters
/// средняя высота пролета, м
/// power kV for switches
/// Напряжение ЛЭП, кВ
/// <summary>
/// Line vertices coordinate list

Debolskiy Andrey
committed
/// список координат вершин ЛЭП как линейного объекта
/// <summary>
/// assigned powerstation/pole

Debolskiy Andrey
committed
/// идентификатор соответсвующего конца/начала линии (столб, трансформаторная подстанция, понижающая подстанция)
/// <summary>
/// assigned powerstation/pole

Debolskiy Andrey
committed
/// идентификатор соответсвующего конца/начала линии (столб, трансформаторная подстанция, понижающая подстанция)
/// <summary>
/// broken/not broken switch

Debolskiy Andrey
committed
/// сломана (true) или нет (false) линяя
/// <summary>
/// power on switch

Debolskiy Andrey
committed
/// получает (true) или нет (false) линия питание

Debolskiy Andrey
committed
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;

Debolskiy Andrey
committed
if (!(this.CheckValue()))
{
throw new System.ArgumentException("Powerline object wasn't initialized correctly");
}

Debolskiy Andrey
committed
/// проверка валидности полей

Debolskiy Andrey
committed
/// <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;

Debolskiy Andrey
committed
return checker;
}
/// <summary>
/// powerstation/pole point class

Debolskiy Andrey
committed
/// класс для трансформаторных подстанций/столбов/понижающих(конечных) подстанций
/// <summary>
/// unique id

Debolskiy Andrey
committed
/// уникальный идентификатор подстанции/столба
/// <summary>
/// Coordinates
/// </summary>
/// <summary>
/// station name field

Debolskiy Andrey
committed
/// название подстанции
/// <summary>
/// power, kW
/// мощность, кВ
/// <summary>
/// type of point - trans/pole/endpoint

Debolskiy Andrey
committed
/// тип станции - трансформаторная подстанция/столб/понижающая(конечная)подстанция
public enum StationType
{
Pole, Trans, Endstat
};

Debolskiy Andrey
committed
/// <summary>
/// тип подстанции
/// </summary>
/// <summary>
/// is point a source?

Debolskiy Andrey
committed
/// является ли подстаниция источником питания (в случае ТЭЦ или питания от внешних для рассматриваемой цепи ЛЭП)
/// <summary>
/// power on switch

Debolskiy Andrey
committed
/// поступает (true) или нет (false) на подстанцию питание
/// <summary>
/// asigned powerlines list

Debolskiy Andrey
committed
/// список оканчивающихся/начинающихся на подстанции ЛЭП

Debolskiy Andrey
committed
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)

Debolskiy Andrey
committed
{
this.Coordinate = crds;
this.Identifier = id;
this.Name = stname;
this.Power = stpower;
this.Stationtype = sttype;
this.IsSource = issource;
this.IsON = false;

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
public bool CheckValue()
{
bool checker = Identifier >=0 && Power >0 && Power < 1000;

Debolskiy Andrey
committed
return checker;
}

Антон Кудряшов
committed
enum FunctionType
{
FunctionVelocityX = 0,
FunctionVelocityY = 1,
FunctionClimate5 = 2,
FunctionClimate10 = 3,
FunctionClimate15 = 4

Антон Кудряшов
committed
}
/// <summary>
/// DTO for input
/// </summary>
/// <summary>
/// prognistic raster info

Debolskiy Andrey
committed
/// массив прогностического ветра
public List<List<PrognosticCell>> PrognosticCells { get; set; }
/// <summary>
/// prognostic raster cell info

Debolskiy Andrey
committed
/// параметры ячеек регулярной сетки прогностического ветра
/// <summary>
/// affine coefficients from prognostic raster projections

Debolskiy Andrey
committed
/// коэффициенты аффиного проеобразования из проекции массива прогностического ветра
public double[] PrognosticAffineCoefficients { get; set; }

Debolskiy Andrey
committed
/// <summary>
/// climate raster array

Debolskiy Andrey
committed
/// массив климатических полей скорости ветра заданной повторяемости
public List<List<ClimateCell>> ClimateCells { get; set; }
/// <summary>
/// climate raster cell info

Debolskiy Andrey
committed
/// параметры ячеек регулярной сетки климатических полей скорости ветра заданной повторяемости
/// <summary>
/// affine coefficients from climate raster projection

Debolskiy Andrey
committed
/// коэффициенты аффинного преобразования из проекции массива климатических полей скорости ветра заданной повторяемости
/// <summary>
/// lines list

Debolskiy Andrey
committed
/// список ЛЭП
/// <summary>
/// stations/poles list

Debolskiy Andrey
committed
/// список точечных объектов - трансформаторных подстанций/столбов/понижающих(конечных) подстанций

Debolskiy Andrey
committed
/// максимальное расстояние между точками ЛЭП, для которых проверяется сломаются/несломаются под действием ветра
/// <summary>
/// stations list without power

Debolskiy Andrey
committed
/// Список подстанций на которые не поступит питание в результате предсказанных поломок ЛЭП в сети
public List<PowerStation> DisabledStations { get; set; }
/// <summary>
/// broken lines list

Debolskiy Andrey
committed
/// Список прогнозируемых сломанных ЛЭП в результате ветрового воздействия
/// <summary>
/// main calculations class
/// </summary>
public class StressPowerChecker
/// <summary>
/// Input Data
/// </summary>
/// <summary>
/// Main function for power graph algorithm

Debolskiy Andrey
committed
/// Основая функция для вычисления распределения питания по графу ЛЭП-подстанции

Debolskiy Andrey
committed
{
List<WindStressPRM.Powerline> prmBrokenLines = brokenPowerLinesAfterCheck();

Debolskiy Andrey
committed
//get the graph

Debolskiy Andrey
committed
//start from source points

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
}
output.DisabledStations = new List<PowerStation>();
output.DisabledLines = new List<Powerline>();
foreach (Powerline line in input.PowerLines)

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
}
foreach (PowerStation powerStation in input.PowerStations)

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
//stations of type pole can be disabled if the line is broken
if (!powerStation.IsON && !(powerStation.Stationtype == PowerStation.StationType.Pole))

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
}
/// <summary>
/// recursive search function for power graph
/// </summary>
/// <param name="sourcepoint"> powered station to search next powered station from</param>
private void CheckPowerPointsForStation(PowerStation sourcepoint)

Debolskiy Andrey
committed
{
throw new Exception("CheckPowerPointsForStation is called from disabled sourcepoint");

Debolskiy Andrey
committed
}
// if the point is not a pole - i.e. we know
// it can redistribute power within connected lines
// we turn it ON if any of the connected lines are powered

Debolskiy Andrey
committed
{
line.IsON = true;
foreach (PowerStation powerStation in Input.PowerStations)

Debolskiy Andrey
committed
{
if (powerStation.Identifier != sourcepoint.Identifier && (powerStation.Identifier == line.PointFromID || powerStation.Identifier == line.PointToID))

Debolskiy Andrey
committed
{
if (!(sourcepoint.Stationtype == PowerStation.StationType.Pole)) {
powerStation.IsON = true;
CheckPowerPointsForStation(powerStation);

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
// if line is a pole we have to check if it's actually able to
// get electricity to other points i.e. no connected lines are broken

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
{
CheckPowerPointsForStation(powerStation);

Debolskiy Andrey
committed
}
}
}
}
}
//else we have broken line or already switched ON powerpoint
}

Debolskiy Andrey
committed
}
/// <summary>
/// preparing powerstations and lists of lines for them to get a graph-like structure
/// </summary>

Debolskiy Andrey
committed
{
//First we make sure that all the sources are ON
//and all non sources are OFF
foreach (PowerStation powerStation in Input.PowerStations)

Debolskiy Andrey
committed
{
if (powerStation.IsSource == true) {
powerStation.IsON = true;

Debolskiy Andrey
committed
// for each power station we create a list of powerlines it is attached to
List<Powerline> lines = new List<Powerline>();

Debolskiy Andrey
committed
{
//we also switch OFF all lines
line.IsON = false;
if (line.PointFromID == powerStation.Identifier || line.PointToID == powerStation.Identifier) {

Debolskiy Andrey
committed
lines.Add(line);
}
}

Debolskiy Andrey
committed
}
}
/// <summary>
/// function to chec if powerline is broken by wind
/// </summary>
/// <returns>list of broken powerlines</returns>
private List<Powerline> brokenPowerLinesAfterCheck()

Debolskiy Andrey
committed
{
List<Powerline> brokenLines = new List<Powerline>();
// actually there are curves in powerLines
List<bool> checkList = new List<bool>();
// cycle throw all points in line
for (int i = 1; i < points.Count; i++)
{
double x1 = points[i - 1].X;
double y1 = points[i - 1].Y;
double x2 = points[i].X;
double y2 = points[i].Y;
bool result = linearLineIsBroken(points[i - 1], points[i], powerCurve.Height, powerCurve.Power);
checkList.Add(result);
}
foreach (bool chkpnt in checkList)
{
if (chkpnt == true)
{

Debolskiy Andrey
committed
{
brokenLines.Add(powerCurve);

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
/// <summary>
/// Divides the line between two vertices if needed
/// depending on dist_threshold
/// and checks if line is broken by wind in any of midpoints
/// </summary>
/// <param name="coord1">first vertice coordinate</param>
/// <param name="coord2">second vertice </param>
/// <param name="heightLine">height</param>
/// <param name="power">power for climatology switches</param>
/// <returns>true if line is broken false otherwise</returns>
private bool linearLineIsBroken(Coordinate coord1, Coordinate coord2, double heightLine, int power)
{
double distance = Math.Sqrt((coord2.X - coord1.X) * (coord2.X - coord1.X) + (coord2.Y - coord1.Y) * (coord2.Y - coord1.Y));
List<Coordinate> pointlist = new List<Coordinate>();
Coordinate midpoint = new Coordinate(0, 0);
int distpropI = Convert.ToInt32(distpropD);
if (distpropI > 1)
{
double constXdiff = (coord2.X - coord1.X) / distpropI;
double constYdiff = (coord2.Y - coord1.Y) / distpropI;
Coordinate subCoord1 = new Coordinate(coord1.X, coord1.Y);
Coordinate subCoord2 = new Coordinate(coord1.X + constXdiff, coord1.Y + constXdiff);
for (int j = 0; j < distpropI; j++)
{
// move to next center, at the next interval
subCoord1 = new Coordinate(subCoord2.X, subCoord2.Y);
subCoord2 = new Coordinate(subCoord1.X + constXdiff, subCoord1.Y + constYdiff);
midpoint = new Coordinate((subCoord1.X + subCoord2.X) / 2, (subCoord1.Y + subCoord2.Y) / 2);
pointlist.Add(midpoint);
midpoint = new Coordinate( (coord1.X + coord2.X) / 2, (coord1.Y + coord2.Y) / 2);

Debolskiy Andrey
committed
pointlist.Add(midpoint);
}
FunctionType climateType;
if (power > 5 && power < 330)
{
climateType = FunctionType.FunctionClimate10;
}
else
{
if (power <= 5) {
climateType = FunctionType.FunctionClimate5;

Debolskiy Andrey
committed
}
else {
climateType = FunctionType.FunctionClimate15;

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
List<bool> checkbool = new List<bool>();
foreach (Coordinate coords in pointlist)

Debolskiy Andrey
committed
{
bool res = false;
double uwind = interpol(coords, FunctionType.FunctionVelocityX);
double vwind = interpol(coords, FunctionType.FunctionVelocityY);

Антон Кудряшов
committed
double climwind = interpol(coords, climateType);
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;
double sinwind = Math.Sin(anglewind);
double C_height = 1.0;
if (umod < 20)
{ //wind is too low

Debolskiy Andrey
committed
res = false;
}
else
{ // calculate prognostic and threshold windstress
double p1 = -0.00078501;
double p2 = 0.13431;
double p3 = -2.11112;
double p4 = 19.548;
double qpr = p1 * umod * umod * umod + p2 * umod * umod + p3 * umod + p4;
double qcl = p1 * climwind * climwind * climwind + p2 * climwind * climwind + p3 * climwind + p4;
double Ppr = qpr * C_height * sinwind * sinwind;
double Pcl = qcl * C_height * 1.0;
if (Ppr >= Pcl)
{
// here line is broken

Debolskiy Andrey
committed
checkbool.Add(res);
}
bool result = false;
foreach (bool lastcheck in checkbool)
{

Debolskiy Andrey
committed
return result;
private double[] affineCoefficients(FunctionType functionType)

Антон Кудряшов
committed
{
switch (functionType)
{
case FunctionType.FunctionVelocityX:
case FunctionType.FunctionVelocityY:

Антон Кудряшов
committed
{

Антон Кудряшов
committed
}
case FunctionType.FunctionClimate5:
case FunctionType.FunctionClimate10:
case FunctionType.FunctionClimate15:

Антон Кудряшов
committed
{

Антон Кудряшов
committed
}
default:
break;
}
return null;
}
// Taken from DotSpatial https://github.com/ViceIce/DotSpatial/blob/22c156c7646b1595d88d2523c066a9c6ab4d3a53/DotSpatial.Data/RasterBoundsExt.cs
// RasterBoundsExt.cs. Define AffineCoefficients like this.
private Index projectionToCell(Coordinate coordinate, FunctionType functionType)

Антон Кудряшов
committed
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
{
double[] c = affineCoefficients(functionType);
double rw, cl;
if (c[2] == 0 && c[4] == 0)
{
// If we don't have skew terms, then the x and y terms are independent.
// also both of the other tests will have divide by zero errors and fail.
cl = (coordinate.X - c[0]) / c[1];
rw = (coordinate.Y - c[3]) / c[5];
}
else if (c[2] != 0)
{
// this equation will have divide by zero if c[2] is zero, but works if c[4] is zero
double div = (c[5] * c[1]) / c[2] - c[4];
cl = (c[3] + (c[5] * coordinate.X) / c[2] - (c[5] * c[0]) / c[2] - coordinate.Y) / div;
rw = (coordinate.X - c[0] - c[1] * cl) / c[2];
}
else
{
double div = (c[4] * c[2] / c[1] - c[5]);
rw = (c[3] + c[4] * coordinate.X / c[1] - c[4] * c[0] / c[1] - coordinate.Y) / div;
cl = (coordinate.X - c[2] * rw - c[0]) / c[1];
}
int iRow = (int)Math.Round(rw);
int iCol = (int)Math.Round(cl);
if (iRow < 0 || iCol < 0 || iRow >= countInList(functionType, true) || iCol >= countInList(functionType, false))
{
throw new Exception("projectionToCell method trying to find uncorrect index");

Антон Кудряшов
committed
}

Антон Кудряшов
committed
}
private Coordinate cellToProjection(Index index, FunctionType functionType)

Антон Кудряшов
committed
{
switch (functionType)
{
case FunctionType.FunctionVelocityX:
case FunctionType.FunctionVelocityY:

Антон Кудряшов
committed
{
return Input.PrognosticCells[index.Row][index.Col].Coordinate;

Антон Кудряшов
committed
}
case FunctionType.FunctionClimate5:
case FunctionType.FunctionClimate10:
case FunctionType.FunctionClimate15:

Антон Кудряшов
committed
{
return Input.ClimateCells[index.Row][index.Col].Coordinate;

Антон Кудряшов
committed
}
default:
break;
}
return null;
}
int countInList(FunctionType functionType, bool forRows)

Антон Кудряшов
committed
{
switch (functionType)
{
case FunctionType.FunctionVelocityX:
case FunctionType.FunctionVelocityY:

Антон Кудряшов
committed
{
return forRows ? Input.PrognosticCells.Count : Input.PrognosticCells[0].Count;

Антон Кудряшов
committed
}
case FunctionType.FunctionClimate5:
case FunctionType.FunctionClimate10:
case FunctionType.FunctionClimate15:

Антон Кудряшов
committed
{
return forRows ? Input.ClimateCells.Count : Input.ClimateCells[0].Count;

Антон Кудряшов
committed
}
default:
break;
}
return 0;
}
private double valueForFunction(FunctionType functionType, Index index)

Антон Кудряшов
committed
{
switch (functionType)
{

Антон Кудряшов
committed
{
return Input.PrognosticCells[index.Row][index.Col].VelocityX;

Антон Кудряшов
committed
}

Антон Кудряшов
committed
{
return Input.PrognosticCells[index.Row][index.Col].VelocityY;

Антон Кудряшов
committed
}

Антон Кудряшов
committed
{

Антон Кудряшов
committed
}

Антон Кудряшов
committed
{

Антон Кудряшов
committed
}

Антон Кудряшов
committed
{

Антон Кудряшов
committed
}
default:
break;
}
return 0;
}
private CellSize cellSizeForFunction(FunctionType functionType)

Антон Кудряшов
committed
{
switch (functionType)
{
case FunctionType.FunctionVelocityX:
case FunctionType.FunctionVelocityY:

Антон Кудряшов
committed
{

Антон Кудряшов
committed
}
case FunctionType.FunctionClimate5:
case FunctionType.FunctionClimate10:
case FunctionType.FunctionClimate15:

Антон Кудряшов
committed
{

Антон Кудряшов
committed
}
default:
break;
}
throw new Exception("There is no cell size");
}
private double interpol(Coordinate coords, FunctionType functionType)

Антон Кудряшов
committed
{
// select directions for projections
const bool normalX = true;// true - East, false West
const bool normalY = false;// true - North, false South
Index rc = projectionToCell(coords, functionType);
Coordinate center = cellToProjection(rc, functionType);

Антон Кудряшов
committed
double xDiff = coords.X - center.X;
double yDiff = coords.Y - center.Y;
//calculate second index
int row2, col2;
if ((xDiff >= 0 && normalX) || (!normalX && xDiff < 0))
{
row2 = rc.Row >= countInList(functionType, true) - 1 ? rc.Row - 1 : rc.Row + 1;
}
else
{
row2 = rc.Row > 0 ? rc.Row - 1 : rc.Row + 1;
}
if ((yDiff >= 0 && normalY) || (!normalY && yDiff < 0))
{
col2 = rc.Col >= countInList(functionType, false) - 1 ? rc.Col - 1 : rc.Col + 1;
}
else
{
col2 = rc.Col > 0 ? rc.Col - 1 : rc.Col + 1;
}
// indexes and values at bounds
Index rcBotLeft = new Index(Math.Min(row2, rc.Row), Math.Min(col2, rc.Col));
Index rcBotRight = new Index(Math.Max(row2, rc.Row), Math.Min(col2, rc.Col));
Index rcTopLeft = new Index(Math.Min(row2, rc.Row), Math.Max(col2, rc.Col));
Index rcTopRight = new Index(Math.Max(row2, rc.Row), Math.Max(col2, rc.Col));

Антон Кудряшов
committed
double valBotLeft = valueForFunction(functionType, rcBotLeft);
double valBotRight = valueForFunction(functionType, rcBotRight);
double valTopLeft = valueForFunction(functionType, rcTopLeft);
double valTopRight = valueForFunction(functionType, rcTopRight);
Coordinate origin = cellToProjection(rcBotLeft, functionType);
bool testBotLeft = Double.IsNaN(valBotLeft);
bool testBotRight = Double.IsNaN(valBotRight);
bool testTopLeft = Double.IsNaN(valTopLeft);
bool testTopRight = Double.IsNaN(valTopRight);
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
if (testBotLeft || testBotRight || testTopLeft || testTopRight)
{
// 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");
}
int count = 0;
if (testBotLeft)
{
valBotLeft = 0;
count++;
}
if (testBotRight)
{
valBotRight = 0;
count++;
}
if (testTopLeft)
{
valTopLeft = 0;
count++;
}
if (testTopRight)
{
valTopRight = 0;
count++;
}
//of course there is count not 0;
if (count == 0) {
throw new Exception("Interpolation Logic Error");
}
double average = (valTopLeft + valTopRight + valBotLeft + valBotRight)/count;
if (testBotLeft)
{
valBotLeft = average;
}
if (testBotRight)
{
valBotRight = average;
}
if (testTopLeft)
{
valTopLeft = average;
}
if (testTopRight)
{
valTopRight = average;
}