Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Организация и исследование эффективных вычислений для решения задач аэроакустики на кластерных архитектурах (магистерская диссерта / Буренков С. Организация и исследование эффективных вычислений для решения задач аэроакустики на кластерных архитектурах.doc
Скачиваний:
86
Добавлен:
28.06.2014
Размер:
2.27 Mб
Скачать

Список литературы

  1. Официальный сайт федеральной службы государственной статистики [Электронный ресурс]. – Режим доступа http://www.gks.ru/.

  2. Шляхтенко С.М. и др. Теория воздушно-реактивных двигателей. – М.: «Машиностроение», 1975. – 568 с.

  3. Мунин А.Г., Квитка В.Е. Авиационная акустика. – М.: «Машиностроение», 1973. – 448 с.

  4. Cobra. Описание программы. Руководство пользователя. – М.: ЦИАМ, 2006. – 29 с.

  5. Крукиер Л.А., Пичугина О.А., Чикина Л.Г. Обзор методов подпространства Крылова // XIV Международная конференция-школа с международным участием «Современные проблемы математического моделирования». – Ростов-на-Дону: изд-во Южного федерального университета, 2011. – 400 с.

  6. Баландин М.Ю., Шурина Э.П. Методы решения СЛАУ большой размерности. – Новосибирск: Изд-во РГГУ, 2000. – 70 с.

  7. Бахвалов Н.С., Жидков Н.П., Кобельков Г.М. Численные методы. – М.: Наука, 1975. – 630 с.

  8. Распопов В.Е., Клунникова М.М. Лекции по курсу «Численные методы». – Красноярск, 2007. – 186 с.

  9. Жуков В.Т., Новикова Н.Д., Феодоритова О.Б. Сдвиговая стратегия в обобщенном методе минимальных невязок. – М., 2009. – 29 с.

  10. Воеводин В.В. Линейная алгебра. М.: Наука, 1980. – 400 с.

  11. Гергель В.П. Теория и практика параллельных вычислений // Учебное пособие. – М.: БИНОМ. Лаборатория знаний, 2007 . – С. 423.

  12. Малышкин В.Э., Корнеев В.Д. Параллельное программирование мультикомпьютеров. – Новосибирск: Издательство НГТУ, 2006. – 439 с.

  13. Кутепов В.П. О параллелизме с разных сторон // 5-я Международная конференция «Параллельные вычисления и проблемы управления». РАН. М.: Институт проблем управления, 2010, 41 – 52.

  14. Писсанецки С. Технология разреженных матриц. – М.: Мир, 1988. – 398 с.

  15. Амосов А.А., Дубинский Ю.А., Копченова Н.В. Вычислительные методы для инженеров // учебное пособие. – М.: Высш. шк., 1994. – 544 с.

  16. Алгоритм Штрассена [Электронный ресурс]. – Режим доступа: ru.wikipedia.org/wiki/Алгоритм_Штрассена.

  17. Алгоритм Копперсмита-Винограда [Электронный ресурс]. – Режим доступа: ru.wikipedia.org/wiki/Алгоритм_Копперсмита_--_Винограда.

  18. Абрамович Г.Н. Прикладная газовая динамика. – М.: Наука, 1969. – 824 с.

  19. Программный комплекс Cobrav2.5. Свидетельство о государственной регистрации №2010613209 от 14 мая 2010 г.

  20. Буюкли Т.В. Моделирование динамического поведения лопаток компрессоров авиационных двигателей в нестационарном потоке воздуха: дис. канд. технич. наук. Московский авиационный институт, Москва, 2011. – 132 с.

Приложение

// GMRES v3.0.cpp : Defines the entry point for the console application.

#include "stdafx.h"

#include <stdlib.h>

#include <cstring>

#include "mpi.h"

#include "math.h"

#define _SUCCESS 0

#define _OUT_OF_ARRAYS_BORDER 1

#define _READ_ERROR 2

int ProcNum, ProcRank;

int *pSizes, *pPlaceBegin;

int FirstRow, LastRow, NumbRows;

///////////////////////////////

void myprint(int size, double *v, const char* ch)

{

FILE *ff;

if (ProcRank == 0)

{

ff = fopen("E:\\GMRES_out_0.txt", "a");

fprintf(ff, "\n");

fprintf(ff, ch);

fprintf(ff, "\n");

for (int i = 0; i < size; i++)

fprintf(ff, "%lg ", v[i]);

fprintf(ff, "\n");

}

if (ProcRank == 1)

{

ff = fopen("E:\\GMRES_out_1.txt", "a");

fprintf(ff, "\n");

fprintf(ff, ch);

fprintf(ff, "\n");

for (int i = 0; i < size; i++)

fprintf(ff, "%lg ", v[i]);

fprintf(ff, "\n");

}

if (ProcRank == 2)

{

ff = fopen("E:\\GMRES_out_2.txt", "a");

fprintf(ff, "\n");

fprintf(ff, ch);

fprintf(ff, "\n");

for (int i = 0; i < size; i++)

fprintf(ff, "%lg ", v[i]);

fprintf(ff, "\n");

}

fclose(ff);

}

////////////////////////////////////////

//=======================================================

template <class T>

T* myRealloc(T* buf, int oldSize, int newSize)

{

T* newBuf = (T*)malloc(newSize * sizeof(T));

int minSize = ((oldSize < newSize) ? oldSize : newSize);

for (int i = 0; i < minSize; i++)

newBuf[i] = buf[i];

if (buf)

free(buf);

return newBuf;

}

//=======================================================

class sparseMatrix

{

public:

int size; // размерность квадратной матрицы

int numbNonZeroElem; // количество ненулевых элементов в матрице

double* aelem; // массив ненулевых элементов матрицы

int* jptr; // номера столбцов ненулевых элементов из aelem

int* iptr; // номер

sparseMatrix(int Size = 0, int NumbNonZeroElem = 0);

sparseMatrix(const sparseMatrix& sm);

void setSize(int Size);

int getSize();

~sparseMatrix();

int put(double elem, int row, int col);

void workOutput();

int loadFromFile(const char* addr);

double get(int row, int col);

friend void SendSparseMatrix(sparseMatrix *matr, int ToProc);

friend void RecvSparseMatrix(sparseMatrix *matr, int FromProc);

friend void MultiplicationOfMatrixToVector(int Size, sparseMatrix A, double* b, double* result);

};

sparseMatrix::sparseMatrix(int Size, int NumbNonZeroElem)

{

size = Size;

numbNonZeroElem = NumbNonZeroElem;

iptr = (int*)calloc(size + 1, sizeof(int));

if (NumbNonZeroElem == 0)

{

jptr = NULL;

aelem = NULL;

}

else

{

aelem = (double*)calloc(NumbNonZeroElem, sizeof(double));

jptr = (int*)calloc(NumbNonZeroElem, sizeof(int));

}

}

sparseMatrix::sparseMatrix(const sparseMatrix& sm)

{

size = sm.size;

numbNonZeroElem = sm.numbNonZeroElem;

iptr = (int*)calloc(size + 1, sizeof(int));

for (int i = 0; i <= size; i++)

iptr[i] = sm.iptr[i];

aelem = (double*)calloc(numbNonZeroElem, sizeof(double));

jptr = (int*)calloc(numbNonZeroElem, sizeof(int));

for (int i = 0; i < numbNonZeroElem; i++)

{

aelem[i] = sm.aelem[i];

jptr[i] = sm.jptr[i];

}

}

void sparseMatrix::setSize(int Size)

{

size = Size;

numbNonZeroElem = 0;

free(iptr);

iptr = (int*)calloc(size + 1, sizeof(int));

free(aelem);

aelem = NULL;

free(jptr);

jptr = NULL;

}

int sparseMatrix::getSize()

{

return size;

}

//--------------------------------

sparseMatrix::~sparseMatrix()

{

size = 0;

numbNonZeroElem = 0;

if (iptr)

{

free(iptr);

iptr = NULL;

}

if (aelem)

{

free(aelem);

aelem = NULL;

}

if (jptr)

{

free(jptr);

jptr = NULL;

}

}

//--------------------------------

int sparseMatrix::put(double elem, int row, int col)

{

// проверка выхода за границы массивов

if (row < 0 || row >= size || col < 0 || col >= size)

return _OUT_OF_ARRAYS_BORDER;

bool flag = false;

int i, ind;

bool newElemIsNull = (elem == 0.0), oldElemIsNull = true;

// определение индекса элемента

for (i = iptr[row], ind = iptr[row]; i <= iptr[row + 1] - 1; i++)

if (jptr[i] <= col)

{

flag = true;

ind = i;

if (jptr[i] == col)

{

flag = false;

oldElemIsNull = false;

break;

}

}

if (flag)

ind++;

// старый элемент нулевой, а новый - отличен от нуля => добавление элемента в массив

if (oldElemIsNull && !newElemIsNull)

{

// добавление памяти

aelem = myRealloc(aelem, iptr[size], iptr[size] + 1);

jptr = myRealloc(jptr, iptr[size], iptr[size] + 1);

// сдвиг элементов в массивах вправо

for (i = iptr[size]; i > ind; i--)

{

aelem[i] = aelem[i - 1];

jptr[i] = jptr[i - 1];

}

// запись значения в освобожденное место

aelem[ind] = elem;

jptr[ind] = col;

// корректировка массива iptr

for (i = row + 1; i <= size; i++)

iptr[i]++;

numbNonZeroElem++;

return _SUCCESS;

}

// старый элемент ненулевой, а новый - нулевой => удаление элемента из массива

if (!oldElemIsNull && newElemIsNull)

{

// сдвиг массивов влево

for (i = ind; i < iptr[size]; i++)

{

aelem[i] = aelem[i + 1];

jptr[i] = jptr[i + 1];

}

// изменение объема памяти

aelem = myRealloc(aelem, iptr[size], iptr[size] - 1);

jptr = myRealloc(jptr, iptr[size], iptr[size] - 1);

// корректировка массива iptr

for (i = row + 1; i <= size; i++)

iptr[i]--;

numbNonZeroElem--;

return _SUCCESS;

}

// оба элемента не равны нулю

if (!oldElemIsNull && !newElemIsNull)

{

aelem[ind] = elem;

return _SUCCESS;

}

// оба элемента равны нулю => ничего не делать

return _SUCCESS;

}

//--------------------------------

void sparseMatrix::workOutput()

{

printf("\nIPTR: [");

for (int i = 0; i <= this->size; i++)

printf("%d, ", this->iptr[i]);

printf("]\n");

printf("JPTR: [");

for (int i = 0; i < this->numbNonZeroElem; i++)

printf("%d, ", this->jptr[i]);

printf("]\n");

printf("AELEM: [");

for (int i = 0; i < this->numbNonZeroElem; i++)

printf("%lg, ", this->aelem[i]);

printf("]\n");

}

//--------------------------------

int sparseMatrix::loadFromFile(const char* addr)

{

FILE *f;

int Size, i, j;

double buf;

if ((f = fopen(addr, "r")) == NULL)

return _READ_ERROR;

if (fscanf(f, "%d\n", &Size) == NULL)

return _READ_ERROR;

this->setSize(Size);

for (i = 0; i < size; i++)

{

for (j = 0; j < size; j++)

if (fscanf(f, "%lg", &buf) != NULL)

this->put(buf, i, j);

else

return _READ_ERROR;

fscanf(f, "\n");

}

return _SUCCESS;

}

//--------------------------------

double sparseMatrix::get(int row, int col)

{

for (int i = iptr[row]; i <= iptr[row + 1] - 1; i++)

{

if (jptr[i] == col)

return aelem[i];

if (jptr[i] > col)

return 0;

}

return 0;

}

//=======================================================

double ScalarVectorsMultiplication(int Size, const double* v1, const double* v2)

{

double partResult = 0.0, finalResult = 0.0;

for (int i = ProcRank; i < Size; i += ProcNum)

partResult += v1[i] * v2[i];

MPI_Allreduce(&partResult, &finalResult, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

return finalResult;

}

//-------------------------------------------------------

// взвешенная сумма векторов: V = a * V1 + V2

void ScaledVectorsSum(double alpha, int Size, double* v1, double* v2, double* res)

{

double* vbuf;

vbuf = (double*)malloc(NumbRows * sizeof(double));

for (int i = FirstRow; i < LastRow; i++)

vbuf[i - FirstRow] = alpha * v1[i] + v2[i];

MPI_Allgatherv(vbuf, NumbRows, MPI_DOUBLE, res, pSizes, pPlaceBegin, MPI_DOUBLE, MPI_COMM_WORLD);

free(vbuf);

}

//-------------------------------------------------------

// умножение вектора на константу: V = a * V1

void ConstToVectorMultiplication(double alpha, int Size, const double* v1, double* res)

{

double* vbuf;

vbuf = (double*)malloc(NumbRows * sizeof(double));

for (int i = FirstRow; i < LastRow; i++)

vbuf[i - FirstRow] = alpha * v1[i];

MPI_Allgatherv(vbuf, NumbRows, MPI_DOUBLE, res, pSizes, pPlaceBegin, MPI_DOUBLE, MPI_COMM_WORLD);

free(vbuf);

}

//-------------------------------------------------------

// умножение матрицы на вектор: V = A * b

void MatrixToVectorMultiplication(int Size, sparseMatrix A, const double* b, double* res)

{

int j;

double* vbuf;

vbuf = (double*)calloc(Size, sizeof(double));

for (int i = 0; i < A.iptr[A.size]; i++)

{

for (j = 1; j <= Size; j++)

if (i < A.iptr[j])

{

j--;

break;

}

vbuf[j] += A.aelem[i] * b[A.jptr[i]];

}

//MPI_Allreduce(vbuf, res, Size, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

MPI_Allgatherv(vbuf + FirstRow, NumbRows, MPI_DOUBLE, res, pSizes, pPlaceBegin, MPI_DOUBLE, MPI_COMM_WORLD);

free(vbuf);

}

//-------------------------------------------------------

// NORN = sqrt(a1*a1 + a2*a2 + ... + aN*aN)

double VectorNormEvklid(int Size, const double* pVector)

{

double partResult = 0.0, finalResult = 0.0;

for (int i = ProcRank; i < Size; i += ProcNum)

partResult += pVector[i] * pVector[i];

MPI_Allreduce(&partResult, &finalResult, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

return sqrt(finalResult);

}

//-------------------------------------------------------

// вычисление невязки: r = b - A * x

void FindMisalignment(int Size, sparseMatrix A, const double* x, const double* b, double* res)

{

double *vbuf1, *vbuf2;

vbuf1 = (double*)malloc(Size * sizeof(double));

vbuf2 = (double*)malloc(NumbRows * sizeof(double));

MatrixToVectorMultiplication(Size, A, x, vbuf1);

for (int i = FirstRow; i < LastRow; i++)

vbuf2[i - FirstRow] = b[i] - vbuf1[i];

MPI_Allgatherv(vbuf2, NumbRows, MPI_DOUBLE, res, pSizes, pPlaceBegin, MPI_DOUBLE, MPI_COMM_WORLD);

free(vbuf1);

free(vbuf2);

}

//-------------------------------------------------------

// решение СЛАУ с верхнетреугольной матрицей коэффициентов методом Гаусса

void UpperGaussSolve(int Size, const double* A, const double* b, double* x)

{

double s;

double* buf;

buf = (double*)calloc(Size, sizeof(double));

for (int i = Size - 1; i >= 0; i--)

{

s = 0.0;

for (int j = i + 1; j < Size; j++)

s += A[i * Size + j] * buf[j];

buf[i] = (b[i] - s) / A[i * Size + i];

}

for (int i = 0; i < Size; i++)

x[i] = buf[i];

free(buf);

}

//-------------------------------------------------------

// зануляется элемент H[ind][ind + 1]: H = G[ind] * H

void RotationOfHessMatr(int size, double* H, int ind, double cosVal, double sinVal)

{

double hElem, lElem;

for (int i = 0; i < size; i++)

{

hElem = H[ind * size + i];

lElem = H[(ind + 1) * size + i];

H[ind * size + i] = cosVal * hElem + sinVal * lElem;

H[(ind + 1) * size + i] = -1.0 * sinVal * hElem + cosVal * lElem;

}

}

//-------------------------------------------------------

// умножение вектора g на матрицу поворота G:

// g = G[ind] * g

void RotationOfVector(int size, double* g, int ind, double cosVal, double sinVal)

{

double lElem, rElem;

lElem = g[ind];

rElem = g[ind + 1];

g[ind] = cosVal * lElem + sinVal * rElem;

g[ind + 1] = cosVal * rElem - sinVal * lElem;

}

//-------------------------------------------------------

int _tmain(int argc, char* argv[])

{

int Size;

double betta;

double eps;

double tStart, tFinish;

double* vbuf;

double dbuf;

int Space, P, ibuf;

int* vIntBuf;

int iteration = 0, maxNumbIterations;

double *cosVal, *sinVal, root;

MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &ProcNum);

MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank);

if (ProcRank == 0)

tStart = MPI_Wtime();

FILE *fiptr, *fjptr, *faelem, *fmode, *f;

// чтение и распространение параметров программы

if (ProcRank == 0)

{

fmode = fopen("E:\\GMRES_mode.txt", "r");

fscanf(fmode, "%d %lg %d\n", &Space, &eps, &maxNumbIterations);

fclose(fmode);

}

MPI_Bcast(&Space, 1, MPI_INT, 0, MPI_COMM_WORLD);

MPI_Bcast(&eps, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);

MPI_Bcast(&maxNumbIterations, 1, MPI_INT, 0, MPI_COMM_WORLD);

// чтение и распространение размерности системы

if (ProcRank == 0)

{

fiptr = fopen("E:\\GMRES_iptr.txt", "r");

fjptr = fopen("E:\\GMRES_jptr.txt", "r");

faelem = fopen("E:\\GMRES_aelem.txt", "r");

fscanf(fiptr, "%d\n", &Size);

}

MPI_Bcast(&Size, 1, MPI_INT, 0, MPI_COMM_WORLD);

// предварительное распределение строк по процессорам

pSizes = (int*)calloc(ProcNum, sizeof(int));

pPlaceBegin = (int*)calloc(ProcNum, sizeof(int));

NumbRows = Size / ProcNum;

FirstRow = NumbRows * ProcRank;

LastRow = NumbRows * (ProcRank + 1);

if (ProcRank == ProcNum - 1)

{

LastRow = Size;

NumbRows = LastRow - FirstRow;

}

vIntBuf = (int*)calloc(ProcNum, sizeof(int));

vIntBuf[ProcRank] = NumbRows;

MPI_Allreduce(vIntBuf, pSizes, ProcNum, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

vIntBuf = (int*)memset(vIntBuf, 0, ProcNum * sizeof(int));

vIntBuf[ProcRank] = FirstRow;

MPI_Allreduce(vIntBuf, pPlaceBegin, ProcNum, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

free(vIntBuf);

// чтение входных данных

sparseMatrix A(Size);

if (ProcRank == 0)

{

// чтение массива iptr на главном процессоре

for (int i = 0; i <= Size; i++)

fscanf(fiptr, "%d", &A.iptr[i]);

A.jptr = (int*)malloc(A.iptr[Size] * sizeof(int));

A.aelem = (double*)malloc(A.iptr[Size] * sizeof(double));

// чтение главным процессором своей части матрицы

for (int i = A.iptr[FirstRow]; i < A.iptr[LastRow]; i++)

{

fscanf(fjptr, "%d", &A.jptr[i]);

fscanf(faelem, "%lf", &A.aelem[i]);

A.numbNonZeroElem++;

}

// чтение и отправление частей матрицы другим процессорам

for (int p = 1; p < ProcNum; p++)

{

int finalBorder;

if (p == ProcNum - 1)

finalBorder = Size;

else

finalBorder = NumbRows * (p + 1);

sparseMatrix bufMatr(Size, A.iptr[finalBorder] - A.iptr[NumbRows * p]);

for (int i = 0; i < bufMatr.numbNonZeroElem; i++)

{

fscanf(fjptr, "%d", &bufMatr.jptr[i]);

fscanf(faelem, "%lf", &bufMatr.aelem[i]);

}

for (int i = NumbRows * p; i <= finalBorder; i++)

bufMatr.iptr[i] = A.iptr[i] - A.iptr[NumbRows * p];

for (int i = finalBorder; i <= Size; i++)

bufMatr.iptr[i] = bufMatr.iptr[finalBorder];

MPI_Send(&bufMatr.size, 1, MPI_INT, p, 99, MPI_COMM_WORLD);

MPI_Send(&bufMatr.numbNonZeroElem, 1, MPI_INT, p, 99, MPI_COMM_WORLD);

MPI_Send(bufMatr.iptr, bufMatr.size + 1, MPI_INT, p, 99, MPI_COMM_WORLD);

MPI_Send(bufMatr.jptr, bufMatr.numbNonZeroElem, MPI_INT, p, 99, MPI_COMM_WORLD);

MPI_Send(bufMatr.aelem, bufMatr.numbNonZeroElem, MPI_DOUBLE, p, 99, MPI_COMM_WORLD);

}

// заполнение чужой части iptr

for (int i = LastRow + 1; i <= Size; i++)

A.iptr[i] = A.iptr[LastRow];

fclose(fiptr);

fclose(fjptr);

fclose(faelem);

}

else

{

MPI_Status Status;

int oldNumbNonZeroElem = A.numbNonZeroElem;

MPI_Recv(&A.size, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &Status);

MPI_Recv(&A.numbNonZeroElem, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &Status);

MPI_Recv(A.iptr, A.size + 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &Status);

A.jptr = myRealloc(A.jptr, oldNumbNonZeroElem, A.numbNonZeroElem);

MPI_Recv(A.jptr, A.numbNonZeroElem, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &Status);

A.aelem = myRealloc(A.aelem, oldNumbNonZeroElem, A.numbNonZeroElem);

MPI_Recv(A.aelem, A.numbNonZeroElem, MPI_DOUBLE, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &Status);

}

// чтение и рассылка вектора правой части

double* b;

b = (double*)calloc(Size, sizeof(double));

if (ProcRank == 0)

{

f = fopen("E:\\GMRES_inpB.txt", "r");

fscanf(f, "%d\n", &Size);

for (int i = 0; i < Size; i++)

fscanf(f, "%lg", &b[i]);

fclose(f);

}

MPI_Bcast(b, Size, MPI_DOUBLE, 0, MPI_COMM_WORLD);

P = Space;

// выделение памяти для промежуточных массивов

double *x, *r, *H, *g, *w, **v;

x = (double*)malloc(Size * sizeof(double));

r = (double*)malloc(Size * sizeof(double));

H = (double*)calloc((Space + 1) * Space, sizeof(double));

g = (double*)calloc(Space + 1, sizeof(double));

w = (double*)malloc(Size * sizeof(double));

vbuf = (double*)malloc(Size * sizeof(double));

v = (double**)malloc((Space + 1) * sizeof(double*));

for (int i = 0; i < Space + 1; i++)

v[i] = (double*)calloc(Size, sizeof(double));

cosVal = (double*)malloc(Space * sizeof(double));

sinVal = (double*)malloc(Space * sizeof(double));

//////////////////////////////////////////////////

x = (double*)memcpy(x, b, Size * sizeof(double));

FindMisalignment(Size, A, x, b, r);

betta = VectorNormEvklid(Size, r);

while ((betta > eps) && (iteration < maxNumbIterations))

{

iteration++;

// построение базиса подпространства Крылова

H = (double*)memset(H, 0, (Space + 1) * Space * sizeof(double));

ConstToVectorMultiplication(1.0 / betta, Size, r, v[0]);

for (int i = 0; i < Space; i++)

{

MatrixToVectorMultiplication(Size, A, v[i], w);

for (int k = 0; k <= i; k++)

{

H[k * Space + i] = ScalarVectorsMultiplication(Size, w, v[k]);

ScaledVectorsSum(-1.0 * H[k * Space + i], Size, v[k], w, w);

}

H[(i + 1) * Space + i] = VectorNormEvklid(Size, w);

ConstToVectorMultiplication(1.0 / H[(i + 1) * Space + i], Size, w, v[i + 1]);

}

// вращения Гивенса

g = (double*)memset(g, 0, (Space + 1) * sizeof(double));

g[0] = betta;

for (int i = 0; i < Space; i++)

{

root = sqrt(H[i * Space + i] * H[i * Space + i] + H[(i + 1) * Space + i] * H[(i + 1) * Space + i]);

cosVal[i] = H[i * Space + i] / root;

sinVal[i] = H[(i + 1) * Space + i] / root;

RotationOfHessMatr(Space, H, i, cosVal[i], sinVal[i]);

RotationOfVector(Space, g, i, cosVal[i], sinVal[i]);

if (fabs(g[i + 1]) < eps)

{

P = i + 1;

break;

}

}

UpperGaussSolve(P, H, g, g);

vbuf = (double*)memset(vbuf, 0, Size * sizeof(double));

for (int i = 0; i < P; i++)

{

ConstToVectorMultiplication(g[i], Size, v[i], vbuf);

ScaledVectorsSum(1.0, Size, x, vbuf, x);

}

FindMisalignment(Size, A, x, b, r);

betta = VectorNormEvklid(Size, r);

if (P < Space)

break;

}

//////////////////////////////////////////////////

if (ProcRank == 0)

{

f = fopen("E:\\GMRES_out.txt", "w");

if (betta > eps)

fprintf(f, "Coudn't get solve with %d iterations. Residual norm is %e", maxNumbIterations, betta);

else

{

fprintf(f, "%d\n", Size);

for (int i = 0; i < Size; i++)

fprintf(f, "%lg ", x[i]);

}

fclose(f);

}

// освобождение динамической памяти

for (int i = 0; i < Space + 1; i++)

free(v[i]);

free(v);

free(vbuf);

free(g);

free(H);

free(r);

free(x);

free(b);

free(pPlaceBegin);

free(pSizes);

free(cosVal);

free(sinVal);

if (ProcRank == 0)

{

tFinish = MPI_Wtime();

f = fopen("E:\\GMRES_PROTOCOL.txt", "a");

fprintf(f, "Space = %d, System size = %d, Iterations = %d, Nproc = %d, time = %lg\n", Space, Size, iteration, ProcNum, tFinish - tStart);

fclose(f);

}

MPI_Finalize();

return 0;

}