Topic: Dof groups and convergence checks

There is a fairly messy code to deal with optional dof groups when checking convergence.
Of course, this is a good idea, but (!)
1. Does it really need to be an option how to group them?
2. The ebenorm isn't split into different dof groups. This is a serious problem.

For issue 1;
I suggest just grouping by dofid.

For issue 2;
Replace the double ebenorm by a floatarray ebenorm. Separate value for each dof.
For checking convergence, just compute the split the residual like;
error = sqrt( norm_Vu / ebeNorm_Vu + norm_Pf/ebeNorm_Pf  + .... )

Re: Dof groups and convergence checks

I'm planning to do these changes quite soon.
In order to implement this, we need to know how to what dof-group each entry in the characteristic vector belongs.

We could use Element::giveDofManDofIDMask() to determine this, however, if any node has slave dofs or any local coordinate systems this approach breaks down.
We have to work on the transformed vectors (i.e. on the actual master dofs, no slave dofs).

I purpose the following,

    for ( int i = 1; i <= nelem; i++ ) {
        element = domain->giveElement(i);

        element->giveLocationArray(loc, eid, s);
        this->giveElementCharacteristicVector(charVec, i, type, mode, tStep, domain);
        if ( charVec.isNotEmpty() ) {
            if ( element->giveRotationMatrix(R, eid) ) {
                charVec.rotatedWith(R, 't');
            }

            answer.assemble(charVec, loc);
            ///////////////////////////////////////////////////////// Compute the squared norm for each dofid;
            for ( int j = 1; j <= charVec.giveSize(); j++) {
                int dofid = domain->giveDofID(loc.at(j));
                double val = charVec.at(j);
                norms.at(dofid) += val*val;
            }
            //////////////////////////////////////////////////////// Old approach, just a single norm to compute;
            //norm += charVec.computeSquaredNorm();
        }
    }

where we have introduced some function
"DofIDItem Domain::giveDofID(int eqn);"
which maps equation number to dof id.
Presumably this function would lie in the Domain, or possibly in the EquationNumberingScheme

This approach, based on the equations would of course now

3

Re: Dof groups and convergence checks

The proposed Domain::giveDofID(int eqn) should be provided by Numbering Scheme. But what about not introducing Domain::giveDofID(int eqn) and performing rather the loop after the assembly over DofManagers and their DOFs? Can save building the equation->dofID mapping and all related stuff (updating, when numbering changes, etc).

Re: Dof groups and convergence checks

If i understand you correctly, you are suggesting looping over the fully assembled vector, which is exactly what NRSolver does already.
We of course need to do that as well, but unfortunately, we need to element-internal forces to normalize with (this is just a split-up ebenorm). In the case of no external forces, the assembled internal forces are always zero at equilibrium.
I can't see any way around it. In the case of a single node

 F1  <--- o ---> F2

we need to obtain; ebeNorm = |F1| + |F2|, which can't be obtained in the assembled version, where we just know the sum F1+F2

I can see an alternative way to do this, and its easiest to explain in pseudo-code;

    for ( int i = 1; i <= nelem; i++ ) {
        element = domain->giveElement(i);
        element->giveLocationArray(loc, eid, s);
        this->giveElementCharacteristicVector(charVec, i, type, mode, tStep, domain);
        if ( charVec.isNotEmpty() ) {
            if ( element->giveRotationMatrix(R, eid) ) {
                charVec.rotatedWith(R, 't');
            }

            answer.assemble(charVec, loc);
            ///////////////////////////////////////////////////////// Compute the squared norm for each dofid;
            if (norms) { // Send NULL if you don't need the ebenorms.
                element->giveMasterDofIDs(masterDofIDs); // Very similar function to "giveLocationArray", but stores dofids instead of equation numbers
                for ( int j = 1; j <= charVec.giveSize(); j++) {
                    int dofid = masterDofIDs.at(j);
                    double val = charVec.at(j);
                    norms->at(dofid) += val*val;
                }
            }
            //////////////////////////////////////////////////////// Old approach, just a single norm to compute;
            //norm += charVec.computeSquaredNorm();
        }
    }

I don't think there would be much performance issues from this.

5

Re: Dof groups and convergence checks

ok, I see it now. Just one option: What about returning MasterDofIDs as a part of  giveLocationArray (an optional argument?). In this way we can save for each element one loop over its DOFs.

Re: Dof groups and convergence checks

Yes that would work as well.
I'll work on this after the rel-2.2 merge.
I'll probably bundle and cache masterDofIDs next to locationArray (they should always be updated at the same time).
Then I will enforce the dof-groups in nrsolver, and use the following equation for the error;

error = 0.;
for (int i = 1; i < numDofIds; i++) {
    double errNorm = ebeNorm.at(i) + FextGrouped.at(i);
    if (errNorm > 0.) {
        error += RGrouped.at(i)*RGrouped.at(i) / errNorm;
    } // If errNorm is zero, then R must be zero as well.
}
error = sqrt(error);

Which basically says that the residual (Fext - Fint) should be small in comparison to |Fext|+|Fint^e| (for each dof ID)