double solve_vs_exact(Options options, Mesh* mesh, std::vector<Element2D*> &elements) { PetscFunctionBegin; // Setup values. int it = 0; double time = 0.0; double timeStep = options.TimeStep(); double duration = options.Duration(); if(options.SaveMovie()) mesh->setUpMovie(options.OutputMovieFile()); // Over-allocate matrices to avoid re-allocations. int max_dims = 3; int int_pnts = elements[0]->NumberIntegrationPoints(); Eigen::MatrixXd f(int_pnts, max_dims); Eigen::MatrixXd u(int_pnts, max_dims); Eigen::MatrixXd ku(int_pnts, max_dims); Eigen::MatrixXd fMinusKu(int_pnts, max_dims); Eigen::MatrixXd fMinusKu_boundary(int_pnts, max_dims); double max_error = 0.0; while (time < duration) { // Collect all global fields to the local partitions. for (auto &field : elements[0]->PullElementalFields()) { mesh->checkOutField(field); } // Zero all fields to which we will sum. for (auto &field : elements[0]->PushElementalFields()) { mesh->zeroFields(field); } for (auto &element : elements) { // Get fields on element, store in successive rows. (e.g., // "u" for acoustic, "ux, uz" for elastic) int fitr = 0; for (auto &field : element->PullElementalFields()) { u.col(fitr) = mesh->getFieldOnElement(field, element->Number(), element->ElementClosure()); fitr++; } double element_error = element->checkTest(mesh, options, u.block(0,0,int_pnts,fitr), time); if(element_error > max_error) { max_error = element_error; } // Compute stiffness, only passing those rows which are occupied. ku.block(0,0,int_pnts,fitr) = element->computeStiffnessTerm( u.block(0,0,int_pnts,fitr)); // Compute acceleration. fMinusKu.block(0,0,int_pnts,fitr) = -1 * ku.block(0,0,int_pnts,fitr).array(); // Sum fields into local partition. fitr = 0; for (auto &field : element->PushElementalFields()) { mesh->addFieldFromElement(field, element->Number(), element->ElementClosure(), fMinusKu.col(fitr)); fitr++; } } // boundary condition happens after full Ku for( auto &element : elements) { // we can now apply boundary conditions (after fields are set) if(element->OnBoundary()) { // apply boundary condition element->applyBoundaryConditions(mesh, options, "a"); } } // Sum fields into global partitions. for (auto &field : elements[0]->PushElementalFields()) { mesh->checkInFieldBegin(field); mesh->checkInFieldEnd(field); } // Take a time step. mesh->applyInverseMassMatrix(); mesh->advanceField(timeStep); if(options.SaveMovie() && (it%options.SaveFrameEvery()==0 || it == 0) ) { // GlobalFields[0] == "u" for acoustic and == "ux" for elastic mesh->saveFrame(mesh->GlobalFields()[0], it); // mesh->setLocalFieldToGlobal("u_exact"); // mesh->saveFrame("u_exact", it); if(max_error > 5) { std::cerr << "ERROR: Solution blowing up!\n"; exit(1); } PRINT_ROOT() << "TIME: " << time; } it++; time += timeStep; } PRINT_ROOT() << "Max Error @ T=end: " << max_error << std::endl; if(options.SaveMovie()) mesh->finalizeMovie(); return max_error; }