- •Аннотация
- •Abstract
- •Глава 1. Проекционные методы решения слау 8
- •Глава 2. Перезапускаемый метод gmres 20
- •Глава 3. Разработка параллельной модификации метода gmres 28
- •Глава 4. Исследование параллельной модификации перезапускаемого gmres 47
- •Введение
- •Глава 1. Проекционные методы решения слау
- •1.1. Принцип построения проекционных методов
- •1.2. Методы подпространства Крылова
- •1.2.1. Метод полной ортогонализации
- •1.2.2. Метод сопряженных градиентов
- •1.2.3. Метод минимальных невязок
- •1.2.3. Метод обобщенных минимальных невязок
- •1.3. Сравнение проекционных методов
- •1.4. Постановка задачи магистерской диссертации
- •1.5. Выводы по главе 1
- •Глава 2. Перезапускаемый методGmres
- •2.1. Ортогонализация Арнольди
- •2.2. Метод вращений Гивенса
- •2.3. Декомпозиция алгоритмаGmres
- •2.4. Предобуславливание в методеGmres
- •2.5. Выводы по главе 2
- •Глава 3. Разработка параллельной модификации методаGmres
- •3.1. Основные классы параллельных вычислительных систем
- •3.2. Классификация моделей параллельного программирования
- •3.3. Формат хранения разреженных матриц
- •3.4. Разделение данных
- •3.5. Исследование обменных взаимодействий в модели передачи сообщений
- •3.6. Особенности параллельной модификации методаGmres
- •3.6.1. Распределение данных по исполнителям
- •3.6.2. Выполнение параллельных операций
- •3.6.3. Объединение результатов расчетов
- •3.7. Теоретическая оценка трудоемкости
- •3.8. Выводы по главе 3
- •Глава 4. Исследование параллельной модификации перезапускаемогоGmres
- •4.1. Задача аэродинамического обтекания профиля
- •4.2. Исследование эффективности параллельной модификации перезапускаемогоGmres
- •4.3. Выводы по главе 4
- •Заключение
- •Список литературы
- •Приложение
Список литературы
Официальный сайт федеральной службы государственной статистики [Электронный ресурс]. – Режим доступа http://www.gks.ru/.
Шляхтенко С.М. и др. Теория воздушно-реактивных двигателей. – М.: «Машиностроение», 1975. – 568 с.
Мунин А.Г., Квитка В.Е. Авиационная акустика. – М.: «Машиностроение», 1973. – 448 с.
Cobra. Описание программы. Руководство пользователя. – М.: ЦИАМ, 2006. – 29 с.
Крукиер Л.А., Пичугина О.А., Чикина Л.Г. Обзор методов подпространства Крылова // XIV Международная конференция-школа с международным участием «Современные проблемы математического моделирования». – Ростов-на-Дону: изд-во Южного федерального университета, 2011. – 400 с.
Баландин М.Ю., Шурина Э.П. Методы решения СЛАУ большой размерности. – Новосибирск: Изд-во РГГУ, 2000. – 70 с.
Бахвалов Н.С., Жидков Н.П., Кобельков Г.М. Численные методы. – М.: Наука, 1975. – 630 с.
Распопов В.Е., Клунникова М.М. Лекции по курсу «Численные методы». – Красноярск, 2007. – 186 с.
Жуков В.Т., Новикова Н.Д., Феодоритова О.Б. Сдвиговая стратегия в обобщенном методе минимальных невязок. – М., 2009. – 29 с.
Воеводин В.В. Линейная алгебра. М.: Наука, 1980. – 400 с.
Гергель В.П. Теория и практика параллельных вычислений // Учебное пособие. – М.: БИНОМ. Лаборатория знаний, 2007 . – С. 423.
Малышкин В.Э., Корнеев В.Д. Параллельное программирование мультикомпьютеров. – Новосибирск: Издательство НГТУ, 2006. – 439 с.
Кутепов В.П. О параллелизме с разных сторон // 5-я Международная конференция «Параллельные вычисления и проблемы управления». РАН. М.: Институт проблем управления, 2010, 41 – 52.
Писсанецки С. Технология разреженных матриц. – М.: Мир, 1988. – 398 с.
Амосов А.А., Дубинский Ю.А., Копченова Н.В. Вычислительные методы для инженеров // учебное пособие. – М.: Высш. шк., 1994. – 544 с.
Алгоритм Штрассена [Электронный ресурс]. – Режим доступа: ru.wikipedia.org/wiki/Алгоритм_Штрассена.
Алгоритм Копперсмита-Винограда [Электронный ресурс]. – Режим доступа: ru.wikipedia.org/wiki/Алгоритм_Копперсмита_--_Винограда.
Абрамович Г.Н. Прикладная газовая динамика. – М.: Наука, 1969. – 824 с.
Программный комплекс Cobrav2.5. Свидетельство о государственной регистрации №2010613209 от 14 мая 2010 г.
Буюкли Т.В. Моделирование динамического поведения лопаток компрессоров авиационных двигателей в нестационарном потоке воздуха: дис. канд. технич. наук. Московский авиационный институт, Москва, 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;
}