Итерационные методы решения СЛАУ
Метод итераций (метод последовательных приближений). Приближенные методы решения систем линейных уравнений позволяют получать значения корней системы с заданной точностью в виде предела последовательности некоторых векторов. Процесс построения такой последовательности называется итерационным (повторяющимся). Эффективность применения приближенных методов зависят от выбора начального вектора и быстроты сходимости процесса. Рассмотрим метод итераций (метод последовательных приближений). Пусть дана система n линейных уравнений с n неизвестными: Ах=b, (14) Предполагая, что диагональные элементы aii 0 (i = 2,..., n), выразим xi через первое уравнение систем x2 - через второе уравнение и т. д. В результате получим систему, эквивалентную системе (14): Обозначим ; , где i == 1, 2,...,n; j == 1,2,..., n. Тогда система (15) запишется таким образом в матричной форме Решим систему (16) методом последовательных приближений. За нулевое приближение примем столбец свободных членов. Любое (k+1)-е приближение вычисляют по формуле Если последовательность приближений x(0),...,x(k) имеет предел , то этот предел является решением системы (15), поскольку в силу свойства предела , т.е. [4,6]. Метод Зейделя. Метод Зейделя представляет собой модификацию метода последовательных приближений. В методе Зейделя при вычислении (k+1)-го приближения неизвестного xi (i>1) учитываются уже найденные ранее (k+1)-е приближения неизвестных xi-1. Пусть дана линейная система, приведенная к нормальному виду: (17) Выбираем произвольно начальные приближения неизвестных и подставляем в первое уравнение системы (17). Полученное первое приближение подставляем во второе уравнение системы и так далее до последнего уравнения. Аналогично строим вторые, третьи и т.д. итерации.
Таким образом, предполагая, что k-е приближения известны, методом Зейделя строим (k+1)-е приближение по следующим формулам: где k=0,1,...,n Метод Ланцоша. Для решения СЛАУ высокого порядка (1), матрица, коэффициентов которой хранится в компактном нижеописанном виде, наиболее удобным итерационным методом является метод Ланцоша [4], схема которого имеет вид: (18) где Преимуществом данного метода является его высокая скорость сходимости к точному решению. Кроме того, доказано, что он обладает свойством «квадратичного окончания», т.е. для положительно определенной матрицы можно гарантировано получить точное решение при количестве итераций . Размер требуемой памяти на каждой итерации не изменяется, т.к. не требует преобразование матрицы . В качестве критерия остановки данного итерационного процесса обычно используют соотношение , (19) где - заданная точность. В качестве другого критерия сходимости иногда удобнее использовать среднеквадратичную разность между решениями, полученными на соседних итерациях: (20) Среднеквадратичную разность необходимо контролировать при выполнении каждых k наперед заданных итераций. Отдельно следует рассмотреть проблему выбора начального приближения . Доказывается, что при положительно определенной матрице , итерационный процесс (18) всегда сходится при любом выборе начального приближения. При решении контактных задач, когда для уточнения граничных условий в зоне предполагаемого контакта требуется большое количество решений СЛАУ вида (1), в качестве начального приближения для первого расчета используется правая часть системы (1), а для каждого последующего пересчета - решение, полученное на предыдущем. Такая схема позволяет значительно сократить количество итераций, необходимых для достижения заданной точности (19) или (20) [10,11].
2 МЕТОДЫ КОМПАКТНОГО ХРАНЕНИЯ МАТРИЦЫ ЖЕСТКОСТИ Матрица жесткости, получающаяся при применении МКЭ, обладает симметричной структурой, что позволяет в общем случае хранить только верхнюю треугольную часть матрицы. Однако для задач с большим количеством неизвестных это так же приводит к проблеме нехватки памяти. Предлагаемый в данной работе метод, позволяет хранить только ненулевые члены матрицы жесткости. Суть его заключается в следующем. Первоначально, с целью выявления связей каждого узла с другими, производится анализ структуры дискретизации области на КЭ. Например, для КЭ - сетки, изображенной на рис. 1, соответствующая структура связей будет иметь вид:
Текст подпрограммы, реализующий предложенный алгоритм анализа структуры КЭ-разбиения тела, приведен в Приложении 1. Данный способ компактного хранения матрицы жесткости позволяет легко его использовать совместно с каким-нибудь численным методом. Наиболее удобным для этой цели представляется использование вышеизложенного итерационного метода Ланцоша, так как на каждой итерации требуется только перемножать матрицу коэффициентов СЛАУ и заданный вектор. Следовательно, для использования предложенного метода компактного хранения СЛАУ необходимо построить прямое и обратное преобразование в первоначальную квадратную матрицу. Пусть – элемент первоначальной квадратной матрицы размерностью , а - ее компактное представление. Тогда для обратного преобразования будут справедливы следующие соотношения: , (*) где m – количество степеней свободы (m=1,2,3). Для прямого преобразования будут справедливы соотношения, обратные к соотношениям (*). 3 ЧИСЛЕННЫЕ ЭКСПЕРИМЕНТЫ Для проверки предлагаемого метода компактного хранения матрицы жесткости была решена задача о контактном взаимодействии оболочечной конструкции и ложемента [12] (рис. 4).
Данная задача решалась методом конечных элементов при помощи системы FORL [5]. Дискретная модель ложемента (в трехмерной постановке) представлена на Рис. 5. При построении данной КЭ-модели было использовано 880 узлов и 2016 КЭ в форме тетраэдра. Полный размер матрицы жесткости для такой задачи составляет байт, что приблизительно равно 2,7 Мбайт оперативной памяти. Размер упакованного представления составил около 315 Кбайт. Данная задача решалась на ЭВМ с процессором Pentium 166 и 32 МБ ОЗУ двумя способами – методом Гаусса и методом Ланцоша. Сопоставление результатов решения приведено в Таблице 1. Таблица 1.
Из Таблицы 1 легко видеть, что результаты решения СЛАУ методом Гаусса и методом Ланцоша хорошо согласуются между собой, при этом время решения вторым способом почти в два раза меньше, чем в случае использования метода Гаусса. ВЫВОДЫ. В данной работе были рассмотрены способы компактного хранения матрицы коэффициентов системы линейных алгебраических уравнений (СЛАУ) и методы ее решения. Разработан алгоритм компактного хранения матрицы жесткости, позволяющий в несколько раз (иногда более чем в десятки раз) сократить объем требуемой памяти для хранения такой матрицы жесткости. Классические методы хранения, учитывающие симметричную и ленточную структуру матриц жесткости, возникающих при применении метода конечных элементов (МКЭ), как правило, не применимы при решении контактных задач, так как при их решении матрицы жесткости нескольких тел объединяются в одну общую матрицу, ширина ленты которой может стремиться к порядку системы.
Предложенная в работе методика компактного хранения матриц коэффициентов СЛАУ и использования метода Ланцоша позволили на примере решения контактных задач добиться существенной экономии процессорного времени и затрат оперативной памяти. ПРИЛОЖЕНИЕ 1 Исходный текст программы, реализующий анализ структуры КЭ-разбиения объекта. #include <math.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <fstream.h> #include "matrix.h" #define BASE3D_4 4 #define BASE3D_8 8 #define BASE3D_10 10 const double Eps = 1.0E-10; DWORD CurrentType = BASE3D_10; void PrintHeader(void) { printf("Command format: AConvert -<switch> <file1.in> <file2.in> <file3.out> [/Options]\n"); printf("Switch: -t10 - Tetraedr(10)\n"); printf(" -c8 - Cube(8)\n"); printf(" -s4 - Shell(4)\n"); printf(" -s8 - Shell(8)\n\n"); printf("Optins: /8 - convert Tetraedr(10)->8*Tetraedr(4)\n"); printf(" /6 - convert Cube(8)->6*Tetraedr(4)\n"); } bool Output(char* fname,Vector<double>& x,Vector<double>& y,Vector<double>& z, Matrix<DWORD>& tr, DWORD n, DWORD NumNewPoints,DWORD ntr,Matrix<DWORD>& Bounds,DWORD CountBn) { char* Label = "NTRout"; int type = CurrentType, type1 = (type==BASE3D_4 || type==BASE3D_10)? 3: 4; DWORD NewSize, i, j; ofstream Out; if (type==BASE3D_4) type1 = 3; else if (type==BASE3D_8) type1 = 4; else if (type==BASE3D_10) type1 = 6; Out.open(fname,ios::out | ios:: binary); if (Out.bad()) return true; Out.write((const char*)Label,6 * sizeof(char)); if (Out.fail()) return true; Out.write((const char*)&type,sizeof(int)); if (Out.fail()) return true; Out.write((const char*)&CountBn,sizeof(DWORD)); if (Out.fail()) { Out.close(); return true; } Out.write((const char*)&(NewSize = n + NumNewPoints),sizeof(DWORD)); if (Out.fail()) return true; Out.write((const char*)&(NumNewPoints),sizeof(DWORD)); if (Out.fail()) { Out.close(); return true; } for (DWORD i = 0; i < n; i++) { Out.write((const char*)&x[i],sizeof(double)); Out.write((const char*)&y[i],sizeof(double)); Out.write((const char*)&z[i],sizeof(double)); if (Out.fail()) { Out.close(); return true; } } for (i = 0; i < NumNewPoints; i++) { Out.write((const char*)&x[n + i],sizeof(double)); Out.write((const char*)&y[n + i],sizeof(double)); if (Out.fail()) { Out.close(); return true; } } Out.write((const char*)&(ntr),sizeof(DWORD)); if (Out.fail()) { Out.close(); return true; } for (i = 0; i < ntr; i++) for (j = 0; j < (DWORD)type; j++) { DWORD out = tr[i][j]; Out.write((const char*)&out,sizeof(DWORD)); if (Out.fail()) { Out.close(); return true; } } for (i = 0; i < CountBn; i++) for (j = 0; j < (DWORD)type1; j++) { DWORD out = Bounds[i][j]; Out.write((const char*)&out,sizeof(DWORD)); if (Out.fail()) { Out.close(); return true; } } { //********************* // Create Links printf("Create links...\r"); Vector<DWORD> Link(n), Size(n); Matrix<DWORD> Links(n,n); DWORD Count; int type = CurrentType; for (DWORD i = 0; i < n; i++) { for (DWORD j = 0; j < ntr; j++) for (DWORD k = 0; k < (DWORD)type; k++) if (tr[j][k] == i) for (DWORD m = 0; m < (DWORD)type; m++) Link[tr[j][m]] = 1; Count = 0; for (DWORD m = 0; m < n; m++) if (Link[m]) Count++; Size[i] = Count; Count = 0; for (DWORD m = 0; m < n; m++) if (Link[m]) Links[i][Count++] = m; //Set zero Link.ReSize(n); } // Output //********************* for (DWORD i = 0; i < n; i++) { DWORD Sz = Size[i]; Out.write((const char*)&Sz,sizeof(DWORD)); for (DWORD j = 0; j < Sz; j++) Out.write((const char*)&(Links[i][j]),sizeof(DWORD));
} //********************* } printf(" \r"); printf("Points: %ld\n",n); printf("FE: %ld\n",ntr); Out.close(); return false; } bool Test(DWORD* a,DWORD* b) { bool result; int NumPoints = 3; if (CurrentType == BASE3D_8) NumPoints = 4; else if (CurrentType == BASE3D_10) NumPoints = 6; for (int i = 0; i < NumPoints; i++) { result = false; for (int j = 0; j < NumPoints; j++) if (b[j] == a[i]) { result = true; break; } if (result == false) return false; } return true; } void Convert(Vector<double>& X,Vector<double>& Y,Vector<double>& Z, Matrix<DWORD>& FE,DWORD NumTr,Matrix<DWORD>& Bounds,DWORD& BnCount) { int cData8[6][5] = {{0,4,5,1,7}, {6,2,3,7,0}, {4,6,7,5,0}, {2,0,1,3,5}, {1,5,7,3,4}, {6,4,0,2,1}}, cData4[4][4] = {{0,1,2,3}, {1,3,2,0}, {3,0,2,1}, {0,3,1,2}}, cData10[4][7] = {{0,1,2,4,5,6,3}, {0,1,3,4,8,7,2}, {1,3,2,8,9,5,0}, {0,2,3,6,9,7,1}}, cData[6][7], Data[6], l, Num1, Num2, m; DWORD i, j, p[6], pp[6], Index; Matrix<DWORD> BoundList(4 * NumTr,6); double cx, cy, cz, x1, y1, z1, x2, y2, z2, x3, y3, z3; Bounds.ReSize(4 * NumTr,6); switch (CurrentType) { case BASE3D_4: Num1 = 4; Num2 = 3; for (l = 0; l < Num1; l++) for (m = 0; m < Num2+1; m++) cData[l][m] = cData4[l][m]; break; case BASE3D_8: Num1 = 6; Num2 = 4; for (l = 0; l < Num1; l++) for (m = 0; m < Num2 + 1; m++) cData[l][m] = cData8[l][m]; break; case BASE3D_10: Num1 = 4; Num2 = 6; for (l = 0; l < Num1; l++) for (m = 0; m < Num2+1; m++) cData[l][m] = cData10[l][m]; } printf("Create bounds...\r"); for (i = 0; i < NumTr - 1; i++) for (int j = 0; j < Num1; j++) if (!BoundList[i][j]) { for (l = 0; l < Num2; l++) p[l] = FE[i][cData[j][l]]; for (DWORD k = i + 1; k < NumTr; k++) for (int m = 0; m < Num1; m++) if (!BoundList[k][m]) { for (int l = 0; l < Num2; l++) pp[l] = FE[k][cData[m][l]]; if (Test(p,pp)) BoundList[i][j] = BoundList[k][m] = 1; } } for (i = 0; i < NumTr; i++) for (j = 0; j < (DWORD)Num1; j++) if (BoundList[i][j] == 0) { if (CurrentType == BASE3D_4) { cx = X[FE[i][cData[j][3]]]; cy = Y[FE[i][cData[j][3]]]; cz = Z[FE[i][cData[j][3]]]; } else if (CurrentType == BASE3D_10) { cx = X[FE[i][cData[j][6]]]; cy = Y[FE[i][cData[j][6]]]; cz = Z[FE[i][cData[j][6]]]; } else { cx = X[FE[i][cData[j][4]]]; cy = Y[FE[i][cData[j][4]]]; cz = Z[FE[i][cData[j][4]]]; } x1 = X[FE[i][cData[j][0]]]; y1 = Y[FE[i][cData[j][0]]]; z1 = Z[FE[i][cData[j][0]]]; x2 = X[FE[i][cData[j][1]]]; y2 = Y[FE[i][cData[j][1]]]; z2 = Z[FE[i][cData[j][1]]]; x3 = X[FE[i][cData[j][2]]]; y3 = Y[FE[i][cData[j][2]]]; z3 = Z[FE[i][cData[j][2]]]; for (l = 0; l < Num2; l++) Data[l] = cData[j][l]; if (((cx-x1)*(y2-y1)*(z3-z1) + (cy-y1)*(z2-z1)*(x3-x1) + (y3-y1)*(cz-z1)*(x2-x1) - (x3-x1)*(y2-y1)*(cz-z1) - (y3-y1)*(z2-z1)*(cx-x1) - (cy-y1)*(z3-z1)*(x2-x1)) > 0) { if (CurrentType == BASE3D_4) { Data[0] = cData[j][0]; Data[1] = cData[j][2]; Data[2] = cData[j][1]; } else if (CurrentType == BASE3D_10) { Data[0] = cData[j][0]; Data[1] = cData[j][2]; Data[2] = cData[j][1]; Data[3] = cData[j][5]; Data[5] = cData[j][3]; } else { Data[0] = cData[j][0]; Data[1] = cData[j][3]; Data[2] = cData[j][2]; Data[3] = cData[j][1]; } } for (l = 0; l < Num2; l++) Bounds[BnCount][l] = FE[i][Data[l]]; BnCount++; } } void main(int argc,char** argv) { char *input1, *input2, *input3, *op = "", *sw; bool CreateFile(char*,char*,char*,char*); printf("ANSYS->FORL file convertor. ZSU(c) 1998.\n\n"); if (argc < 5 || argc > 6) { PrintHeader(); return; } sw = argv[1]; input1 = argv[2]; input2 = argv[3]; input3 = argv[4]; if (!strcmp(sw,"-t10")) CurrentType = BASE3D_10; else if (!strcmp(sw,"-c8")) CurrentType = BASE3D_8; else { printf("Unknown switch %s\n\n",sw); PrintHeader(); return; } if (argc == 6) { op = argv[5]; if (strcmp(op,"/8") && strcmp(op,"/6")) { printf("Unknown options %s\n\n",op); PrintHeader(); return; } } if (CreateFile(input1,input2,input3,op)) printf("OK\n"); } bool CreateFile(char* fn1,char* fn2,char* fn3,char* Op) { FILE *in1, *in2, *in3; Vector<double> X(1000), Y(1000), Z(1000); DWORD NumPoints, NumFE, NumBounds = 0, tmp; Matrix<DWORD> FE(1000,10), Bounds; bool ReadTetraedrData(char*,char*,FILE*,FILE*,Vector<double>&,Vector<double>&,Vector<double>&, Matrix<DWORD>&,DWORD&,DWORD&), ReadCubeData(char*,char*,FILE*,FILE*,Vector<double>&,Vector<double>&,Vector<double>&, Matrix<DWORD>&,DWORD&,DWORD&); void Convert824(Matrix<DWORD>&,DWORD&), Convert1024(Matrix<DWORD>&,DWORD&); if ((in1 = fopen(fn1,"r")) == NULL) { printf("Unable open file %s",fn1); return false; } if ((in2 = fopen(fn2,"r")) == NULL) { printf("Unable open file %s",fn2); return false; } if (CurrentType == BASE3D_10) { if (!ReadTetraedrData(fn1,fn2,in1,in2,X,Y,Z,FE,NumPoints,NumFE)) return false; if (!strcmp(Op,"/8")) { // Create 8*Tetraedr(4) Convert1024(FE,NumFE); } Convert(X,Y,Z,FE,NumFE,Bounds,NumBounds); return!Output(fn3,X,Y,Z,FE,NumPoints,0,NumFE,Bounds,NumBounds); } if (CurrentType == BASE3D_8) { if (!ReadCubeData(fn1,fn2,in1,in2,X,Y,Z,FE,NumPoints,NumFE)) return false; if (!strcmp(Op,"/6")) { // Create 6*Tetraedr(4) Convert824(FE,NumFE); } Convert(X,Y,Z,FE,NumFE,Bounds,NumBounds); return!Output(fn3,X,Y,Z,FE,NumPoints,0,NumFE,Bounds,NumBounds); } return false; } void Convert824(Matrix<DWORD>& FE,DWORD& NumFE) { Matrix<DWORD> nFE(6 * NumFE,4); DWORD data[][4] = { { 0,2,3,6 }, { 4,5,1,7 }, { 0,4,1,3 }, { 6,7,3,4 }, { 1,3,7,4 }, { 0,4,6,3 } }, Current = 0; for (DWORD i = 0; i < NumFE; i++) for (DWORD j = 0; j < 6; j++) { for (DWORD k = 0; k < 4; k++) nFE[Current][k] = FE[i][data[j][k]]; Current++; } CurrentType = BASE3D_4; NumFE = Current; FE = nFE; } void Convert1024(Matrix<DWORD>& FE,DWORD& NumFE) { Matrix<DWORD> nFE(8 * NumFE,4); DWORD data[][4] = { { 3,7,8,9 }, { 0,4,7,6 }, { 2,5,9,6 }, { 7,9,8,6 }, { 4,8,5,1 }, { 4,5,8,6 }, { 7,8,4,6 }, { 8,9,5,6 } }, Current = 0; for (DWORD i = 0; i < NumFE; i++) for (DWORD j = 0; j < 8; j++) { for (DWORD k = 0; k < 4; k++) nFE[Current][k] = FE[i][data[j][k]]; Current++; } CurrentType = BASE3D_4; NumFE = Current; FE = nFE; } bool ReadTetraedrData(char* fn1,char* fn2,FILE* in1,FILE* in2,Vector<double>& X,Vector<double>& Y,Vector<double>& Z, Matrix<DWORD>& FE,DWORD& NumPoints,DWORD& NumFE) { double tx, ty, tz; char TextBuffer[1001]; DWORD Current = 0L, tmp; while (!feof(in1)) { if (fgets(TextBuffer,1000,in1) == NULL) { if (feof(in1)) break; printf("Unable read file %s",fn1); fclose(in1); fclose(in2); return false; } if (sscanf(TextBuffer,"%ld %lf %lf %lf", &NumPoints,&tx,&ty,&tz)!= 4) continue; X[Current] = tx; Y[Current] = ty; Z[Current] = tz; if (++Current == 999) { Vector<double> t1 = X, t2 = Y, t3 = Z; X.ReSize(2 * X.Size()); Y.ReSize(2 * X.Size()); Z.ReSize(2 * X.Size()); for (DWORD i = 0; i < Current; i++) { X[i] = t1[i]; Y[i] = t2[i]; Z[i] = t3[i]; } } if (Current % 100 == 0) printf("Line: %ld\r",Current); } fclose(in1); printf(" \r"); NumPoints = Current; Current = 0L; while (!feof(in2)) { if (fgets(TextBuffer,1000,in2) == NULL) { if (feof(in2)) break; printf("Unable read file %s",fn2); fclose(in2); return false; } if (sscanf(TextBuffer,"%d %d %d %d %d %ld %ld %ld %ld %ld %ld %ld %ld", &tmp,&tmp,&tmp,&tmp,&tmp, &FE[Current][0],&FE[Current][1],&FE[Current][2],&FE[Current][3], &FE[Current][4],&FE[Current][5],&FE[Current][6],&FE[Current][7])!= 13) continue; if (fgets(TextBuffer,1000,in2) == NULL) { printf("Unable read file %s",fn2); fclose(in2); return false; } if (sscanf(TextBuffer,"%ld %ld",&FE[Current][8],&FE[Current][9])!= 2) { printf("Unable read file %s",fn2); fclose(in2); return false; } { if (fabs((tx = 0.5*(X[FE[Current][0] - 1] + X[FE[Current][1] - 1])) - X[FE[Current][4] - 1]) > Eps) X[FE[Current][4] - 1] = tx; if (fabs((ty = 0.5*(Y[FE[Current][0] - 1] + Y[FE[Current][1] - 1])) - Y[FE[Current][4] - 1]) > Eps) Y[FE[Current][4] - 1] = ty; if (fabs((tz = 0.5*(Z[FE[Current][0] - 1] + Z[FE[Current][1] - 1])) - Z[FE[Current][4] - 1]) > Eps) Z[FE[Current][4] - 1] = tz; if (fabs((tx = 0.5*(X[FE[Current][2] - 1] + X[FE[Current][1] - 1])) - X[FE[Current][5] - 1]) > Eps) X[FE[Current][5] - 1] = tx; if (fabs((ty = 0.5*(Y[FE[Current][2] - 1] + Y[FE[Current][1] - 1])) - Y[FE[Current][5] - 1]) > Eps) Y[FE[Current][5] - 1] = ty; if (fabs((tz = 0.5*(Z[FE[Current][2] - 1] + Z[FE[Current][1] - 1])) - Z[FE[Current][5] - 1]) > Eps) Z[FE[Current][5] - 1] = tz; if (fabs((tx = 0.5*(X[FE[Current][0] - 1] + X[FE[Current][2] - 1])) - X[FE[Current][6] - 1]) > Eps) X[FE[Current][6] - 1] = tx; if (fabs((ty = 0.5*(Y[FE[Current][0] - 1] + Y[FE[Current][2] - 1])) - Y[FE[Current][6] - 1]) > Eps) Y[FE[Current][6] - 1] = ty; if (fabs((tz = 0.5*(Z[FE[Current][0] - 1] + Z[FE[Current][2] - 1])) - Z[FE[Current][6] - 1]) > Eps) Z[FE[Current][6] - 1] = tz; if (fabs((tx = 0.5*(X[FE[Current][0] - 1] + X[FE[Current][3] - 1])) - X[FE[Current][7] - 1]) > Eps) X[FE[Current][7] - 1] = tx; if (fabs((ty = 0.5*(Y[FE[Current][0] - 1] + Y[FE[Current][3] - 1])) - Y[FE[Current][7] - 1]) > Eps) Y[FE[Current][7] - 1] = ty; if (fabs((tz = 0.5*(Z[FE[Current][0] - 1] + Z[FE[Current][3] - 1])) - Z[FE[Current][7] - 1]) > Eps) Z[FE[Current][7] - 1] = tz; if (fabs((tx = 0.5*(X[FE[Current][3] - 1] + X[FE[Current][1] - 1])) - X[FE[Current][8] - 1]) > Eps) X[FE[Current][8] - 1] = tx; if (fabs((ty = 0.5*(Y[FE[Current][3] - 1] + Y[FE[Current][1] - 1])) - Y[FE[Current][8] - 1]) > Eps) Y[FE[Current][8] - 1] = ty; if (fabs((tz = 0.5*(Z[FE[Current][3] - 1] + Z[FE[Current][1] - 1])) - Z[FE[Current][8] - 1]) > Eps) Z[FE[Current][8] - 1] = tz; if (fabs((tx = 0.5*(X[FE[Current][3] - 1] + X[FE[Current][2] - 1])) - X[FE[Current][9] - 1]) > Eps) X[FE[Current][9] - 1] = tx; if (fabs((ty = 0.5*(Y[FE[Current][3] - 1] + Y[FE[Current][2] - 1])) - Y[FE[Current][9] - 1]) > Eps) Y[FE[Current][9] - 1] = ty; if (fabs((tz = 0.5*(Z[FE[Current][3] - 1] + Z[FE[Current][2] - 1])) - Z[FE[Current][9] - 1]) > Eps) Z[FE[Current][9] - 1] = tz; } if (++Current == 999) { Matrix<DWORD> t = FE; FE.ReSize(2 * FE.Size1(),10); for (DWORD i = 0; i < Current; i++) for (DWORD j = 0; j < 10; j++) FE[i][j] = t[i][j]; } if (Current % 100 == 0) printf("Line: %ld\r",Current); } NumFE = Current; for (DWORD i = 0; i < NumFE; i++) for (DWORD j = 0; j < 10; j++) FE[i][j]--; printf(" \r"); return true; } bool ReadCubeData(char* fn1,char*fn2,FILE* in1,FILE* in2,Vector<double>& X,Vector<double>& Y,Vector<double>& Z, Matrix<DWORD>& FE,DWORD& NumPoints,DWORD& NumFE) { double tx, ty, tz; char TextBuffer[1001]; DWORD Current = 0L, tmp; while (!feof(in1)) { if (fgets(TextBuffer,1000,in1) == NULL) { if (feof(in1)) break; printf("Unable read file %s",fn1); fclose(in1); fclose(in2); return false; } if (sscanf(TextBuffer,"%ld %lf %lf %lf", &NumPoints,&tx,&ty,&tz)!= 4) continue; X[Current] = tx; Y[Current] = ty; Z[Current] = tz; if (++Current == 999) { Vector<double> t1 = X, t2 = Y, t3 = Z; X.ReSize(2 * X.Size()); Y.ReSize(2 * X.Size()); Z.ReSize(2 * X.Size()); for (DWORD i = 0; i < Current; i++) { X[i] = t1[i]; Y[i] = t2[i]; Z[i] = t3[i]; } } if (Current % 100 == 0) printf("Line: %ld\r",Current); } fclose(in1); printf(" \r"); NumPoints = Current; Current = 0L; while (!feof(in2)) { if (fgets(TextBuffer,1000,in2) == NULL) { if (feof(in2)) break; printf("Unable read file %s",fn2); fclose(in2); return false; } if (sscanf(TextBuffer,"%d %d %d %d %d %ld %ld %ld %ld %ld %ld %ld %ld", &tmp,&tmp,&tmp,&tmp,&tmp, &FE[Current][0],&FE[Current][1],&FE[Current][3],&FE[Current][2], &FE[Current][4],&FE[Current][5],&FE[Current][7],&FE[Current][6])!= 13) continue; if (++Current == 999) { Matrix<DWORD> t = FE; FE.ReSize(2 * FE.Size1(),10); for (DWORD i = 0; i < Current; i++) for (DWORD j = 0; j < 10; j++) FE[i][j] = t[i][j]; } if (Current % 100 == 0) printf("Line: %ld\r",Current);} NumFE = Current; for (DWORD i = 0; i < NumFE; i++) for (DWORD j = 0; j < 10; j++) FE[i][j]--; printf(" \r"); return true;}ПРИЛОЖЕНИЕ 2. Исходный текст программы, реализующей алгоритм компактного хранения и решения СЛАУ высокого порядка. #include "matrix.h" class RVector { private: Vector<double> Buffer; public: RVector(void) {} ~RVector() {} RVector(DWORD Size) { Buffer.ReSize(Size); } RVector(RVector& right) { Buffer = right.Buffer; } RVector(Vector<double>& right) { Buffer = right; } DWORD Size(void) { return Buffer.Size(); } void ReSize(DWORD Size) { Buffer.ReSize(Size); } double& operator [] (DWORD i) { return Buffer[i]; } RVector& operator = (RVector& right) { Buffer = right.Buffer; return *this; } RVector& operator = (Vector<double>& right) { Buffer = right; return *this; } void Sub(RVector&); void Sub(RVector&,double); void Mul(double); void Add(RVector&); friend double Norm(RVector&,RVector&); }; class TSMatrix { private: Vector<double> Right; Vector<double>* Array; Vector<DWORD>* Links; uint Dim; DWORD Size; public: TSMatrix(void) { Size = 0; Dim = 0; Array = NULL; Links = NULL; } TSMatrix(Vector<DWORD>*,DWORD,uint); ~TSMatrix(void) { if (Array) delete [] Array; } Vector<double>& GetRight(void) { return Right; } DWORD GetSize(void) { return Size; } uint GetDim(void) { return Dim; } Vector<double>& GetVector(DWORD i) { return Array[i]; } Vector<DWORD>* GetLinks(void) { return Links; } void SetLinks(Vector<DWORD>* l) { Links = l; } void Add(Matrix<double>&,Vector<DWORD>&); void Add(DWORD I, DWORD L, DWORD J, DWORD K, double v) { DWORD Row = I, Col = L * Links[I].Size() * Dim + Find(I,J) * Dim + K; Array[Row][Col] += v; } void Add(DWORD I, double v) { Right[I] += v; } DWORD Find(DWORD,DWORD); void Restore(Matrix<double>&); void Set(DWORD,DWORD,double,bool); void Set(DWORD Index1,DWORD Index2,double value) { DWORD I = Index1 / Dim, L = Index1 % Dim, J = Index2 / Dim, K = Index2 % Dim, Pos = Find(I,J), Row = I, Col; if (Pos == DWORD(-1)) return; Col = L * Links[I].Size() * Dim + Find(I,J) * Dim + K; Array[Row][Col] = value; } bool Get(DWORD Index1,DWORD Index2,double& value) { DWORD I = Index1 / Dim, L = Index1 % Dim, J = Index2 / Dim, K = Index2 % Dim, Pos = Find(I,J), Row = I, Col; value = 0; if (Pos == DWORD(-1)) return false; Col = L * Links[I].Size() * Dim + Find(I,J) * Dim + K; value = Array[Row][Col]; return true; } void Mul(RVector&,RVector&); double Mul(DWORD,RVector&); void write(ofstream&); void read(ifstream&); }; class RMatrix { private: Vector<double> Buffer; DWORD size; public: RMatrix(DWORD sz) { size = sz; Buffer.ReSize(size*(size + 1)*0.5); } ~RMatrix() {} DWORD Size(void) { return size; } double& Get(DWORD i,DWORD j) { return Buffer[(2*size + 1 - i)*0.5*i + j - i]; } }; //************************ #include "smatrix.h" double Norm(RVector& Left,RVector& Right) { double Ret = 0; for (DWORD i = 0; i < Left.Size(); i++) Ret += Left[i] * Right[i]; return Ret; } void RVector::Sub(RVector& Right) { for (DWORD i = 0; i < Size(); i++) (*this)[i] -= Right[i]; } void RVector::Add(RVector& Right) { for (DWORD i = 0; i < Size(); i++) (*this)[i] += Right[i]; } void RVector::Mul(double koff) { for (DWORD i = 0; i < Size(); i++) (*this)[i] *= koff; } void RVector::Sub(RVector& Right,double koff) { for (DWORD i = 0; i < Size(); i++) (*this)[i] -= Right[i]*koff; } TSMatrix::TSMatrix(Vector<DWORD>* links, DWORD size, uint dim) { Dim = dim; Links = links; Size = size; Right.ReSize(Dim * Size); Array = new Vector<double>[Size]; for (DWORD i = 0; i < Size; i++) Array[i].ReSize(Links[i].Size() * Dim * Dim); } void TSMatrix::Add(Matrix<double>& FEMatr,Vector<DWORD>& FE) { double Res; DWORD RRow; for (DWORD i = 0L; i < FE.Size(); i++) for (DWORD l = 0L; l < Dim; l++) for (DWORD j = 0L; j < FE.Size(); j++) for (DWORD k = 0L; k < Dim; k++) { Res = FEMatr[i * Dim + l][j * Dim + k]; if (Res) Add(FE[i],l,FE[j],k,Res); } for (DWORD i = 0L; i < FE.Size(); i++) for (DWORD l = 0L; l < Dim; l++) { RRow = FE[UINT(i % (FE.Size()))] * Dim + l; Res = FEMatr[i * Dim + l][FEMatr.Size1()]; if (Res) Add(RRow,Res); } } DWORD TSMatrix::Find(DWORD I,DWORD J) { DWORD i; for (i = 0; i < Links[I].Size(); i++) if (Links[I][i] == J) return i; return DWORD(-1); } void TSMatrix::Restore(Matrix<double>& Matr) { DWORD i, j, NRow, NPoint, NLink, Pos; Matr.ReSize(Size * Dim,Size * Dim + 1); for (i = 0; i < Size; i++) for (j = 0; j < Array[i].Size(); j++) { NRow = j / (Array[i].Size() / Dim); // Number of row NPoint = (j - NRow * (Array[i].Size() / Dim)) / Dim; // Number of points NLink = j % Dim; // Number of link Pos = Links[i][NPoint]; Matr[i * Dim + NRow][Pos * Dim + NLink] = Array[i][j]; } for (i = 0; i < Right.Size(); i++) Matr[i][Matr.Size1()] = Right[i]; } void TSMatrix::Set(DWORD Index,DWORD Position,double Value,bool Case) { DWORD Row = Index, Col = Position * Links[Index].Size() * Dim + Find(Index,Index) * Dim + Position, i; double koff = Array[Row][Col], val; if (!Case) Right[Dim * Index + Position] = Value; else { Right[Index * Dim + Position] = Value * koff; for (i = 0L; i < Size * Dim; i++) if (i!= Index * Dim + Position) { Set(Index * Dim + Position,i,0); Set(i,Index * Dim + Position,0); if (Get(i,Index * Dim + Position,val)) Right[i] -= val * Value; } } } void TSMatrix::Mul(RVector& Arr,RVector& Res) { DWORD i, j, NRow, NPoint, NLink, Pos; Res.ReSize(Arr.Size()); for (i = 0; i < Size; i++) for (j = 0; j < Array[i].Size(); j++) { NRow = j / (Array[i].Size() / Dim); NPoint = (j - NRow * (Array[i].Size() / Dim)) / Dim; NLink = j % Dim; Pos = Links[i][NPoint]; Res[i * Dim + NRow] += Arr[Pos * Dim + NLink] * Array[i][j]; } } double TSMatrix::Mul(DWORD Index,RVector& Arr) { DWORD j, I = Index / Dim, L = Index % Dim, Start = L * (Array[I].Size() / Dim), Stop = Start + (Array[I].Size() / Dim), NRow, NPoint, NLink, Pos; double Res = 0; for (j = Start; j < Stop; j++) { NRow = j / (Array[I].Size() / Dim); NPoint = (j - NRow * (Array[I].Size() / Dim)) / Dim; NLink = j % Dim; Pos = Links[I][NPoint]; Res += Arr[Pos * Dim + NLink] * Array[I][j]; } return Res; } void TSMatrix::write(ofstream& Out) { DWORD ColSize; Out.write((char*)&(Dim),sizeof(DWORD)); Out.write((char*)&(Size),sizeof(DWORD)); for (DWORD i = 0; i < Size; i++) { ColSize = Array[i].Size(); Out.write((char*)&(ColSize),sizeof(DWORD)); for (DWORD j = 0; j < ColSize; j++) Out.write((char*)&(Array[i][j]),sizeof(double)); } for (DWORD i = 0; i < Size * Dim; i++) Out.write((char*)&(Right[i]),sizeof(double)); } void TSMatrix::read(ifstream& In) { DWORD ColSize; In.read((char*)&(Dim),sizeof(DWORD)); In.read((char*)&(Size),sizeof(DWORD)); if (Array) delete [] Array; Array = new Vector<double>[Size]; Right.ReSize(Size * Dim); for (DWORD i = 0; i < Size; i++) { In.read((char*)&(ColSize),sizeof(DWORD)); Array[i].ReSize(ColSize); for (DWORD j = 0; j < ColSize; j++) In.read((char*)&(Array[i][j]),sizeof(double)); } for (DWORD i = 0; i < Size * Dim; i++) In.read((char*)&(Right[i]),sizeof(double)); } Список литературы Зенкевич О., Морган К. Конечные методы и аппроксимация // М.: Мир, 1980 Зенкевич О., Метод конечных элементов // М.: Мир., 1975 Стрэнг Г., Фикс Дж. Теория метода конечных элементов // М.: Мир, 1977 Бахвалов Н.С.,Жидков Н.П., Кобельков Г.М. Численные методы // М.: наука, 1987 Воеводин В.В., Кузнецов Ю.А. Матрицы и вычисления // М.:Наука, 1984 Бахвалов Н.С. Численные методы // М.: Наука, 1975 Годунов С.К. Решение систем линейных уравнений // Новосибирск: Наука, 1980 Гоменюк С.И., Толок В.А. Инструментальная система анализа задач механики деформируемого твердого тела // Приднiпровський науковий вiсник – 1997. – №4. F.G. Gustavson, “Some basic techniques for solving sparse matrix algorithms”, // editer by D.J. Rose and R.A.Willoughby, Plenum Press, New York, 1972 А.Джордж, Дж. Лиу, Численное решение больших разреженных систем уравнений // Москва, Мир, 1984 D.J. Rose, “A graph theoretic study of the numerical solution of sparse positive definite system of linear equations” // New York, Academic Press, 1972 Мосаковский В.И., Гудрамович В.С., Макеев Е.М., Контактные задачи теории оболочек и стержней // М.:”Машиностроение”, 1978
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|