QList<SolutionArray *> SolutionAgros::solveSolutioArray(Hermes::vector<EssentialBCs> bcs) { QTime time; // solution agros array QList<SolutionArray *> solutionArrayList; // load the mesh file mesh = readMeshFromFile(tempProblemFileName() + ".mesh"); refineMesh(mesh, true, true); // create an H1 space Hermes::vector<Space *> space; // create hermes solution array Hermes::vector<Solution *> solution; // create reference solution Hermes::vector<Solution *> solutionReference; // projection norms Hermes::vector<ProjNormType> projNormType; // prepare selector Hermes::vector<RefinementSelectors::Selector *> selector; // error marker bool isError = false; RefinementSelectors::Selector *select = NULL; switch (adaptivityType) { case AdaptivityType_H: select = new RefinementSelectors::HOnlySelector(); break; case AdaptivityType_P: select = new RefinementSelectors::H1ProjBasedSelector(RefinementSelectors::H2D_P_ANISO, Util::config()->convExp, H2DRS_DEFAULT_ORDER); break; case AdaptivityType_HP: select = new RefinementSelectors::H1ProjBasedSelector(RefinementSelectors::H2D_HP_ANISO, Util::config()->convExp, H2DRS_DEFAULT_ORDER); break; } for (int i = 0; i < numberOfSolution; i++) { space.push_back(new H1Space(mesh, &bcs[i], polynomialOrder)); // set order by element for (int j = 0; j < Util::scene()->labels.count(); j++) if (Util::scene()->labels[j]->material != Util::scene()->materials[0]) space.at(i)->set_uniform_order(Util::scene()->labels[j]->polynomialOrder > 0 ? Util::scene()->labels[j]->polynomialOrder : polynomialOrder, QString::number(j).toStdString()); // solution agros array solution.push_back(new Solution()); if (adaptivityType != AdaptivityType_None) { // add norm projNormType.push_back(Util::config()->projNormType); // add refinement selector selector.push_back(select); // reference solution solutionReference.push_back(new Solution()); } } // check for DOFs if (Space::get_num_dofs(space) == 0) { m_progressItemSolve->emitMessage(QObject::tr("DOF is zero"), true); } else { for (int i = 0; i < numberOfSolution; i++) { // transient if (analysisType == AnalysisType_Transient) { // constant initial solution solution.at(i)->set_const(mesh, initialCondition); solutionArrayList.append(solutionArray(solution.at(i))); } // nonlinear if ((linearityType != LinearityType_Linear) && (analysisType != AnalysisType_Transient)) { solution.at(i)->set_const(mesh, 0.0); } } actualTime = 0.0; // update time function Util::scene()->problemInfo()->hermes()->updateTimeFunctions(actualTime); m_wf->set_current_time(actualTime); m_wf->solution = solution; m_wf->delete_all(); m_wf->registerForms(); // emit message if (adaptivityType != AdaptivityType_None) m_progressItemSolve->emitMessage(QObject::tr("Adaptivity type: %1").arg(adaptivityTypeString(adaptivityType)), false); double error = 0.0; // solution int maxAdaptivitySteps = (adaptivityType == AdaptivityType_None) ? 1 : adaptivitySteps; int actualAdaptivitySteps = -1; for (int i = 0; i<maxAdaptivitySteps; i++) { // set up the solver, matrix, and rhs according to the solver selection. SparseMatrix *matrix = create_matrix(matrixSolver); Vector *rhs = create_vector(matrixSolver); Solver *solver = create_linear_solver(matrixSolver, matrix, rhs); if (adaptivityType == AdaptivityType_None) { if (analysisType != AnalysisType_Transient) solve(space, solution, solver, matrix, rhs); } else { // construct globally refined reference mesh and setup reference space. Hermes::vector<Space *> spaceReference = *Space::construct_refined_spaces(space); // assemble reference problem. solve(spaceReference, solutionReference, solver, matrix, rhs); if (!isError) { // project the fine mesh solution onto the coarse mesh. OGProjection::project_global(space, solutionReference, solution, matrixSolver); // Calculate element errors and total error estimate. Adapt adaptivity(space, projNormType); // Calculate error estimate for each solution component and the total error estimate. error = adaptivity.calc_err_est(solution, solutionReference) * 100; // emit signal m_progressItemSolve->emitMessage(QObject::tr("Adaptivity rel. error (step: %2/%3, DOFs: %4/%5): %1%"). arg(error, 0, 'f', 3). arg(i + 1). arg(maxAdaptivitySteps). arg(Space::get_num_dofs(space)). arg(Space::get_num_dofs(spaceReference)), false, 1); // add error to the list m_progressItemSolve->addAdaptivityError(error, Space::get_num_dofs(space)); if (error < adaptivityTolerance || Space::get_num_dofs(space) >= adaptivityMaxDOFs) { break; } if (i != maxAdaptivitySteps-1) adaptivity.adapt(selector, Util::config()->threshold, Util::config()->strategy, Util::config()->meshRegularity); actualAdaptivitySteps = i+1; } if (m_progressItemSolve->isCanceled()) { isError = true; break; } // delete reference space for (int i = 0; i < spaceReference.size(); i++) { delete spaceReference.at(i)->get_mesh(); delete spaceReference.at(i); } spaceReference.clear(); } // clean up. delete solver; delete matrix; delete rhs; } // delete reference solution for (int i = 0; i < solutionReference.size(); i++) delete solutionReference.at(i); solutionReference.clear(); // delete selector if (select) delete select; selector.clear(); // timesteps if (!isError) { SparseMatrix *matrix = NULL; Vector *rhs = NULL; Solver *solver = NULL; // allocate dp for transient solution DiscreteProblem *dpTran = NULL; if (analysisType == AnalysisType_Transient) { // set up the solver, matrix, and rhs according to the solver selection. matrix = create_matrix(matrixSolver); rhs = create_vector(matrixSolver); solver = create_linear_solver(matrixSolver, matrix, rhs); // solver->set_factorization_scheme(HERMES_REUSE_FACTORIZATION_COMPLETELY); dpTran = new DiscreteProblem(m_wf, space, true); } int timesteps = (analysisType == AnalysisType_Transient) ? floor(timeTotal/timeStep) : 1; for (int n = 0; n<timesteps; n++) { // set actual time actualTime = (n+1)*timeStep; // update essential bc values Space::update_essential_bc_values(space, actualTime); // update timedep values Util::scene()->problemInfo()->hermes()->updateTimeFunctions(actualTime); m_wf->set_current_time(actualTime); m_wf->delete_all(); m_wf->registerForms(); // transient if ((timesteps > 1) && (linearityType == LinearityType_Linear)) isError = !solveLinear(dpTran, space, solution, solver, matrix, rhs); if ((timesteps > 1) && (linearityType != LinearityType_Linear)) isError = !solve(space, solution, solver, matrix, rhs); // output for (int i = 0; i < numberOfSolution; i++) { solutionArrayList.append(solutionArray(solution.at(i), space.at(i), error, actualAdaptivitySteps, (n+1)*timeStep)); } if (analysisType == AnalysisType_Transient) m_progressItemSolve->emitMessage(QObject::tr("Transient time step (%1/%2): %3 s"). arg(n+1). arg(timesteps). arg(actualTime, 0, 'e', 2), false, n+2); if (m_progressItemSolve->isCanceled()) { isError = true; break; } } // clean up if (solver) delete solver; if (matrix) delete matrix; if (rhs) delete rhs; if (dpTran) delete dpTran; } } // delete mesh delete mesh; // delete space for (unsigned int i = 0; i < space.size(); i++) { // delete space.at(i)->get_mesh(); delete space.at(i); } space.clear(); // delete last solution for (unsigned int i = 0; i < solution.size(); i++) delete solution.at(i); solution.clear(); if (isError) { for (int i = 0; i < solutionArrayList.count(); i++) delete solutionArrayList.at(i); solutionArrayList.clear(); } return solutionArrayList; }
bool SolutionAgros::solve(Hermes::vector<Space *> space, Hermes::vector<Solution *> solution, Solver *solver, SparseMatrix *matrix, Vector *rhs) { bool isError = false; if (linearityType == LinearityType_Linear) { DiscreteProblem dpLin(m_wf, space, true); isError = !solveLinear(&dpLin, space, solution, solver, matrix, rhs); // dump matrix FILE *f = fopen(QString(tempProblemDir() + "/matrix.m").toStdString().c_str(), "w"); matrix->dump(f, QString("mat").toStdString().c_str(), DF_MATRIX_MARKET); fclose(f); return !isError; } if (linearityType == LinearityType_Picard) { /* DiscreteProblem dpNonlinPicard(m_wf, space, true); // create Picard solution Hermes::vector<Solution *> solutionPicard; for (int i = 0; i < numberOfSolution; i++) solutionPicard.push_back(new Solution()); // perform the Picard's iteration for (int i = 0; i < linearityNonlinearSteps; i++) { isError = !solveLinear(&dpNonlinPicard, space, solutionPicard, solver, matrix, rhs, false); ProjNormType projNormTypeTMP = HERMES_H1_NORM; // ProjNormType projNormTypeTMP = HERMES_L2_NORM; // calc error double *val_sol, *val_solpic, *val_diff; double error = 0.0; for (int i = 0; i < numberOfSolution; i++) { error += calc_abs_error(solution.at(i), solutionPicard.at(i), projNormTypeTMP) * 100.0 / calc_norm(&sln_new, HERMES_H1_NORM) * 100; val_sol = solution.at(i)->get_fn_values(); val_solpic = solutionPicard.at(i)->get_fn_values(); val_diff = new double[Space::get_num_dofs(space)]; for (int j = 0; j < Space::get_num_dofs(space); j++) val_diff[j] = val_solpic[j]; // + 0.5 * (val_sol[j] - val_solpic[j]); } // emit signal m_progressItemSolve->emitMessage(QObject::tr("Picards method rel. error (%2/%3): %1%"). arg(error, 0, 'f', 5). arg(i + 1). arg(linearityNonlinearSteps), false, 1); // add error to the list m_progressItemSolve->addNonlinearityError(error); if (error < linearityNonlinearTolerance) { // FIXME - clean up break; } // copy solution for (int i = 0; i < numberOfSolution; i++) { // if (error > 100.0) // solution.at(i)->multiply(0.5); // else solution.at(i)->copy(solutionPicard.at(i)); } // Solution::vector_to_solutions(val_solpic, space, solution); // Solution::vector_to_solutions(solutionPicard., space, solution); } for (int i = 0; i < solutionPicard.size(); i++) delete solutionPicard.at(i); solutionPicard.clear(); return !isError; */ } if (linearityType == LinearityType_Newton) { /* // project the initial condition on the FE space to obtain initial // coefficient vector for the Newton's method. info("Projecting to obtain initial vector for the Newton's method."); double *coeff_vec = new double[Space::get_num_dofs(space)]; OGProjection::project_global(space, solution.at(0), coeff_vec, Util::scene()->problemInfo()->matrixSolver); DiscreteProblem dpNonlinNewton(wf, space, false); // The Newton's loop. double damping_coeff = 1.0; // perform the Picard's iteration for (int i = 0; i < linearityNonlinearSteps; i++) { // assemble the Jacobian matrix and residual vector. dpNonlinNewton.assemble(coeff_vec, matrix, rhs, false); // Multiply the residual vector with -1 since the matrix // equation reads J(Y^n) \deltaY^{n+1} = -F(Y^n). rhs->change_sign(); // Calculate the l2-norm of residual vector double error = get_l2_norm(rhs); // emit signal m_progressItemSolve->emitMessage(QObject::tr("Newton’s method rel. error (%2/%3): %1") .arg(error, 0, 'f', 5) .arg(i) .arg(linearityNonlinearSteps), false, 1); // add error to the list m_progressItemSolve->addNonlinearityError(error); // if residual norm is within tolerance, or the maximum number of iteration has been reached, then quit. if (error < linearityNonlinearTolerance) break; // Solve the linear system. isError = solver->solve(); if (!isError) error("Matrix solver failed.\n"); // add \deltaY^{n+1} to Y^n. for (int j = 0; j < Space::get_num_dofs(space); j++) coeff_vec[j] += damping_coeff * solver->get_solution()[j]; } Solution::vector_to_solutions(coeff_vec, space, solution); delete [] coeff_vec; */ } }
bool solveLinear(const DMatZZpFFPACK& A, const DMatZZpFFPACK& B, DMatZZpFFPACK& X) { return solveLinear(A, B, true, X, false); }