Sorry for being a bit talkative, but I've spent some more time trying to design something general, clean and useful, and now I feel a have some more insight. I shall try to give a summarized answer to each part.
bp wrote:Ok, I see your points. From my point of view, it would be nice if one could implement computeMacroStress method on material level, rather than on problem description level. The reason is to keep the problem representation clean as much as possible. If implemented by some parent class representing material models based on homogenization, then it could be shared by many models. This could be done, provided that the problem can return its characteristic components - like the NodalInternalForcesVector, etc.
Other than constructing the necessary matrices there would only be about 7 short and simple lines of code left for me.
I would have to write more code to return every matrix (and numerical method to solve) then to actually just calculate the stress and tangent directly. Most code lies in constructing the coefficient matrix C, which i could write in a support routine in the interface for the engineering model.
Only this type of homogenization would need these matrices, vectors and objects. A different method would have to do vastly different things. Perhaps iterate over solveYourselfAt(tStep);
It may happen, that some additional functionality will be required by the macro material in addition to methods providing characteristic components.
I'd just like to point out that this is no "what if". This will definitely happen, and not in exotic boundary cases (the 3-4 kinds of permeability homogenization that Carl is working with for example).
Then the question is whether to use interface concept or make a derived class, that will provide the needed functionality. I would prefer the latter option, as it will allow material to define this specific problem class (ideally as a nested class within itself). The material should be then responsible for maintaining this class. Material also should be responsible for creating this compatible problem representation at micro level.
The interface concept can be used as well. Here I see one main drawback: when several interfaces will come into a play, then there will be a lot of additional services not related to problem solution - this will make the class more difficult not only to follow, but also manage.
What do you think?
Borek
In a the derived class, for more complicated homogenization, there will probably be a need to change the way the problem is solved. So, I'm afraid it would lead to having to replace most of the code in the parent class.
The way i see it, you can't easily separate problem solving from homogenization. It's an integral part of solving, as in some cases, it would radically change the problem itself.
Stress/Strain with Dirichlet boundary conditions was probably not a good representative example, although it is probably the most common one.
Yes, it probably make the engineering model more complex for those who do not need homogenization, but isn't the same true for every optional feature?
I would still suggest this interface
/**
* @file HomogenizationInterface.h
* @since 2.0
* @date 2010-06-08
* @author Mikael Öhman
*/
#ifndef HOMOGENIZATIONINTERFACE_H
#define HOMOGENIZATIONINTERFACE_H
namespace oofem {
enum HomogenizationType {
HT_None = 0,
HT_StressStrainDirichlet = 1, /// Normal dirichlet BC for small deformation (structural problems), or velocity (flow problems).
HT_StressStrainNeumann = 2, /// Normal dirichlet BC for small deformation (structural problems), or velocity (flow problems).
HT_PermeabilityConstantVelocity = 3, /// For permeability problem, @f$v_i = K_{ij}p_{,j}@f$ using constant velocity on the boundary.
HT_PermeabilityConstantTraction = 4, /// For permeability problem, @f$v_i = K_{ij}p_{,j}@f$ using constant traction on the boundary.
HT_PermeabilityLinearTraction = 5 /// For permeability problem, @f$v_i = K_{ij}p_{,j}@f$ using linearly varying traction on the boundary.
};
/**
* The homogenization interface lets engineering models implement some types of homogenization over the domain.
* The engineering models can then be used by constitutive drivers to solve micro problems for each integration point.
*/
class HomogenizationInterface : public Interface
{
protected:
HomogenizationType ht;
public:
// Perhaps seperate this, and use "solveFor"
//virtual void solveFor(const FloatArray &input, TimeStep *tStep);
// Should these also have an input for homogenizationtype? I don't think one would ever need to have more than one at the same time.
/** Computes the characteristic vector for the active RVE problem.
* This method should set the boundary condition given the input, solve the micro problem and perform homogenization.
* @param answer The characteristic vector.
* @param input Input to set the boundary condition.
* @param tStep The timestep to solve for.
* @return True for succes, otherwise false.
*/
virtual bool computeMacroCharacteristicVector(FloatArray &answer, const FloatArray &input, TimeStep *tStep) = 0;
/** Computes the tangent for the last calculated vector.
* computeMacroCharacteristicVector should be called before calling this.
* @param answer The tangent.
* @param tStep The timestep to solve for.
* @return True for success, otherwise false.
*/
virtual bool computeMacroTangent(FloatMatrix &answer, TimeStep *tStep) = 0;
/** Prepares to use engineering model as an RVE.
* Implementation should show error if the type is not supported.
* @param ht Sets which type of problem/boundary condition should be used for the simulation.
* @return bool True if type is supported, otherwise false.
*/
virtual bool activateHomogenizationMode(HomogenizationType ht) = 0;
virtual const char *giveClassName() const { return "HomogenizationInterface"; }
};
} // end namespace oofem
#endif // HOMOGENIZATIONINTERFACE_H
There are several ways to handle common operations, but I'm not sure that are so many common things within homogenization.
I could add this add some static support methods so one doesn't need to implement it again.
FloatMatrix* constructCoefficientMatrixDirichlet(Domain *domain, FloatArray &cCoords);
{
int nNodes = domain->giveNumberOfDofManagers();
if (domain->giveNumberOfElements() == 0) {
this->C = new FloatMatrix(0,0);
return;
}
Element *e1 = domain->giveElement(1);
int dim = e1->giveSpatialDimension();
int dofType[3] = {0,0,0};
domainType d = domain->giveDomainType();
if (d == _2dIncompressibleFlow || d == _3dIncompressibleFlow) {
dofType[0] = V_u; dofType[1] = V_v; dofType[2] = V_w;
}
else if (d == _3dMode || d == _2dPlaneStressMode || d == _PlaneStrainMode || d == _2dTrussMode) {
dofType[0] = D_u; dofType[1] = D_v; dofType[2] = D_w;
}
else
OOFEM_ERROR("Unsupported domain type to construct C matrix");
int npeq = this->giveNumberOfPrescribedEquations(EID_MomentumBalance);
C = new FloatMatrix(npeq, dim*(dim+1)/2);
C->zero();
PrescribedTensor *pt = dynamic_cast<PrescribedTensor*>(domain->giveBc(1));
if (!pt) {
OOFEM_WARNING("Incorrect boundary condition, should be prescribed tensor");
return false;
}
double xbar = cCoords.at(1), ybar = cCoords.at(2), zbar = cCoords.at(3);
for (int i = 1; i <= nNodes; i++) {
Node *n = domain->giveNode(i);
FloatArray *coords = n->giveCoordinates();
Dof *d1 = n->giveDofWithID(dofType[0]);
Dof *d2 = n->giveDofWithID(dofType[1]);
int k1 = d1->__givePrescribedEquationNumber();
int k2 = d2->__givePrescribedEquationNumber();
if (dim == 2) {
if (k1) {
C->at(k1,1) = coords->at(1)-xbar;
C->at(k1,3) = coords->at(2)-ybar;
}
if (k2) {
C->at(k2,2) = coords->at(2)-ybar;
C->at(k2,3) = coords->at(1)-xbar;
}
}
else { // dim == 3
OOFEM_ERROR("COMPLETELY UNTESTED!");
Dof *d3 = n->giveDofWithID(dofType[2]);
int k3 = d3->__givePrescribedEquationNumber();
if (k1) {
C->at(k1,1) = coords->at(1)-xbar;
C->at(k1,4) = coords->at(2)-ybar;
C->at(k1,5) = coords->at(3)-zbar;
}
if (k2) {
C->at(k2,2) = coords->at(2)-ybar;
C->at(k2,4) = coords->at(1)-xbar;
C->at(k2,6) = coords->at(3)-zbar;
}
if (k3) {
C->at(k3,3) = coords->at(3)-zbar;
C->at(k3,5) = coords->at(1)-xbar;
C->at(k3,6) = coords->at(2)-ybar;
}
}
}
return C;
}
Of course, I have made sure that everything related to homogenization is neatly isolated into functions as much as possible.
I can't see any downsides of doing it this way.
Edit: Had to edit and add text again, the forum tends to cut my replies short.