int
SPRNodalRecoveryModel :: recoverValues(Set elementSet, InternalStateType type, TimeStep *tStep)
{
    int nnodes = domain->giveNumberOfDofManagers();
    IntArray regionNodalNumbers(nnodes);
    IntArray patchElems, dofManToDetermine, pap;
    FloatMatrix a;
    FloatArray dofManValues;
    IntArray dofManPatchCount;

    if ( ( this->valType == type ) && ( this->stateCounter == tStep->giveSolutionStateCounter() ) ) {
        return 1;
    }

#ifdef __PARALLEL_MODE
    this->initCommMaps();
#endif

    // clear nodal table
    this->clear();

    int regionValSize;
    int regionDofMans;


    regionValSize = 0;
    // loop over elements and determine local region node numbering and determine and check nodal values size
    if ( this->initRegionNodeNumbering(regionNodalNumbers, regionDofMans, elementSet) == 0 ) {
        return 0;
    }

    SPRPatchType regType = this->determinePatchType(elementSet);

    dofManPatchCount.resize(regionDofMans);
    dofManPatchCount.zero();


    //pap = patch assembly points
    this->determinePatchAssemblyPoints(pap, regType, elementSet);

    int npap = pap.giveSize();
    for ( int ipap = 1; ipap <= npap; ipap++ ) {
        int papNumber = pap.at(ipap);
        int oldSize = regionValSize;

        this->initPatch(patchElems, dofManToDetermine, pap, papNumber, elementSet);
        this->computePatch(a, patchElems, regionValSize, regType, type, tStep);
        if ( oldSize == 0 ) {
            dofManValues.resize(regionDofMans * regionValSize);
            dofManValues.zero();
        }
        this->determineValuesFromPatch(dofManValues, dofManPatchCount, regionNodalNumbers,
                                       dofManToDetermine, a, regType);
    }

#ifdef __PARALLEL_MODE
    this->exchangeDofManValues(dofManValues, dofManPatchCount, regionNodalNumbers, regionValSize);
#endif

    // average  recovered values of active region
    bool abortFlag = false;
    for ( int i = 1; i <= nnodes; i++ ) {
        if ( regionNodalNumbers.at(i) &&
            ( ( domain->giveDofManager(i)->giveParallelMode() == DofManager_local ) ||
             ( domain->giveDofManager(i)->giveParallelMode() == DofManager_shared ) ) ) {
            int eq = ( regionNodalNumbers.at(i) - 1 ) * regionValSize;
            if ( dofManPatchCount.at( regionNodalNumbers.at(i) ) ) {
                for ( int j = 1; j <= regionValSize; j++ ) {
                    dofManValues.at(eq + j) /= dofManPatchCount.at( regionNodalNumbers.at(i) );
                }
            } else {
                OOFEM_WARNING("values of %s in dofmanager %d undetermined", __InternalStateTypeToString(type), i);

                for ( int j = 1; j <= regionValSize; j++ ) {
                    dofManValues.at(eq + j) = 0.0;
                }
                //abortFlag = true;
            }
        }

        if ( abortFlag ) {
            abort();
        }

        // update recovered values
        this->updateRegionRecoveredValues(regionNodalNumbers, regionValSize, dofManValues);
    }

    this->valType = type;
    this->stateCounter = tStep->giveSolutionStateCounter();
    return 1;
}
int
NodalAveragingRecoveryModel :: recoverValues(InternalStateType type, TimeStep *tStep)
{
    int ireg, nregions = this->giveNumberOfVirtualRegions();
    int ielem, nelem = domain->giveNumberOfElements();
    int inode, nnodes = domain->giveNumberOfDofManagers();
    int elemNodes;
    int regionValSize;
    int elementNode, node;
    int regionDofMans;
    int i, neq, eq;
    Element *element;
    NodalAveragingRecoveryModelInterface *interface;
    IntArray skipRegionMap(nregions), regionRecSize(nregions);
    IntArray regionNodalNumbers(nnodes);
    IntArray regionDofMansConnectivity;
    FloatArray lhs, val;


    if ( ( this->valType == type ) && ( this->stateCounter == tStep->giveSolutionStateCounter() ) ) {
        return 1;
    }

#ifdef __PARALLEL_MODE
    bool parallel = this->domain->giveEngngModel()->isParallel();
    if (parallel)
        this->initCommMaps();
#endif

    // clear nodal table
    this->clear();

    // init region table indicating regions to skip
    this->initRegionMap(skipRegionMap, regionRecSize, type);

#ifdef __PARALLEL_MODE
    if (parallel) {
        // synchronize skipRegionMap over all cpus
        IntArray temp_skipRegionMap(skipRegionMap);
        MPI_Allreduce(temp_skipRegionMap.givePointer(), skipRegionMap.givePointer(), nregions, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
    }
#endif

    // loop over regions
    for ( ireg = 1; ireg <= nregions; ireg++ ) {
        // skip regions
        if ( skipRegionMap.at(ireg) ) {
            continue;
        }

        // loop over elements and determine local region node numbering and determine and check nodal values size
        if ( this->initRegionNodeNumbering(regionNodalNumbers, regionDofMans, ireg) == 0 ) {
            break;
        }

        regionValSize = regionRecSize.at(ireg);
        neq = regionDofMans * regionValSize;
        lhs.resize(neq);
        lhs.zero();
        regionDofMansConnectivity.resize(regionDofMans);
        regionDofMansConnectivity.zero();

        // assemble element contributions
        for ( ielem = 1; ielem <= nelem; ielem++ ) {
            element = domain->giveElement(ielem);

#ifdef __PARALLEL_MODE
            if ( element->giveParallelMode() != Element_local ) {
                continue;
            }

#endif
            if ( this->giveElementVirtualRegionNumber(ielem) != ireg ) {
                continue;
            }

            // If an element doesn't implement the interface, it is ignored.
            if ( ( interface = ( NodalAveragingRecoveryModelInterface * )
                               element->giveInterface(NodalAveragingRecoveryModelInterfaceType) ) == NULL ) {
                //abort();
                continue;
            }

            elemNodes = element->giveNumberOfDofManagers();
            // ask element contributions
            for ( elementNode = 1; elementNode <= elemNodes; elementNode++ ) {
                node = element->giveDofManager(elementNode)->giveNumber();
                interface->NodalAveragingRecoveryMI_computeNodalValue(val, elementNode, type, tStep);
                // if the element cannot evaluate this variable, it is ignored
                if ( val.giveSize() == 0 ) {
                    continue;
                }
                eq = ( regionNodalNumbers.at(node) - 1 ) * regionValSize;
                for ( i = 1; i <= regionValSize; i++ ) {
                    lhs.at(eq + i) += val.at(i);
                }

                regionDofMansConnectivity.at( regionNodalNumbers.at(node) )++;
            }
        } // end assemble element contributions

#ifdef __PARALLEL_MODE
        if (parallel)
            this->exchangeDofManValues(ireg, lhs, regionDofMansConnectivity, regionNodalNumbers, regionValSize);
#endif

        // solve for recovered values of active region
        for ( inode = 1; inode <= nnodes; inode++ ) {
            if ( regionNodalNumbers.at(inode) ) {
                eq = ( regionNodalNumbers.at(inode) - 1 ) * regionValSize;
                for ( i = 1; i <= regionValSize; i++ ) {
                    if ( regionDofMansConnectivity.at( regionNodalNumbers.at(inode) ) > 0 ) {
                        lhs.at(eq + i) /= regionDofMansConnectivity.at( regionNodalNumbers.at(inode) );
                    } else {
                        OOFEM_WARNING2("NodalAveragingRecoveryModel::recoverValues: values of dofmanager %d undetermined", inode);
                        lhs.at(eq + i) = 0.0;
                    }
                }
            }
        }

        // update recovered values
        this->updateRegionRecoveredValues(ireg, regionNodalNumbers, regionValSize, lhs);
    } // end loop over regions

    this->valType = type;
    this->stateCounter = tStep->giveSolutionStateCounter();
    return 1;
}
int
NodalAveragingRecoveryModel :: recoverValues(Set elementSet, InternalStateType type, TimeStep *tStep)
{
    int nnodes = domain->giveNumberOfDofManagers();
    IntArray regionNodalNumbers(nnodes);
    IntArray regionDofMansConnectivity;
    FloatArray lhs, val;


    if ( ( this->valType == type ) && ( this->stateCounter == tStep->giveSolutionStateCounter() ) ) {
        return 1;
    }

#ifdef __PARALLEL_MODE
    bool parallel = this->domain->giveEngngModel()->isParallel();
    if ( parallel ) {
        this->initCommMaps();
    }
#endif

    // clear nodal table
    this->clear();

    int regionValSize = 0;
    int regionDofMans;

    // loop over elements and determine local region node numbering and determine and check nodal values size
    if ( this->initRegionNodeNumbering(regionNodalNumbers, regionDofMans, elementSet) == 0 ) {
        return 0;
    }

    regionDofMansConnectivity.resize(regionDofMans);
    regionDofMansConnectivity.zero();

    IntArray elements = elementSet.giveElementList();
    // assemble element contributions
    for ( int i = 1; i <= elements.giveSize(); i++ ) {
        int ielem = elements.at(i);
        NodalAveragingRecoveryModelInterface *interface;
        Element *element = domain->giveElement(ielem);

        if ( element->giveParallelMode() != Element_local ) {
            continue;
        }

        // If an element doesn't implement the interface, it is ignored.
        if ( ( interface = static_cast< NodalAveragingRecoveryModelInterface * >
                           ( element->giveInterface(NodalAveragingRecoveryModelInterfaceType) ) ) == NULL ) {
            //abort();
            continue;
        }

        int elemNodes = element->giveNumberOfDofManagers();
        // ask element contributions
        for ( int elementNode = 1; elementNode <= elemNodes; elementNode++ ) {
            int node = element->giveDofManager(elementNode)->giveNumber();
            interface->NodalAveragingRecoveryMI_computeNodalValue(val, elementNode, type, tStep);
            // if the element cannot evaluate this variable, it is ignored
            if ( val.giveSize() == 0 ) {
                continue;
            } else if ( regionValSize == 0 ) {
                regionValSize = val.giveSize();
                lhs.resize(regionDofMans * regionValSize);
                lhs.zero();
            } else if ( val.giveSize() != regionValSize ) {
                OOFEM_LOG_RELEVANT("NodalAveragingRecoveryModel :: size mismatch for InternalStateType %s, ignoring all elements that doesn't use the size %d\n", __InternalStateTypeToString(type), regionValSize);
                continue;
            }
            int eq = ( regionNodalNumbers.at(node) - 1 ) * regionValSize;
            for ( int j = 1; j <= regionValSize; j++ ) {
                lhs.at(eq + j) += val.at(j);
            }

            regionDofMansConnectivity.at( regionNodalNumbers.at(node) )++;
        }
    } // end assemble element contributions

#ifdef __PARALLEL_MODE
    if ( parallel ) {
        this->exchangeDofManValues(lhs, regionDofMansConnectivity, regionNodalNumbers, regionValSize);
    }
#endif

    // solve for recovered values of active region
    for ( int inode = 1; inode <= nnodes; inode++ ) {
        if ( regionNodalNumbers.at(inode) ) {
            int eq = ( regionNodalNumbers.at(inode) - 1 ) * regionValSize;
            for ( int i = 1; i <= regionValSize; i++ ) {
                if ( regionDofMansConnectivity.at( regionNodalNumbers.at(inode) ) > 0 ) {
                    lhs.at(eq + i) /= regionDofMansConnectivity.at( regionNodalNumbers.at(inode) );
                } else {
                    OOFEM_WARNING("values of dofmanager %d undetermined", inode);
                    lhs.at(eq + i) = 0.0;
                }
            }
        }
    }

    // update recovered values
    this->updateRegionRecoveredValues(regionNodalNumbers, regionValSize, lhs);

    this->valType = type;
    this->stateCounter = tStep->giveSolutionStateCounter();
    return 1;
}