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
/// Внешний индекс

Антон Кудряшов
committed
public int Row;
/// <summary>
/// Inner index

Debolskiy Andrey
committed
/// Внутренний индекс

Антон Кудряшов
committed
public int Col;
/// <summary>
/// designated constructor
/// </summary>
/// <param name="Row">row index</param>
/// <param name="Col">column index</param>

Антон Кудряшов
committed
{
if (Row <= -1 || Col <= -1) {
throw new Exception("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()))
{
throw new System.ArgumentException("Passed coordinates are not valid!");
}
else
{
this.X = X;
this.Y = Y;
}
}

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

Debolskiy Andrey
committed
public bool CheckValue()
{
bool checker = true;
if (X != null) { checker = true; }
else { checker = false; }
if (Y != null) { checker = true; }
else { checker = false; }
return checker;
/// <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
/// Координаты центра ячейки
/// <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)

Debolskiy Andrey
committed
if (!(this.CheckValue()))
{
throw new System.ArgumentException("Prognostic wind velocities are incorrect");
}
else
{
this.coords = coord;
this.velocityX = vX;
this.velocityY = vY;
}
}

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

Debolskiy Andrey
committed
public bool CheckValue()
{
bool checker = false;

Debolskiy Andrey
committed
///Скорость ветра на высоте 10м от поверхности на Земле не может превышать 70м/c

Debolskiy Andrey
committed
if (Math.Abs(velocityX) < 70) { checker = true; }
else { checker = false; }
if (Math.Abs(velocityY) < 70) { checker = true; }
else { checker = false; }
return checker;
/// <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
/// Координаты центра ячейки
/// <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)

Debolskiy Andrey
committed
if (!(this.CheckValue()))
{
throw new System.ArgumentException("Climate wind value is not correct");
}
else
{
this.coords = coord;
this.wind5 = w5;
this.wind10 = w10;
this.wind15 = w15;
}
}

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

Debolskiy Andrey
committed
public bool CheckValue()
{
bool checker = true;
if (Math.Abs(wind5) < 70 && Math.Abs(wind10) < 70 && Math.Abs(wind15) < 70) { checker = true; }
else { checker = false; }
return checker;
/// <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
this.height = hgh;

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()
{
bool checker = true;
if (width > 0 && height > 0) { checker = true; }
else { checker = false; }
return checker;

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

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

Debolskiy Andrey
committed
/// уникальный идентификатор

Debolskiy Andrey
committed
public int identifier { get; set; }
/// <summary>
/// year of construction

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

Debolskiy Andrey
committed
/// average height of cable span between two poles, meters
/// средняя высота пролета, м
/// <summary>
/// power kW for switches

Debolskiy Andrey
committed
/// Мощность ЛЭП, кВт
/// <summary>
/// Line vertices coordinate list

Debolskiy Andrey
committed
/// список координат вершин ЛЭП как линейного объекта
public List<Coordinate> coords { get; set; }
/// <summary>
/// assigned powerstation/pole

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

Debolskiy Andrey
committed
public int pointFromID;
/// <summary>
/// assigned powerstation/pole

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

Debolskiy Andrey
committed
public int pointToID;
/// <summary>
/// broken/not broken switch

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

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

Debolskiy Andrey
committed
public bool ison;
private int MissingIdValue = -1;

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(List<Coordinate> coordinates, int id, int year, double height, int power, int toID, int fromID)
this.year = year;
this.height = height;
this.power = power;

Debolskiy Andrey
committed
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 = true;
if ( identifier>= 0 && Math.Abs(year - 1985) < 45 && Math.Abs(height - 15)<15 && power > 0 && power < 1000 && pointFromID >=0 && pointToID >=0)
{ checker = true; }
else { checker = false; }
return checker;
}
/// <summary>
/// powerstation/pole point class

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

Debolskiy Andrey
committed
/// уникальный идентификатор подстанции/столба

Debolskiy Andrey
committed
public int identifier;
/// <summary>
/// Coordinates
/// </summary>
/// <summary>
/// station name field

Debolskiy Andrey
committed
/// название подстанции

Debolskiy Andrey
committed
public string name;
/// <summary>
/// power, kW

Debolskiy Andrey
committed
/// мощность, кВт

Debolskiy Andrey
committed
public int power;
/// <summary>
/// type of point - trans/pole/endpoint

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

Debolskiy Andrey
committed
public enum stationtype {pole, trans, endstat};
/// <summary>
/// тип подстанции
/// </summary>
public stationtype type;
/// <summary>
/// is point a source?

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

Debolskiy Andrey
committed
public bool issource;
/// <summary>
/// power on switch

Debolskiy Andrey
committed
/// поступает (true) или нет (false) на подстанцию питание

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

Debolskiy Andrey
committed
public PowerStation(Coordinate crds, int id, string stname, int stpower, stationtype sttype, bool issource)

Debolskiy Andrey
committed
{
this.coords = crds;
this.identifier = id;
this.name = stname;
this.power = stpower;
this.type = sttype;
this.issource = issource;

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
public bool CheckValue()
{
bool checker = true;
if (identifier >=0 && power >0 && power < 1000 )
{ checker = true; }
else { checker = false; }
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
/// коэффициенты аффинного преобразования из проекции массива климатических полей скорости ветра заданной повторяемости
public double[] climateAffineCoefficients { get; set; }
/// <summary>
/// lines list

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

Debolskiy Andrey
committed
/// список точечных объектов - трансформаторных подстанций/столбов/понижающих(конечных) подстанций
public List<PowerStation> powerStations { get; set; }

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

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

Debolskiy Andrey
committed
/// Список прогнозируемых сломанных ЛЭП в результате ветрового воздействия
public List<Powerline> disabledLines { get; set; }
/// <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
{
this.input = input;
//Calculate which lines are broken
List<WindStressPRM.Powerline> prmBrokenLines = brokenPowerLinesAfterCheck();

Debolskiy Andrey
committed
//get the graph

Debolskiy Andrey
committed
//start from source points

Debolskiy Andrey
committed
{
if (pwstation.issource)
{
CheckPowerPointsForStation(pwstation);

Debolskiy Andrey
committed
}
Output output = new Output();
output.disabledStations = new List<PowerStation>();
output.disabledLines = new List<Powerline>();

Debolskiy Andrey
committed
{
if (line.isbroken)
{
output.disabledLines.Add(line);

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
//stations of type pole can be disabled if the line is broken
if (!powerStation.ison && !(powerStation.type == 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
if (!sourcepoint.ison)
{
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
foreach (Powerline line in sourcepoint.linelist)
{
if (!line.isbroken && !line.ison)

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
{
if (powerStation.identifier != sourcepoint.identifier && (powerStation.identifier == line.pointFromID || powerStation.identifier == line.pointToID))

Debolskiy Andrey
committed
{

Debolskiy Andrey
committed
if (!(sourcepoint.type == 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
bool powerLineCheck = false;
foreach (Powerline powerline in powerStation.linelist)

Debolskiy Andrey
committed
{
if (powerline.isbroken) {
powerLineCheck = true;
}

Debolskiy Andrey
committed
}

Debolskiy Andrey
committed
{
powerStation.ison = true;
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

Debolskiy Andrey
committed
{
if (powerStation.issource == true) {
powerStation.ison = true;
}
else {
powerStation.ison = false;
}

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<Coordinate> points = powerCurve.coords;
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++)
{

Debolskiy Andrey
committed
if (j == 0)
{
midpoint.X = (subCoord1.X + subCoord2.X) / 2;
midpoint.Y = (subCoord1.Y + subCoord2.Y) / 2;
pointlist.Add(midpoint);
}
else
{
// move to next center
subCoord1.X = subCoord2.X;
subCoord1.Y = subCoord2.Y;
subCoord2.X = subCoord1.X + constXdiff;
subCoord2.Y = subCoord1.Y + constYdiff;

Debolskiy Andrey
committed
midpoint.X = (subCoord1.X + subCoord2.X) / 2;
midpoint.Y = (subCoord1.Y + subCoord2.Y) / 2;
pointlist.Add(midpoint);
midpoint.X = (coord1.X + coord2.X) / 2;
midpoint.Y = (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)
{
if (lastcheck == true) { result = true; }

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
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
{
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
{

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

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

Антон Кудряшов
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
{

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

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

Антон Кудряшов
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);

Антон Кудряшов
committed
//PRM_coordinate last = cellToProjection(rcTopRight, functionType);//test only
// sizes for cell
double hx = cellSizeForFunction(functionType).width;
double hy = cellSizeForFunction(functionType).height;
// coefficients
double px = (coords.X - origin.X) / hx;
double py = (coords.Y - origin.Y) / hy;
// inverse directions
px *= normalX ? 1 : -1;
py *= normalY ? 1 : -1;
// interpolation
double top = (1 - px) * valTopLeft + px * valTopRight;
double bot = (1 - px) * valBotLeft + px * valBotRight;
double rval = (1 - py) * bot + py * top;
return rval;
}