示例#1
0
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;
}